Vue2 练手项目 |
您所在的位置:网站首页 › vue2实战教程 › Vue2 练手项目 |
项目代码:github.com/jiang-zi... 所需的前置知识 Vue 基础 vue-cli、指令、组件、路由、vuex axios baseURL、拦截器 element-ui 安装与配置、常用的组件 npm 与 模块化 能使用 npm 维护项目中的依赖包 ES6 模块化语法 项目初始化 基于 vue-cli 初始化 Vue2 模板的项目目的:为后面的项目开发做准备。 一 、创建项目 vue create 项目名称 二 、vue-cli 手动选择要安装的功能,选择第三个 Default ([Vue 2] babel, eslint) Default (Vue 3) ([Vue 3] babel, eslint) Manually select features 三 、初始化 vue-cli 的核心步骤:Manually select features (*) Choose Vue version (*) Babel ( ) TypeScript ( ) Progressive Web App (PWA) Support (*) Router (*) Vuex (*) CSS Pre-processors (*) Linter / Formatter ( ) Unit Testing ( ) E2E TestingChoose a version of Vue.js that you want to start the project with (Use arrow keys) 2.x 3.xUse history mode for router? (Requires proper server setup for index fallback in production) (Y/n) nPick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): (Use arrow keys) Sass/SCSS (with dart-sass) Sass/SCSS (with node-sass) Less StylusPick a linter / formatter config: (Use arrow keys) ESLint + Airbnb config ESLint + Standard config ESLint + PrettierPick additional lint features: (Press to select, to toggle all, to invert selection) (*) Lint on save ( ) Lint and fix on commitWhere do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys) In dedicated config files In package.jsonSave this as a preset for future projects? (y/N) N 注册功能 路由实现组件切换新建两个页面组件 在 views 下新建 Reg/Reg.vue 和 Login/Login.vue 在 router/index.js 中配置路由规则 在 App.vue 中使用 router-view 组件配置路由出口 在浏览器输入 http://localhost:8081/#/login 或 http://localhost:8081/#/reg 实现切换 渲染注册表单 去 element-ui 官网复制 form 组件的前四行, 补上结束标签 根据需求完善数据项的设置 美化样式 注册表单校验检查复制过来的表单组件中重要的属性是否存在 model rules ref prop (form-item)在 rules 对象中写校验规则(复制官网代码进行修改) 注册按钮点击事件中做兜底校验 注册功能实现 通过兜底校验后发送 ajax 请求, 携带数据对象 获取服务器返回的结果后根据状态码进行判断, 并提示用户 注册成功后使用编程式导航跳转至登录页 登录功能 渲染登录页面和跳转注册 去笔记中直接复制(课后练习建议从头来一遍) 给 el-link 添加点击事件, 编程式导航跳转至 /reg 点击按钮发起请求 给登录按钮绑定点击事件, 做兜底校验 如果通过校验就发起请求 获取请求结果, 进行判断并提示用户成功或失败 存储 token 至 Vuex 在 store/index.js 中定义子模块及数据, 并开启命名空间 定义 mutation 函数, 用于修改 Vuex 中的 token 登录成功时触发 mutation 的函数, 并传递 token token 持久化手动 (自己实现) 在 mutation 函数中使用 localStorage.setItem() 存储 token 在 state 初始化值的时候使用 localStorage.getItem() 取出 token插件 (自动实现) 安装该插件后, 会自动持久化存储 Vuex 中所有的数据, 如需进行进一步的配置, 请查看官网 下包 yarn add vuex-persistedstate 导入 安装插件 登录成功跳转至首页 登录成功后使用编程式导航跳转至 / 后台主页 配置路由规则, 新建 Main.vue 首页 将笔记中 Main.vue 的结构样式复制过来 退出登录 找到退出登录按钮, 给 menu-item 绑定点击事件 用户点击退出时使用 $confirm 确认框提醒用户是否真的要退出 用户确认退出时, 清空 Vuex 中的 token 并跳转至 /login 登录页 侧边栏菜单 渲染用户信息 去笔记中复制静态页面及 CSS 样式 在 Vuex 中定义 userInfo 数据 在 actions 中封装一个获取用户信息的函数 发起请求获取用户信息 (通过 context 可以获取到 state) 将获取到的用户信息传递给 mutations 进行修改 userInfo 在 Main.vue 的 created 中使用 this.$store.dispatch() 触发 actions 函数执行 将数据导入 Main.vue (使用辅助函数) 渲染数据 渲染侧边菜单布局去官网复制 el-menu 的代码并进行学习 el-menu: 导航菜单容器 default-active: 默认高亮的菜单项el-menu-item: 没有子菜单的项目 index: 菜单项的唯一标识el-submenu: 有子菜单的项目 复制笔记中的样式进行美化 渲染侧边菜单数据在 Main.vue 中封装 getMenus 函数, 在 created 中调用, 发起请求获取菜单数据并存入 data 由于循环渲染的菜单项有两种类型, 所以需要使用 template 标签包裹 在 template 标签上写 v-for 循环渲染 template 是虚拟标签, 不能绑定 key, 需要将 key 设置在子元素上在两个子菜单标签上通过 v-if 进行判断具体显示哪个菜单项 使用插值表达式和 v-bind 动态渲染内容 动态绑定 index 属性, 用于导航高亮el-submenu 还需要继续使用 v-for 渲染子菜单 开启路由模式方便后续开发 优化请求 token在 main.js 中给 axios 添加请求拦截器 拦截时携带 token 给请求头 在 main.js 中可以直接使用 store 对象获取到 Vuex 中的数据之前手动携带 token 的地方可以删除请求头配置 权限控制 未登录禁止访问首页 - 导航守卫在 router/index.js 中配置全局前置导航守卫 判断条件有 2 个需要进行拦截: 本地没有 token 不是访问 /login 和 /reg 页面时 已登录但 Token 过期 - axios 的响应拦截器 添加 axios 响应拦截器, 判断状态码为 401 的情况 给用户友好的提示 跳转至 /login 页面并清空 token 和 userInfo 渲染首页 创建 views/Menus/Home/Home.vue 组件, 复制笔记中的代码 观察代码发现需要 echarts, 所以下载 echarts 包 希望访问 /home 时切换到该组件显示, 配置 Main 的子路由 在 Main.vue 中写一个 router-view 作为路由出口 给 Main 路由规则配置重定向 个人中心 - 基本资料 使用路由渲染组件 创建 views/Menus/User/UserInfo.vue 组件, 复制笔记中的代码 配置路由规则, 同 Home 组件 渲染表单 去官网找到 form 组件进行复制 根据需求修改成项目需要的样式 在 UserInfo.vue 中导入辅助函数并映射 userInfo 数据 在 created 中将 userInfo 赋值给 userForm, 需要使用浅拷贝, 确保两个对象互不影响 在 userRules 中添加表单校验规则 重置表单 给重置按钮绑定点击事件 调用表单对象的 resetFields() 方法 更新用户信息 点击提交进行兜底校验 校验通过后发送请求更新用户信息 获取结果进行判断, 并提醒用户 如果更新成功, 重新发起请求获取最新的用户信息 个人中心 - 更换头像 使用路由渲染组件 创建 views/Menus/User/UserAvatar.vue 组件, 复制笔记中的代码 配置路由规则, 同上 选择图片 添加文件选择框在按钮上方, 但由于文件选择框太丑, 所以将其隐藏 给选择图片按钮绑定点击事件, 触发文件选择框的点击事件 给文件框绑定 change 事件 当用户选择图片时触发 change 事件, 并获取 e.target.files 根据 files 的长度来判断用户是否选择了图片 渲染预览图片使用 FileReader 将 File 对象转换为 BASE64 字符串 // 使用 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 }转换为 BASE64 后将字符串赋值给 avatar 准备两个 img 根据 avatar 的值进行 v-if 选择渲染 渲染完成后对上传按钮的 disabled 进行判断 更新用户头像 给按钮绑定点击事件, 发送请求携带 avatar 数据 根据响应的状态提示用户 重新获取用户信息 个人中心 - 修改密码 使用路由渲染组件 创建 views/Menus/User/UserPwd.vue 组件, 复制笔记中的代码 配置路由规则, 同上 表单校验 编写基础表单校验规则 (如果非常熟练可复制) 使用自定义校验规则进行两次密码相同校验 重置表单 给重置按钮绑定点击事件 调用表单对象的 resetFields() 方法 修改用户密码 给按钮绑定点击事件, 点击时进行兜底校验 校验通过后发起请求 获取结果并根据状态提示用户 重置表单 文章管理 - 文章分类 使用路由渲染组件 创建 views/Menus/Article/ArtCate.vue 组件, 复制笔记中的代码 配置路由规则, 同上 获取分类数据 在 created 中发起请求 获取数据判断结果 将数据存入 data 中 渲染表格去 Element-UI 的官网复制表格代码 根据需求改造表格代码并渲染数据 table-column 设置 type 为 index 就是序号列修改样式注意权重问题 渲染添加分类 Dialog 去 Element-UI 的官网复制最基础的 dialog 代码 根据需求修改绑定的数据和样式 在 dialog 中添加一个 form 组件, 两者结合使用 数据绑定并新增校验规则 关闭时重置表单 给 dialog 绑定事件: closed 事件触发时调用表单的重置方法即可 添加文章分类功能实现 给添加按钮绑定点击事件, 事件触发时进行兜底校验 校验通过后发起请求将用户输入的内容提交给后台 获取响应结果, 根据结果提醒用户 重新发起请求渲染页面 关闭 dialog 渲染修改分类 Dialog 将添加分类的 dialog 完整的复制一份 根据需求修改或添加所有的文本和数据变量 点击编辑按钮让 dialog 显示 (先不考虑功能实现, 仅做展示) 给编辑按钮绑定点击事件, 传入当前行数据 (作用域插槽: scope.row) 判断 id 是否为 1 或 2 并提醒用户不允许修改 将 row 浅拷贝给 editForm, 展示当前点击编辑的分类数据 将 editVisible 设置为 true (显示 dialog) 编辑文章分类功能实现 给确定按钮绑定点击事件, 事件触发时进行兜底校验 校验通过后发起请求将用户输入的内容提交给后台 获取响应结果, 根据结果提醒用户 重新发起请求渲染页面 关闭 dialog 删除文章分类 给删除按钮绑定点击事件, 传入 id 事件触发判断 id 是否为 1 或 2 并提醒用户不允许修改 发起请求给后台进行删除 (查询参数) 获取响应结果, 根据结果提醒用户 重新发起请求渲染页面 文章管理 - 发表文章 使用路由渲染组件 创建 views/Menus/Article/ArtList.vue 组件, 复制笔记中的代码 配置路由规则, 同上 弹出发表文章 Dialog 去 Element-UI 官网复制 Dialog 组件代码, 设置 fullscreen 属性变成全屏 dialog 绑定 :before-close 属性, 做关闭前的回调, 确保用户点击关闭不会直接关掉 dialog 当用户关闭时 this.$confirm 提醒用户, 是否确定关闭 如果确定关闭就关闭 dialog 渲染文章标题和文章分类表单 去 Element-UI 官网复制 Form 组件的代码 根据需求修改为我们想要的效果 双向绑定数据并设置表单校验规则 渲染文章分类数据 发送请求获取分类列表数据 使用 v-for 循环渲染 el-option 动态绑定 value 和 label 渲染富文本编辑器 下包 vue-quill-editor 按照官方文档导入并全局注册 使用组件, 并双向绑定数据 使用深度选择器修改样式 (min-height) 添加表单校验规则 渲染文章封面 去笔记中将静态结构复制到指定区域 添加 form-item 写 img 标签并修改样式 准备一个文件选择框, 将其设置为隐藏 准备一个按钮 用户选择图片 给选择封面按钮绑定点击事件, 用户点击时触发文件选择框的点击事件 给文件选择框绑定 change 事件 在 change 事件中使用事件对象获取用户选择的文件对象 判断用户选择的文件对象, 进行存储到表单或清空表单的封面图片 渲染预览图片 当用户选择图片后, 使用 FileReader 将图片对象转成 BASE64 字符串 设置给预览图片的 src 当用户取消选择后, 导入本地的默认图片, 将其设置给图片的 src 发布前准备工作 渲染两个按钮, 并绑定点击事件 事件触发时进行表单的兜底校验 通过校验后设置 state 为 '已发布' 或 '草稿' 关闭 dialog 时清空所有表单数据及预览的图片 发布文章 使用 FormData 填装参数 发起请求, 携带 FormData 根据结果提醒用户 关闭 dialog 将来实现了文章列表功能后, 还需要重新发请求获取最新的文章列表数据 文章管理 - 文章列表 渲染列表数据 封装获取列表数据的函数, 在 created 中调用获取数据存入 data 中 去 Element-UI 官网复制 Table 组件进行数据渲染 发表文章完成后, 调用封装的获取列表函数, 重新渲染页面 格式化日期 下包 dayjs 引入到组件中 封装一个 formatDate 的函数 在函数中格式化日期后返回 使用作用域插槽获取日期数据, 调用函数, 传入日期数据并使用插值表达式渲染 分页功能 去 Element-UI 官网复制 Pagination 组件 根据需求进行修改 (q.pagenum / q.pagesize / total) 获取数据时将 total 存入 data 中 结合 current-change 和 size-change 事件实现分页功能 当前页发生变化时将 q 的 pagenum 重新赋值并发起请求 pagesize 同理 筛选功能 渲染文章分类的下拉菜单, 进行双向绑定 q 的属性 当用户点击筛选按钮时触发点击事件 点击事件中将 q.pagenum 设置为 1 后重新发起请求渲染数据 重置筛选 给重置按钮绑定点击事件 事件触发时将所有请求参数清空 重新发起请求渲染数据 预览文章 - 获取文章数据 使用作用域插槽将文章标题改为 el-link 组件 给标题绑定点击事件, 并传入 id 事件触发时根据 id 获取文章详情数据, 存入 data 中 将 dialog 显示出来 预览文章 - 渲染数据 将获取到的数据使用插值表达式渲染到对应的区域 设置样式 删除文章 使用作用域插槽包裹 el-button 给 el-button 绑定点击事件, 并传入 id 事件触发时根据 id 删除文章 重新发起请求渲染文章列表数据 优化删除的操作发起请求删除文章完成以后,做如下判断在渲染文章列表 this.$message.success('删除成功!') // 如果在刷新数据之前,当前页的数据只有 1 条, // 而且,当前的页码值 > 1, // 则说明当前页已没有数据可显示,需要让页码值 -1 + if (this.artList.length === 1 && this.q.pagenum > 1) { + this.q.pagenum-- + } // 重新发起请求渲染文章列表数据 this.initArtList() 打包发布 生成打包报告打开 package.json 配置文件,为 scripts 节点下的 build 命令添加 --report 参数: { "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build --report", "lint": "vue-cli-service lint" } }重新运行打包的命令: npm run build 或 yarn bulid打包完成后,发现在 dist 目录下多了一个名为 report.html 的文件。在浏览器中打开此文件,会看到详细的打包报告。 未配置 externals 之前: 凡是 import 导入的第三方模块,在最终打包完成后,会被合并到 chunk-vendors.js 中 缺点:导致单个文件的体积过大配置了 externals 之后: webpack 在进行打包时,会把 externals 节点下声明的第三方包排除在外 因此最终打包生成的 js 文件中,不会包含 externals 节点下的包 好处:优化了打包后项目的体积。 初步配置 externals 节点在项目根目录下创建 vue.config.js 配置文件,在里面新增 configureWebpack 节点如下: module.exports = { // 省略其它代码... // 增强 vue-cli 的 webpack 配置项 configureWebpack: { // 打包优化 externals: { // import导包的包名: window全局的成员名称 echarts: 'echarts', vue: 'Vue', 'vue-router': 'VueRouter', vuex: 'Vuex', axios: 'axios', dayjs: 'dayjs', 'element-ui': 'ELEMENT', 'vue-quill-editor': 'VueQuillEditor', 'vuex-persistedstate': 'createPersistedState' } } }在 /public/index.html 文件中,新增如下的资源引用: 在 main.js 中注释掉 element-ui 的样式和 quill 的样式: // 1. 导入 element-ui 组件库的样式 // import 'element-ui/lib/theme-chalk/index.css' // 2. 导入 quill 的样式 // import 'quill/dist/quill.core.css' // import 'quill/dist/quill.snow.css' // import 'quill/dist/quill.bubble.css'在 /public/index.html 文件的 标签之后,引入需要的 css 样式: 配置路由懒加载 优化性能参考 vue-router 的官方文档,进行路由懒加载的配置 配置路由懒加载的核心步骤: 运行如下的命令,安装 babel 插件: npm install --save-dev @babel/plugin-syntax-dynamic-import修改项目根目录下的 babel.config.js 配置文件,新增 plugins 节点: module.exports = { presets: ['@vue/cli-plugin-babel/preset'], // 实现路由组件按需导入的 babel 插件 + plugins: ['@babel/plugin-syntax-dynamic-import'] }在 /src/router/index.js 模块中,基于 const 组件 = () => import('组件的存放路径') 语法,改造每个路由组件的导入方式。例如: // 路由懒加载 vue 异步组件技术 导入 const Reg = () => import('@/views/Reg/Reg.vue') const Login = () => import('../views/Login/login.vue') const Main = () => import('@/views/main/main') const Home = () => import('../views/menus/Home/Home.vue') const UserInfo = () => import('../views/menus/User/UserInfo.vue') const UserAvatar = () => import('../views/menus/User/UserAvatar.vue') const UserPwd = () => import('../views/menus/User/UserPwd.vue') const ArtCate = () => import('../views/menus/Article/ArtCate.vue') const ArtList = () => import('../views/menus/Article/ArtList.vue')项目地址:github.com/jiang-zi... |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |