目錄
0 前言
1 準備工作
1.1 安裝pnpm
1.2 創建vue項目
1.3 Eslint & Prettier的配置
1.4 husky 提交代碼檢查
1.5 目錄調整
1.6 VueRouter4
1.6.1 基礎配置
1.6.2 路由跳轉
1.7 引入 Element Plus 組件庫
1.8 Pinia
1.8.1 優化?
1.9 封裝請求工具
1.9.1 安裝 axios 與配置框架
1.9.2 示例代碼
2 開發
0 前言
黑馬程序員視頻地址:Vue3大事件項目-項目介紹和pnpm創建項目
接口文檔:登錄 - 黑馬程序員-大事件?
1 準備工作
1.1 安裝pnpm
官網:pnpm - 速度快、節省磁盤空間的軟件包管理器 | pnpm中文文檔 | pnpm中文網
安裝pnpm命令:
npm i pnpm -g
pnpm創建vue項目命令:
pnpm create vue
命令對比:?
npm | yarn | pnpm |
---|---|---|
npm install | yarn | pnpm install |
npm install axios | yarn add axios | pnpm add axios |
npm install axios -D | yarn add axios -D | pnpm add axios -D |
npm uninstall axios | yarn remove axios | pnpm remove axios |
npm run dev | yarn dev | pnpm dev |
1.2 創建vue項目
使用pnpm創建vue項目時,選擇以下配置
請選擇要包含的功能: (↑/↓ 切換,空格選擇,a 全選,回車確認)
| [ ] TypeScript
| [ ] JSX 支持
| [+] Router(單頁面應用開發)
| [+] Pinia(狀態管理)
| [ ] Vitest(單元測試)
| [ ] 端到端測試
| [+] ESLint(錯誤預防)
| [+] Prettier(代碼格式化)
標記:警告提示(待解決)
?創建完項目需要進入相應文件夾中,安裝所有依賴
pnpm install
1.3 Eslint & Prettier的配置
見?【VUE3】Eslint 與 Prettier 的配置-CSDN博客
推薦使用里面的方案二,即將 prettier 的規則讓 eslint 來執行
因為 1.4 中的檢查代碼需要 eslint 來檢查
1.4 husky 提交代碼檢查
husky 是一個 git hooks 工具 ?( git的鉤子工具,可以在特定時機執行特定的命令 )
第一步:初始化倉庫
git init
第二步:初始化 husky 工具配置
pnpm dlx husky-init; pnpm install
第三步:修改 .husky/pre-commit 文件
pnpm lint
但是這樣會有一個問題!?
我們可以打開 package.json 文件,看到里面的 lint 命令對應為:
"lint": "eslint . --fix"
即默認進行的是全量檢查,耗時問題,歷史問題,因此需要再導入一個包 lint-staged :
第一步:安裝
pnpm i lint-staged -D
第二步:配置 package.json 文件
{// ... 省略 ..."lint-staged": {"*.{js,ts,vue}": ["eslint --fix"]}
}{"scripts": {// ... 省略 ..."lint-staged": "lint-staged"}
}
第三步:修改 .husky/pre-commit 文件
pnpm lint-staged
這樣就會只檢查修改過的文件,哪怕以前提交的文件有問題,也不會檢查報錯
可以通過控制 1.3 中的那篇文章的第七節中的?'no-undef': 'off'來模擬提交以前有問題的文件
1.5 目錄調整
刪除默認文件后,增加 api 與 utils 文件夾
如果使用 sass,則需安裝對應依賴
pnpm add sass -D
1.6 VueRouter4
更多內容見官網:Vue Router | Vue.js 的官方路由?
1.6.1 基礎配置
import { createRouter, createWebHistory } from 'vue-router'// createRouter 創建路由實例,===> new VueRouter()
// 1. history模式: createWebHistory() http://xxx/user
// 2. hash模式: createWebHashHistory() http://xxx/#/user// vite 的配置 import.meta.env.BASE_URL 是路由的基準地址,默認是 ’/‘
// https://vitejs.dev/guide/build.html#public-base-path// 如果將來你部署的域名路徑是:http://xxx/my-path/user
// vite.config.ts 添加配置 base: my-path,路由這就會加上 my-path 前綴了const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: []
})export default router
1.6.2 路由跳轉
由于 setup 下,this 指向 undefined ,因此需要引入包創建 router 與 router 對象
<script setup>
import { useRoute, useRouter } from 'vue-router'
const router = useRouter()
const route = useRoute()
const gotoCart = () => {console.log(route)router.push('/individual')
}
</script><template><div>我是App</div><button @click="gotoCart()">跳轉購物車頁面</button>
</template>
1.7 引入 Element Plus 組件庫
官方手冊:一個 Vue 3 UI 框架 | Element Plus
安裝組件庫
pnpm install element-plus
按需引入:
第一步:安裝插件
pnpm add -D unplugin-vue-components unplugin-auto-import
?第二步:把下列代碼插入到你的?Vite
?的配置文件中
import { defineConfig } from 'vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'export default defineConfig({// ...plugins: [// ...AutoImport({resolvers: [ElementPlusResolver()],}),Components({resolvers: [ElementPlusResolver()],}),],
})
全部引入此處不贅述?
注意:
1.在引入之后,無需任何配置,即可使用組件庫內的組件
2.并且components下的vue組件也可以直接使用,無需導入
1.8 Pinia
見文檔:【VUE3】Pinia-CSDN博客
注意:由于創建項目時勾選了Pinia,所以此處不需要再手動安裝配置Pinia,直接可以使用
但是持久化還需手動配置,此處不再贅述
1.8.1 優化?
將 main.js 中關于 pinia 的代碼抽離到 store/index.js 中,并且將 store/modules 中的所有倉庫文件統一從 index.js 中導出,方便管理且簡化代碼?
// main.js
// ...
import pinia from './stores'// ...
app.use(pinia)// ...
// store/index.jsimport { createPinia } from 'pinia'
import persist from 'pinia-plugin-persistedstate'const pinia = createPinia()
pinia.use(persist)export default piniaexport * from '@/stores/modules/user'
export * from '@/stores/modules/count'// 上面的代碼等同于
// import { useUserStore, ... } from '@/stores/modules/user'
// export { useUserStore, ... }
// 組件.vueimport { useUserStore, useCountStore } from '@/stores'const userStore = useUserStore()
const userCount = useCountStore()
1.9 封裝請求工具
手冊:axios中文文檔|axios中文網 | axios?
1.9.1 安裝 axios 與配置框架
1.安裝 axios
pnpm add axios
2.框架代碼
// utils/request.jsimport axios from 'axios'const baseURL = 'http://big-event-vue-api-t.itheima.net'const instance = axios.create({// TODO 1. 基礎地址,超時時間
})instance.interceptors.request.use((config) => {// TODO 2. 攜帶tokenreturn config},(err) => Promise.reject(err)
)instance.interceptors.response.use((res) => {// TODO 3. 處理業務失敗// TODO 4. 摘取核心響應數據return res},(err) => {// TODO 5. 處理401錯誤return Promise.reject(err)}
)export default instance
1.9.2 示例代碼
// utils/request.jsimport axios from 'axios'
import { useUserStore } from '@/stores'
import { ElMessage } from 'element-plus'
import router from '@/router'
const baseURL = 'http://big-event-vue-api-t.itheima.net'const instance = axios.create({// TODO 1. 基礎地址,超時時間baseURL,timeout: 100000
})instance.interceptors.request.use((config) => {// TODO 2. 攜帶tokenconst userStore = useUserStore()if (userStore.token) {config.headers.Authorization = userStore.token}return config},(err) => Promise.reject(err)
)instance.interceptors.response.use((res) => {// TODO 3. 處理業務失敗if (res.data.code === 0) {return res}ElMessage({ message: res.data.message || '服務異常', type: 'error' })// TODO 4. 摘取核心響應數據return Promise.reject(res.data)},(err) => {ElMessage({ message: err.response.data.message || '服務異常', type: 'error' })// TODO 5. 處理401錯誤if (err.response?.status === 401) {router.push('/login')}return Promise.reject(err)}
)export default instance
2 開發
2.1 路由配置
示例:采用?路由懶加載
// router/index.jsimport { createRouter, createWebHistory } from 'vue-router'const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{ path: '/login', component: () => import('@/views/login/LoginPage.vue') },{path: '/',component: () => import('@/views/layout/LayoutContainer.vue'),redirect: '/article/manage',children: [{ path: '/article/manage', component: () => import('@/views/article/ArticleManage.vue') },{ path: '/article/channel', component: () => import('@/views/article/ArticleChannel.vue') },{ path: '/user/profile', component: () => import('@/views/user/UserProfile.vue') },{ path: '/user/avatar', component: () => import('@/views/user/UserAvatar.vue') },{ path: 'user/password', component: () => import('@/views/user/UserPassword.vue') }]}]
})export default router
記得準備路由出口,如:
// App.vue<template><router-view></router-view>
</template>
2.2 登錄注冊
2.2.1 靜態頁面
1.安裝 element-plus 圖標庫
pnpm i @element-plus/icons-vue
2.靜態結構準備
注意:登錄頁面與注冊頁面使用 v-if 與 v-else 控制切換
// views/login/LoginPage.vue<script setup>
import { User, Lock } from '@element-plus/icons-vue'
import { ref } from 'vue'
const isRegister = ref(true)
</script><template><el-row class="login-page"><el-col :span="12" class="bg"></el-col><el-col :span="6" :offset="3" class="form"><el-form ref="form" size="large" autocomplete="off" v-if="isRegister"><el-form-item><h1>注冊</h1></el-form-item><el-form-item><el-input :prefix-icon="User" placeholder="請輸入用戶名"></el-input></el-form-item><el-form-item><el-input :prefix-icon="Lock" type="password" placeholder="請輸入密碼"></el-input></el-form-item><el-form-item><el-input :prefix-icon="Lock" type="password" placeholder="請輸入再次密碼"></el-input></el-form-item><el-form-item><el-button class="button" type="primary" auto-insert-space> 注冊 </el-button></el-form-item><el-form-item class="flex"><el-link type="info" :underline="false" @click="isRegister = false"> ← 返回 </el-link></el-form-item></el-form><el-form ref="form" size="large" autocomplete="off" v-else><el-form-item><h1>登錄</h1></el-form-item><el-form-item><el-input :prefix-icon="User" placeholder="請輸入用戶名"></el-input></el-form-item><el-form-item><el-inputname="password":prefix-icon="Lock"type="password"placeholder="請輸入密碼"></el-input></el-form-item><el-form-item class="flex"><div class="flex"><el-checkbox>記住我</el-checkbox><el-link type="primary" :underline="false">忘記密碼?</el-link></div></el-form-item><el-form-item><el-button class="button" type="primary" auto-insert-space>登錄</el-button></el-form-item><el-form-item class="flex"><el-link type="info" :underline="false" @click="isRegister = true"> 注冊 → </el-link></el-form-item></el-form></el-col></el-row>
</template><style lang="scss" scoped>
.login-page {height: 100vh;background-color: #fff;.bg {background:url('@/assets/logo2.png') no-repeat 60% center / 240px auto,url('@/assets/login_bg.jpg') no-repeat center / cover;border-radius: 0 20px 20px 0;}.form {display: flex;flex-direction: column;justify-content: center;user-select: none;.title {margin: 0 auto;}.button {width: 100%;}.flex {width: 100%;display: flex;justify-content: space-between;}}
}
</style>
2.2.2 規則校驗
官方文檔:Form 表單 | Element Plus
四大校驗方式:
????????1.非空校驗:required
????????2.長度校驗:min、max
? ? ? ? 3.正則校驗:pattern
? ? ? ? 4.自定義校驗?:validator
第一步:聲明表單數據對象與規則對象,其中表單數據對象必須是響應式的?
const formData = ref({username: '',password: '',repassword: ''
})
const formRules = {username: [{ required: true, message: '用戶名不能為空!', trigger: 'blur' },// blur是失去焦點事件{ min: 5, max: 10, message: '用戶名必須為5-10位字符', trigger: 'blur' }],password: [{ required: true, message: '密碼不能為空!', trigger: 'blur' },{ pattern: /^\S{8,15}$/, message: '密碼必須為8-15位非空字符', trigger: 'change' }// change為改變時校驗,發現當檢驗提示錯誤后,若觸發失焦事件,會導致提示消失,因此不推薦]
}
第二步:給整個表單的大標簽綁定數據對象與規則對象
<el-form
...
:model="formData"
:rules="formRules"
>
<!-- ... -->
</el-form>
第三步:給輸入框綁定數據,并且給表單元素標簽綁定要使用的規則
<el-form-item prop="username"> ?<el-input:prefix-icon="User"placeholder="請輸入用戶名"v-model="formData.username" ?></el-input>
</el-form-item>
自定義校驗方式:
使用方式相同,只是配置規則時,validator 指向一個函數
參數:
????????rule:當前校驗規則相關的信息
? ? ? ? value:所校驗的表單元素目前的表單值
? ? ? ? callback:無論成功還是失敗,都需要 callback 回調
const formRules = {// ...repassword: [{validator: (rule, value, callback) => {if (value !== formData.value.password) {callback(new Error('兩次密碼不一致,請重新輸入!'))} else {callback()}},trigger: 'blur'}]
}
2.2.3 表單預校驗
由于vue3的特性,即導入的組件內的方法默認不會暴露,因此需要獲取組件對象,然后再獲取,如:
第一步:獲取組件對象
詳細見?【VUE3】組合式API-CSDN博客?中的 9.2
const form = ref()
<el-form
ref="form" ?
size="large"
autocomplete="off"
v-if="isRegister"
:model="formData"
:rules="formRules"
>
第二步:調用 validate 方法
validate 方法即對整個表單的內容進行驗證,接收一個回調函數,或返回 Promise
const register = async () => {await form.value.validate() ?await userRegisterService(formData.value) // 這個是提交數據apiElMessage.success('注冊成功!')isRegister.value = false // 切換登錄
}
注意:因為之前我們設置了插件來幫我們自動導入Element組件,所以上述代碼中的ElMessage方法我們沒有導入,但是eslint會報錯,可以在 eslint.config.js 中來配置,讓其不報錯,位置及代碼如下:
// ...export default defineConfig([// ...{rules: {// ...'vue/no-setup-props-destructure': ['off'], // 放在這個下面globals: {ElMessage: 'readonly',ElMessageBox: 'readonly',ElLoading: 'readonly'}}},
])
2.2.4 封裝注冊api
// api/user.jsimport request from '@/utils/request'export const userRegisterService = ({ username, password, repassword }) =>request.post('/api/reg', { username, password, repassword })
調用見 2.2.3?
持續更新