项目起步
创建项目
目的:使用vue-cli创建一个vue3.0项目。
第一步:打开命令行窗口。
- 注意,所在目录将会是你创建项目的目录。
第二步:执行创建项目命令行
第三步:选择自定义创建
第四步:选中vue-router,vuex,css Pre-processors选项
第五步:选择vue3.0版本
第六步:选择hash模式的路由
第七步:选择less作为预处理器
第八步:选择 standard 标准代码风格
第九步:保存代码校验代码风格,代码提交时候校验代码风格
第十步:依赖插件或者工具的配置文件分文件保存
第十一步:是否记录以上操作,选择否
第十二步:等待安装…
最后:安装完毕
目录调整
目的:对项目功能模块进行拆分。
大致步骤:
- 删除无用代码和文件
- 完善项目的基础结构
- 读懂默认生成的代码
落的代码:
注意:以上结构目录及供参考
需要注意的一些文件:
router/index.js
import { createRouter, createWebHashHistory } from 'vue-router'
const routes = [
]
// 创建路由实例
const router = createRouter({
// 使用hash方式实现路由
history: createWebHashHistory(),
// 配置路由规则,写法和之前一样
routes
})
export default router
vue3.0中createRouter来创建路由实例,createWebHashHistory代表使用hash模式的路由。
store/index.js
import { createStore } from 'vuex'
// 创建vuex仓库并导出
export default createStore({
state: {
// 数据
},
mutations: {
// 改数据函数
},
actions: {
// 请求数据函数
},
modules: {
// 分模块
},
getters: {
// vuex的计算属性
}
})
vue3.0中createStore来创建vuex实例。
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
// 创建一个vue应用实例
createApp(App).use(store).use(router).mount('#app')
vue3.0中createApp来创建应用app。
额外增加两个配置文件:
jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
}
},
"exclude": ["node_modules", "dist"]
}
当我们使用路径别名@的时候可以提示路径。
.eslintignore
/dist
/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的用法
- 根模块的用法
定义
import { createStore } from 'vuex'
// vue2.0 创建仓库 new Vuex.Store({})
// vue3.0 创建仓库 createStore({})
export default createStore({
// 数据
state: {
info: '王浩'
},
// vuex的计算属性
getters: {
fullInfo (state) {
return state.info + '😁😁😁'
}
},
// 改数据函数
mutations: {
updateInfo (state, payload) {
state.info = payload
}
},
// 请求数据函数
actions: {
updateInfo (context, payload) {
setTimeout(() => {
context.commit('updateInfo', payload)
}, 1000)
}
},
// 分模块
modules: {}
})
使用
<template>
<!-- vue2.0需要根元素,vue3.0可以是代码片段 Fragment -->
<div>
<!-- 1. 使用根模块state的数据 -->
<div>{{ $store.state.info }}</div>
<!-- 2. 使用根模块getters的数据 -->
<div>{{ $store.getters.fullInfo }}</div>
<button @click="handleClick">点击</button>
</div>
</template>
<script>
import { useStore } from 'vuex'
export default {
name: 'App',
setup () {
// 获取store对象不可以写到事件函数中
const store = useStore()
const handleClick = () => {
// 获取store对象
// 触发mutation
// store.commit('updateInfo', '你好啊')
// 触发action
store.dispatch('updateInfo', 'hi')
}
return { handleClick }
}
}
</script>
- modules (分模块)
- 存在两种情况
- 默认的模块,
state
区分模块,其他getters
mutations
actions
都在全局。 - 带命名空间
namespaced: true
的模块,所有功能区分模块,更高封装度和复用。
- 默认的模块,
import { createStore } from 'vuex'
const moduleA = {
// 子模块state建议写成函数
state: () => {
return {
username: '模块A'
}
},
getters: {
changeName (state) {
return state.username + 'AAAAAA'
}
}
}
const moduleB = {
// 带命名空间的模块
namespaced: true,
// 子模块state建议写成函数
state: () => {
return {
username: '模块B'
}
},
getters: {
changeName (state) {
return state.username + 'BBBBBB'
}
},
mutations: {
// 修改名字的mutation
update (state) {
state.username = 'BBBB' + state.username
}
},
actions: {
update ({ commit }) {
// 假设请求
setTimeout(() => {
commit('update')
}, 2000)
}
}
}
// 创建vuex仓库并导出
export default createStore({
state: {
// 数据
person: [
{ id: 1, name: 'tom', gender: '男' },
{ id: 2, name: 'lucy', gender: '女' },
{ id: 3, name: 'jack', gender: '男' }
]
},
mutations: {
// 改数据函数
},
actions: {
// 请求数据函数
},
modules: {
// 分模块
a: moduleA,
b: moduleB
},
getters: {
// vuex的计算属性
boys: (state) => {
return state.person.filter(p => p.gender === '男')
}
}
})
使用:
<template>
<div>APP组件</div>
<ul>
<li v-for="item in $store.getters.boys" :key="item.id">{{item.name}}</li>
</ul>
<!-- 使用模块A的username -->
<p>A的username --- {{$store.state.a.username}}</p>
<p>A的changeName --- {{$store.getters.changeName}}</p>
<hr>
<p>B的username --- {{$store.state.b.username}}</p>
<p>B的changeName --- {{$store.getters['b/changeName']}}</p>
<button @click="$store.commit('b/update')">修改username</button>
<button @click="$store.dispatch('b/update')">异步修改username</button>
</template>
vuex-持久化
目的:让在vuex中管理的状态数据同时存储在本地。可免去自己存储的环节。
- 在开发的过程中,像用户信息(名字,头像,token)需要vuex中存储且需要本地存储。
- 再例如,购物车如果需要未登录状态下也支持,如果管理在vuex中页需要存储在本地。
- 我们需要category模块存储分类信息,但是分类信息不需要持久化。
1)首先:我们需要安装一个vuex的插件vuex-persistedstate
来支持vuex的状态持久化。
npm i vuex-persistedstate
2)然后:在src/store
文件夹下新建 modules
文件,在 modules
下新建 user.js
和 cart.js
src/store/modules/user.js
// 用户模块
export default {
namespaced: true,
state () {
return {
// 用户信息
profile: {
id: '',
avatar: '',
nickname: '',
account: '',
mobile: '',
token: ''
}
}
},
mutations: {
// 修改用户信息,payload就是用户信息对象
setUser (state, payload) {
state.profile = payload
}
}
}
src/store/modules/cart.js
// 购物车状态
export default {
namespaced: true,
state: () => {
return {
list: []
}
}
}
src/store/modules/category.js
// 分类模块
export default {
namespaced: true,
state () {
return {
// 分类信息集合
list: []
}
}
}
3)继续:在 src/store/index.js
中导入 user cart 模块。
import { createStore } from 'vuex'
import user from './modules/user'
import cart from './modules/cart'
import cart from './modules/category'
export default createStore({
modules: {
user,
cart,
category
}
})
4)最后:使用vuex-persistedstate插件来进行持久化
import { createStore } from 'vuex'
+import createPersistedstate from 'vuex-persistedstate'
import user from './modules/user'
import cart from './modules/cart'
import cart from './modules/category'
export default createStore({
modules: {
user,
cart,
category
},
+ plugins: [
+ createPersistedstate({
+ key: 'erabbit-client-pc-store',
+ paths: ['user', 'cart']
+ })
+ ]
})
注意:
===> 默认是存储在localStorage中
===> key是存储数据的键名
===> paths是存储state中的那些数据,如果是模块下具体的数据需要加上模块名称,如user.token
===> 修改state后触发才可以看到本地存储数据的的变化。
测试: user模块定义一个mutation在main.js去调用下,观察浏览器application的localStorage下数据。
src/App.js
<template>
<div class="container">
<!-- 修改数据,测试是否持久化 -->
App {{$store.state.user.profile.account}}
<button @click="$store.commit('user/setUser',{account:'zhousg'})">设置用户信息</button>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
请求工具
目的:基于axios封装一个请求工具,调用接口时使用。
- 安装 axios
npm i axios
- 新建
src/utils/request.js
模块,代码如下
// 封装通用的接口调用模块----------------------
import axios from 'axios'
import store from '@/store'
import router from '@/router'
// ------------------请求的基准路径-----------------------------
export const baseURL = ''
// 创建独立的axios的实例
const instance = axios.create({
baseURL: baseURL,
timeout: 5000
})
// ------------请求拦截器:统一添加请求头--------------------
instance.interceptors.request.use((config) => {
// 判断Vuex中是否有token,如果有就添加到请求头
const token = store.state.user.profile.token
// 2. 判断是否有token
if (token) {
// 3. 设置token
config.headers.Authorization = 'Bearer ' + token
}
return config
}, (err) => {
return Promise.reject(err)
})
// ------------响应拦截器:处理后端返回的数据,把data属性去掉----------------
instance.interceptors.response.use((response) => {
return response.data
}, (err) => {
// 处理token的过期操作
if (err.response && err.response.status === 401) {
// token过期了,清空过期的用户信息,跳转到登录页面
store.commit('user/updateUserInfo', {})
router.push('/login')
}
return Promise.reject(err)
})
// ----------------封装一个通用的请求方法----------------------------
export default (options) => {
return instance({
// 如果没有传递请求方式,默认是使用get请求
method: options.method || 'GET',
// 请求地址
url: options.url,
// 对象的键可以是动态的变量
// get请求,添加params属性,其他请求添加data属性
[options.method.toUpperCase() === 'GET' ? 'params' : 'data']: options.data
// data用于传递请求体数据(POST/PUT/DELETE)
// data: options.data,
// params用于传递get请求数据(查询字符串)
// params: options.data
})
}
路由设计
目的:知道项目路由层级的设计
路径 | 组件(功能) | 嵌套级别 |
---|---|---|
/ | 首页布局容器 | 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级 |