项目起步

创建项目

目的:使用vue-cli创建一个vue3.0项目。

第一步:打开命令行窗口。
1603852293974.png

  • 注意,所在目录将会是你创建项目的目录。

第二步:执行创建项目命令行

1603852444971.png

第三步:选择自定义创建
1603852670808.png
第四步:选中vue-router,vuex,css Pre-processors选项
1603852792935.png
第五步:选择vue3.0版本
1603852839087.png
第六步:选择hash模式的路由
1603852990684.png
第七步:选择less作为预处理器
1603853031917.png

第八步:选择 standard 标准代码风格
1603853095879.png
第九步:保存代码校验代码风格,代码提交时候校验代码风格
1603853195466.png
第十步:依赖插件或者工具的配置文件分文件保存
1603853269591.png
第十一步:是否记录以上操作,选择否
1603853342559.png
第十二步:等待安装…
1603853394460.png
最后:安装完毕
1603853818009.png

目录调整

目的:对项目功能模块进行拆分。

大致步骤:

  • 删除无用代码和文件
  • 完善项目的基础结构
  • 读懂默认生成的代码

落的代码:

1605596588487.png

注意:以上结构目录及供参考

需要注意的一些文件:

  • router/index.js
  1. import { createRouter, createWebHashHistory } from 'vue-router'
  2. const routes = [
  3. ]
  4. // 创建路由实例
  5. const router = createRouter({
  6. // 使用hash方式实现路由
  7. history: createWebHashHistory(),
  8. // 配置路由规则,写法和之前一样
  9. routes
  10. })
  11. export default router

vue3.0中createRouter来创建路由实例,createWebHashHistory代表使用hash模式的路由。

  • store/index.js
  1. import { createStore } from 'vuex'
  2. // 创建vuex仓库并导出
  3. export default createStore({
  4. state: {
  5. // 数据
  6. },
  7. mutations: {
  8. // 改数据函数
  9. },
  10. actions: {
  11. // 请求数据函数
  12. },
  13. modules: {
  14. // 分模块
  15. },
  16. getters: {
  17. // vuex的计算属性
  18. }
  19. })

vue3.0中createStore来创建vuex实例。

  • main.js
  1. import { createApp } from 'vue'
  2. import App from './App.vue'
  3. import router from './router'
  4. import store from './store'
  5. // 创建一个vue应用实例
  6. createApp(App).use(store).use(router).mount('#app')

vue3.0中createApp来创建应用app。

额外增加两个配置文件:

  • jsconfig.json
  1. {
  2. "compilerOptions": {
  3. "baseUrl": ".",
  4. "paths": {
  5. "@/*": ["./src/*"],
  6. }
  7. },
  8. "exclude": ["node_modules", "dist"]
  9. }

当我们使用路径别名@的时候可以提示路径。

  • .eslintignore
  1. /dist
  2. /src/vender

eslint在做风格检查的时候忽略 dist 和 vender 不去检查。

基于git管理项目

  • git init
  • git add .
  • git commit -m ‘初始化仓库’
  • 创建远程仓库
  • 添加远程仓库的别名 git remote add origin https://gitee.com/wzj1031/erabbit-128.git
  • 推送代码 git push -u origin master

    vuex-基础

目的:知道每个配置作用,根模块vue3.0的用法,带命名空间模块再vue3.0的用法

  1. 根模块的用法

定义

  1. import { createStore } from 'vuex'
  2. // vue2.0 创建仓库 new Vuex.Store({})
  3. // vue3.0 创建仓库 createStore({})
  4. export default createStore({
  5. // 数据
  6. state: {
  7. info: '王浩'
  8. },
  9. // vuex的计算属性
  10. getters: {
  11. fullInfo (state) {
  12. return state.info + '😁😁😁'
  13. }
  14. },
  15. // 改数据函数
  16. mutations: {
  17. updateInfo (state, payload) {
  18. state.info = payload
  19. }
  20. },
  21. // 请求数据函数
  22. actions: {
  23. updateInfo (context, payload) {
  24. setTimeout(() => {
  25. context.commit('updateInfo', payload)
  26. }, 1000)
  27. }
  28. },
  29. // 分模块
  30. modules: {}
  31. })

使用

  1. <template>
  2. <!-- vue2.0需要根元素,vue3.0可以是代码片段 Fragment -->
  3. <div>
  4. <!-- 1. 使用根模块state的数据 -->
  5. <div>{{ $store.state.info }}</div>
  6. <!-- 2. 使用根模块getters的数据 -->
  7. <div>{{ $store.getters.fullInfo }}</div>
  8. <button @click="handleClick">点击</button>
  9. </div>
  10. </template>
  11. <script>
  12. import { useStore } from 'vuex'
  13. export default {
  14. name: 'App',
  15. setup () {
  16. // 获取store对象不可以写到事件函数中
  17. const store = useStore()
  18. const handleClick = () => {
  19. // 获取store对象
  20. // 触发mutation
  21. // store.commit('updateInfo', '你好啊')
  22. // 触发action
  23. store.dispatch('updateInfo', 'hi')
  24. }
  25. return { handleClick }
  26. }
  27. }
  28. </script>
  1. modules (分模块)
  • 存在两种情况
    • 默认的模块,state 区分模块,其他 getters mutations actions 都在全局。
    • 带命名空间 namespaced: true 的模块,所有功能区分模块,更高封装度和复用。
  1. import { createStore } from 'vuex'
  2. const moduleA = {
  3. // 子模块state建议写成函数
  4. state: () => {
  5. return {
  6. username: '模块A'
  7. }
  8. },
  9. getters: {
  10. changeName (state) {
  11. return state.username + 'AAAAAA'
  12. }
  13. }
  14. }
  15. const moduleB = {
  16. // 带命名空间的模块
  17. namespaced: true,
  18. // 子模块state建议写成函数
  19. state: () => {
  20. return {
  21. username: '模块B'
  22. }
  23. },
  24. getters: {
  25. changeName (state) {
  26. return state.username + 'BBBBBB'
  27. }
  28. },
  29. mutations: {
  30. // 修改名字的mutation
  31. update (state) {
  32. state.username = 'BBBB' + state.username
  33. }
  34. },
  35. actions: {
  36. update ({ commit }) {
  37. // 假设请求
  38. setTimeout(() => {
  39. commit('update')
  40. }, 2000)
  41. }
  42. }
  43. }
  44. // 创建vuex仓库并导出
  45. export default createStore({
  46. state: {
  47. // 数据
  48. person: [
  49. { id: 1, name: 'tom', gender: '男' },
  50. { id: 2, name: 'lucy', gender: '女' },
  51. { id: 3, name: 'jack', gender: '男' }
  52. ]
  53. },
  54. mutations: {
  55. // 改数据函数
  56. },
  57. actions: {
  58. // 请求数据函数
  59. },
  60. modules: {
  61. // 分模块
  62. a: moduleA,
  63. b: moduleB
  64. },
  65. getters: {
  66. // vuex的计算属性
  67. boys: (state) => {
  68. return state.person.filter(p => p.gender === '男')
  69. }
  70. }
  71. })

使用:

  1. <template>
  2. <div>APP组件</div>
  3. <ul>
  4. <li v-for="item in $store.getters.boys" :key="item.id">{{item.name}}</li>
  5. </ul>
  6. <!-- 使用模块A的username -->
  7. <p>A的username --- {{$store.state.a.username}}</p>
  8. <p>A的changeName --- {{$store.getters.changeName}}</p>
  9. <hr>
  10. <p>B的username --- {{$store.state.b.username}}</p>
  11. <p>B的changeName --- {{$store.getters['b/changeName']}}</p>
  12. <button @click="$store.commit('b/update')">修改username</button>
  13. <button @click="$store.dispatch('b/update')">异步修改username</button>
  14. </template>

vuex-持久化

目的:让在vuex中管理的状态数据同时存储在本地。可免去自己存储的环节。

  • 在开发的过程中,像用户信息(名字,头像,token)需要vuex中存储且需要本地存储。
  • 再例如,购物车如果需要未登录状态下也支持,如果管理在vuex中页需要存储在本地。
  • 我们需要category模块存储分类信息,但是分类信息不需要持久化。

1)首先:我们需要安装一个vuex的插件vuex-persistedstate来支持vuex的状态持久化。

  1. npm i vuex-persistedstate

2)然后:在src/store 文件夹下新建 modules 文件,在 modules 下新建 user.jscart.js

src/store/modules/user.js

  1. // 用户模块
  2. export default {
  3. namespaced: true,
  4. state () {
  5. return {
  6. // 用户信息
  7. profile: {
  8. id: '',
  9. avatar: '',
  10. nickname: '',
  11. account: '',
  12. mobile: '',
  13. token: ''
  14. }
  15. }
  16. },
  17. mutations: {
  18. // 修改用户信息,payload就是用户信息对象
  19. setUser (state, payload) {
  20. state.profile = payload
  21. }
  22. }
  23. }

src/store/modules/cart.js

  1. // 购物车状态
  2. export default {
  3. namespaced: true,
  4. state: () => {
  5. return {
  6. list: []
  7. }
  8. }
  9. }

src/store/modules/category.js

  1. // 分类模块
  2. export default {
  3. namespaced: true,
  4. state () {
  5. return {
  6. // 分类信息集合
  7. list: []
  8. }
  9. }
  10. }

3)继续:在 src/store/index.js 中导入 user cart 模块。

  1. import { createStore } from 'vuex'
  2. import user from './modules/user'
  3. import cart from './modules/cart'
  4. import cart from './modules/category'
  5. export default createStore({
  6. modules: {
  7. user,
  8. cart,
  9. category
  10. }
  11. })

4)最后:使用vuex-persistedstate插件来进行持久化

  1. import { createStore } from 'vuex'
  2. +import createPersistedstate from 'vuex-persistedstate'
  3. import user from './modules/user'
  4. import cart from './modules/cart'
  5. import cart from './modules/category'
  6. export default createStore({
  7. modules: {
  8. user,
  9. cart,
  10. category
  11. },
  12. + plugins: [
  13. + createPersistedstate({
  14. + key: 'erabbit-client-pc-store',
  15. + paths: ['user', 'cart']
  16. + })
  17. + ]
  18. })

注意:

===> 默认是存储在localStorage中

===> key是存储数据的键名

===> paths是存储state中的那些数据,如果是模块下具体的数据需要加上模块名称,如user.token

===> 修改state后触发才可以看到本地存储数据的的变化。

测试: user模块定义一个mutation在main.js去调用下,观察浏览器application的localStorage下数据。

src/App.js

  1. <template>
  2. <div class="container">
  3. <!-- 修改数据,测试是否持久化 -->
  4. App {{$store.state.user.profile.account}}
  5. <button @click="$store.commit('user/setUser',{account:'zhousg'})">设置用户信息</button>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. name: 'App'
  11. }
  12. </script>

请求工具

目的:基于axios封装一个请求工具,调用接口时使用。

  • 安装 axios
  1. npm i axios
  • 新建 src/utils/request.js 模块,代码如下
  1. // 封装通用的接口调用模块----------------------
  2. import axios from 'axios'
  3. import store from '@/store'
  4. import router from '@/router'
  5. // ------------------请求的基准路径-----------------------------
  6. export const baseURL = ''
  7. // 创建独立的axios的实例
  8. const instance = axios.create({
  9. baseURL: baseURL,
  10. timeout: 5000
  11. })
  12. // ------------请求拦截器:统一添加请求头--------------------
  13. instance.interceptors.request.use((config) => {
  14. // 判断Vuex中是否有token,如果有就添加到请求头
  15. const token = store.state.user.profile.token
  16. // 2. 判断是否有token
  17. if (token) {
  18. // 3. 设置token
  19. config.headers.Authorization = 'Bearer ' + token
  20. }
  21. return config
  22. }, (err) => {
  23. return Promise.reject(err)
  24. })
  25. // ------------响应拦截器:处理后端返回的数据,把data属性去掉----------------
  26. instance.interceptors.response.use((response) => {
  27. return response.data
  28. }, (err) => {
  29. // 处理token的过期操作
  30. if (err.response && err.response.status === 401) {
  31. // token过期了,清空过期的用户信息,跳转到登录页面
  32. store.commit('user/updateUserInfo', {})
  33. router.push('/login')
  34. }
  35. return Promise.reject(err)
  36. })
  37. // ----------------封装一个通用的请求方法----------------------------
  38. export default (options) => {
  39. return instance({
  40. // 如果没有传递请求方式,默认是使用get请求
  41. method: options.method || 'GET',
  42. // 请求地址
  43. url: options.url,
  44. // 对象的键可以是动态的变量
  45. // get请求,添加params属性,其他请求添加data属性
  46. [options.method.toUpperCase() === 'GET' ? 'params' : 'data']: options.data
  47. // data用于传递请求体数据(POST/PUT/DELETE)
  48. // data: options.data,
  49. // params用于传递get请求数据(查询字符串)
  50. // params: options.data
  51. })
  52. }

路由设计

目的:知道项目路由层级的设计

1605599713484.png

路径 组件(功能) 嵌套级别
/ 首页布局容器 1级
/ 首页 2级
/category/:id 一级分类 2级
/category/sub/:id 二级分类 2级
/product/:id 商品详情 2级
/login 登录 1级
/login/callback 第三方登录回调 1级
/cart 购物车 2级
/member/checkout 填写订单 2级
/member/pay 进行支付 2级
/member/pay/result 支付结果 2级
/member 个人中心布局容器 2级
/member 个人中心 3级
/member/order 订单管理 3级
/member/order/:id 订单详情 3级