# vue-ev-70 **Repository Path**: leetc/vue-ev-70 ## Basic Information - **Project Name**: vue-ev-70 - **Description**: 这是一个大事件项目,很大! - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 0 - **Created**: 2022-01-13 - **Last Updated**: 2022-08-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 大事件项目纪要 ## 注册功能 ### 路由实现组件切换 1. 新建两个页面组件 在 views 下新建 Reg/Reg.vue 和 Login/Login.vue 2. 在 router/index.js 中配置路由规则 3. 在 App.vue 中使用 router-view 组件配置路由出口 4. 在浏览器输入 http://localhost:8081/#/login 或 http://localhost:8081/#/reg 实现切换 ### 渲染注册表单 1. 去官网复制 form 组件的前四行, 补上结束标签 2. 根据需求完善数据项的设置 3. 美化样式 ### 注册表单校验 1. 检查复制过来的表单组件中重要的属性是否存在 - model - rules - ref - prop (form-item) 2. 在 rules 对象中写校验规则(复制官网代码进行修改) 3. 注册按钮点击事件中做兜底校验 ### 注册功能实现 1. 通过兜底校验后发送 ajax 请求, 携带数据对象 2. 获取服务器返回的结果后根据状态码进行判断, 并提示用户 3. 注册成功后使用编程式导航跳转至登录页 ## 登录功能 ### 渲染登录页面和跳转注册 1. 去笔记中直接复制(课后练习建议从头来一遍) 2. 给 `el-link` 添加点击事件, 编程式导航跳转至 `/reg` ### 点击按钮发起请求 1. 给登录按钮绑定点击事件, 做兜底校验 2. 如果通过校验就发起请求 3. 获取请求结果, 进行判断并提示用户成功或失败 ### 存储 token 至 Vuex 1. 在 `store/index.js` 中定义子模块及数据, 并开启命名空间 2. 定义 mutation 函数, 用于修改 Vuex 中的 token 3. 登录成功时触发 mutation 的函数, 并传递 token ### token 持久化 1. 手动 (自己实现) - 在 mutation 函数中使用 `localStorage.setItem()` 存储 token - 在 state 初始化值的时候使用 `localStorage.getItem()` 取出 token 2. 插件 (自动实现) > 安装该插件后, 会自动持久化存储 Vuex 中所有的数据, 如需进行进一步的配置, 请查看官网 - 下包 `yarn add vuex-persistedstate` - 导入 - 安装插件 ### 登录成功跳转至首页 1. 登录成功后使用编程式导航跳转至 `/` 后台主页 2. 配置路由规则, 新建 `Main.vue` 首页 3. 将笔记中 `Main.vue` 的结构样式复制过来 ### 退出登录 1. 找到退出登录按钮, 给 `menu-item` 绑定点击事件 2. 用户点击退出时使用 `$confirm` 确认框提醒用户是否真的要退出 3. 用户确认退出时, 清空 Vuex 中的 token 并跳转至 `/login` 登录页 ## 侧边栏菜单 ### 渲染用户信息 1. 去笔记中复制静态页面及 CSS 样式 2. 在 Vuex 中定义 `userInfo` 数据 3. 在 `actions` 中封装一个获取用户信息的函数 4. 发起请求获取用户信息 (通过 `context` 可以获取到 `state`) 5. 将获取到的用户信息传递给 `mutations` 进行修改 `userInfo` 6. 在 `Main.vue` 的 created 中使用 `this.$store.dispatch()` 触发 `actions` 函数执行 7. 将数据导入 `Main.vue` (使用辅助函数) 8. 渲染数据 ### 渲染侧边菜单布局 1. 去官网复制 el-menu 的代码并进行学习 - el-menu: 导航菜单容器 - default-active: 默认高亮的菜单项 - el-menu-item: 没有子菜单的项目 - index: 菜单项的唯一标识 - el-submenu: 有子菜单的项目 2. 复制笔记中的样式进行美化 ### 渲染侧边菜单数据 1. 在 Main.vue 中封装 getMenus 函数, 在 created 中调用, 发起请求获取菜单数据并存入 data 2. 由于循环渲染的菜单项有两种类型, 所以需要使用 template 标签包裹 3. 在 template 标签上写 v-for 循环渲染 - template 是虚拟标签, 不能绑定 key, 需要将 key 设置在子元素上 4. 在两个子菜单标签上通过 v-if 进行判断具体显示哪个菜单项 5. 使用插值表达式和 v-bind 动态渲染内容 - 动态绑定 index 属性, 用于导航高亮 6. el-submenu 还需要继续使用 v-for 渲染子菜单 7. 开启路由模式方便后续开发 ### 优化请求 token 1. 在 main.js 中给 axios 添加请求拦截器 2. 拦截时携带 token 给请求头 - 在 main.js 中可以直接使用 store 对象获取到 Vuex 中的数据 3. 之前手动携带 token 的地方可以删除请求头配置 ### 权限控制 #### 未登录禁止访问首页 - 导航守卫 1. 在 router/index.js 中配置全局前置导航守卫 2. 判断条件有 2 个需要进行拦截: 1. 本地没有 token 2. 不是访问 /login 和 /reg 页面时 #### 已登录但 Token 过期 - axios 的响应拦截器 1. 添加 axios 响应拦截器, 判断状态码为 401 的情况 2. 给用户友好的提示 3. 跳转至 /login 页面并清空 token 和 userInfo ### 渲染首页 1. 创建 views/Menus/Home/Home.vue 组件, 复制笔记中的代码 2. 观察代码发现需要 echarts, 所以下载 echarts 包 3. 希望访问 /home 时切换到该组件显示, 配置 Main 的子路由 4. 在 Main.vue 中写一个 router-view 作为路由出口 5. 给 Main 路由规则配置重定向 ## 个人中心 - 基本资料 ### 使用路由渲染组件 1. 创建 views/Menus/User/UserInfo.vue 组件, 复制笔记中的代码 2. 配置路由规则, 同 Home 组件 ### 渲染表单 1. 去官网找到 form 组件进行复制 2. 根据需求修改成项目需要的样式 3. 在 UserInfo.vue 中导入辅助函数并映射 userInfo 数据 4. 在 created 中将 userInfo 赋值给 userForm, 需要使用浅拷贝, 确保两个对象互不影响 4. 在 userRules 中添加表单校验规则 ### 重置表单 1. 给重置按钮绑定点击事件 2. 调用表单对象的 `resetFields()` 方法 ### 更新用户信息 1. 点击提交进行兜底校验 2. 校验通过后发送请求更新用户信息 3. 获取结果进行判断, 并提醒用户 4. 如果更新成功, 重新发起请求获取最新的用户信息 ## 个人中心 - 更换头像 ### 使用路由渲染组件 1. 创建 views/Menus/User/UserAvatar.vue 组件, 复制笔记中的代码 2. 配置路由规则, 同上 ### 选择图片 1. 添加文件选择框在按钮上方, 但由于文件选择框太丑, 所以将其隐藏 2. 给选择图片按钮绑定点击事件, 触发文件选择框的点击事件 3. 给文件框绑定 change 事件 4. 当用户选择图片时触发 change 事件, 并获取 e.target.files 5. 根据 files 的长度来判断用户是否选择了图片 ### 渲染预览图片 1. 使用 FileReader 将 File 对象转换为 BASE64 字符串 ```js // 使用 FileReader 将 File 对象转换为 BASE64 并设置给 avatar // 创建 FileReader const fr = new FileReader() // 读取 File 对象 fr.readAsDataURL(e.target.files[0]) // 绑定事件, 必须使用箭头函数, 因为要访问 data 中的数据 fr.onload = e => { // console.log(e.target.result) // 触发事件后赋值 this.avatar = e.target.result } ``` 2. 转换为 BASE64 后将字符串赋值给 avatar 3. 准备两个 img 根据 avatar 的值进行 v-if 选择渲染 4. 渲染完成后对上传按钮的 disabled 进行判断 ### 更新用户头像 1. 给按钮绑定点击事件, 发送请求携带 avatar 数据 2. 根据响应的状态提示用户 3. 重新获取用户信息 ## 个人中心 - 修改密码 ### 使用路由渲染组件 1. 创建 views/Menus/User/UserPwd.vue 组件, 复制笔记中的代码 2. 配置路由规则, 同上 ### 表单校验 1. 编写基础表单校验规则 (如果非常熟练可复制) 2. 使用自定义校验规则进行两次密码相同校验 ### 重置表单 1. 给重置按钮绑定点击事件 2. 调用表单对象的 `resetFields()` 方法 ### 修改用户密码 1. 给按钮绑定点击事件, 点击时进行兜底校验 2. 校验通过后发起请求 3. 获取结果并根据状态提示用户 4. 重置表单 ## 文章管理 - 文章分类 ### 使用路由渲染组件 1. 创建 views/Menus/Article/ArtCate.vue 组件, 复制笔记中的代码 2. 配置路由规则, 同上 ### 获取分类数据 1. 在 created 中发起请求 2. 获取数据判断结果 3. 将数据存入 data 中 ### 渲染表格 1. 去 Element-UI 的官网复制表格代码 2. 根据需求改造表格代码并渲染数据 - table-column 设置 type 为 index 就是序号列 3. 修改样式注意权重问题 ### 渲染添加分类 Dialog 1. 去 Element-UI 的官网复制最基础的 dialog 代码 2. 根据需求修改绑定的数据和样式 3. 在 dialog 中添加一个 form 组件, 两者结合使用 4. 数据绑定并新增校验规则 ### 关闭时重置表单 1. 给 dialog 绑定事件: closed 2. 事件触发时调用表单的重置方法即可 ### 添加文章分类功能实现 1. 给添加按钮绑定点击事件, 事件触发时进行兜底校验 2. 校验通过后发起请求将用户输入的内容提交给后台 3. 获取响应结果, 根据结果提醒用户 4. 重新发起请求渲染页面 5. 关闭 dialog ### 渲染修改分类 Dialog 1. 将添加分类的 dialog 完整的复制一份 2. 根据需求修改或添加所有的文本和数据变量 3. ~~点击编辑按钮让 dialog 显示 (先不考虑功能实现, 仅做展示)~~ 4. 给编辑按钮绑定点击事件, 传入当前行数据 (作用域插槽: scope.row) 5. 判断 id 是否为 1 或 2 并提醒用户不允许修改 6. 将 row 浅拷贝给 editForm, 展示当前点击编辑的分类数据 7. 将 editVisible 设置为 true (显示 dialog) ### 编辑文章分类功能实现 1. 给确定按钮绑定点击事件, 事件触发时进行兜底校验 2. 校验通过后发起请求将用户输入的内容提交给后台 3. 获取响应结果, 根据结果提醒用户 4. 重新发起请求渲染页面 5. 关闭 dialog ### 删除文章分类 1. 给删除按钮绑定点击事件, 传入 id 2. 事件触发判断 id 是否为 1 或 2 并提醒用户不允许修改 3. 发起请求给后台进行删除 (查询参数) 4. 获取响应结果, 根据结果提醒用户 5. 重新发起请求渲染页面 ## 文章管理 - 发表文章 ### 使用路由渲染组件 1. 创建 views/Menus/Article/ArtList.vue 组件, 复制笔记中的代码 2. 配置路由规则, 同上 ### 弹出发表文章 Dialog 1. 去 Element-UI 官网复制 Dialog 组件代码, 设置 fullscreen 属性变成全屏 dialog 2. 绑定 :before-close 属性, 做关闭前的回调, 确保用户点击关闭不会直接关掉 dialog 3. 当用户关闭时 this.$confirm 提醒用户, 是否确定关闭 4. 如果确定关闭就关闭 dialog ### 渲染文章标题和文章分类表单 1. 去 Element-UI 官网复制 Form 组件的代码 2. 根据需求修改为我们想要的效果 3. 双向绑定数据并设置表单校验规则 ### 渲染文章分类数据 1. 发送请求获取分类列表数据 2. 使用 v-for 循环渲染 el-option 3. 动态绑定 value 和 label ### 渲染富文本编辑器 1. 下包 vue-quill-editor 2. 按照官方文档导入并全局注册 3. 使用组件, 并双向绑定数据 4. 使用深度选择器修改样式 (min-height) 5. 添加表单校验规则 ### 渲染文章封面 1. 去笔记中将静态结构复制到指定区域 2. 添加 form-item 3. 写 img 标签并修改样式 4. 准备一个文件选择框, 将其设置为隐藏 5. 准备一个按钮 ### 用户选择图片 1. 给选择封面按钮绑定点击事件, 用户点击时触发文件选择框的点击事件 2. 给文件选择框绑定 change 事件 3. 在 change 事件中使用事件对象获取用户选择的文件对象 4. 判断用户选择的文件对象, 进行存储到表单或清空表单的封面图片 ### 渲染预览图片 1. 当用户选择图片后, 使用 FileReader 将图片对象转成 BASE64 字符串 2. 设置给预览图片的 src 3. 当用户取消选择后, 导入本地的默认图片, 将其设置给图片的 src ### 发布前准备工作 1. 渲染两个按钮, 并绑定点击事件 2. 事件触发时进行表单的兜底校验 3. 通过校验后设置 state 为 `'已发布'` 或 `'草稿'` 4. 关闭 dialog 时清空所有表单数据及预览的图片 ### 发布文章 1. 使用 FormData 填装参数 2. 发起请求, 携带 FormData 3. 根据结果提醒用户 4. 关闭 dialog 5. 将来实现了文章列表功能后, 还需要重新发请求获取最新的文章列表数据 ## 文章管理 - 文章列表 ### 渲染列表数据 1. 封装获取列表数据的函数, 在 created 中调用获取数据存入 data 中 2. 去 Element-UI 官网复制 Table 组件进行数据渲染 3. 发表文章完成后, 调用封装的获取列表函数, 重新渲染页面 ### 格式化日期 1. 下包 dayjs 2. 引入到组件中 3. 封装一个 formatDate 的函数 4. 在函数中格式化日期后返回 5. 使用作用域插槽获取日期数据, 调用函数, 传入日期数据并使用插值表达式渲染 ### 分页功能 1. 去 Element-UI 官网复制 Pagination 组件 2. 根据需求进行修改 (q.pagenum / q.pagesize / total) 3. 获取数据时将 total 存入 data 中 4. 结合 current-change 和 size-change 事件实现分页功能 5. 当前页发生变化时将 q 的 pagenum 重新赋值并发起请求 6. pagesize 同理 ### 筛选功能 1. 渲染文章分类的下拉菜单, 进行双向绑定 q 的属性 2. 当用户点击筛选按钮时触发点击事件 3. 点击事件中将 q.pagenum 设置为 1 后重新发起请求渲染数据 ### 重置筛选 1. 给重置按钮绑定点击事件 2. 事件触发时将所有请求参数清空 3. 重新发起请求渲染数据 ### 预览文章 - 获取文章数据 1. 使用作用域插槽将文章标题改为 el-link 组件 2. 给标题绑定点击事件, 并传入 id 3. 事件触发时根据 id 获取文章详情数据, 存入 data 中 4. 将 dialog 显示出来 ### 预览文章 - 渲染数据 1. 将获取到的数据使用插值表达式渲染到对应的区域 2. 设置样式 ### 删除文章 1. 使用作用域插槽将文章 id 传递给删除按钮点击事件的处理函数中 2. 使用 $confirm 提醒用户是否删除 3. 用户确定删除后发起请求删除数据 4. 重新发起请求渲染页面 5. 越界处理 (当最后一页删没了需要让 pagenum--)