文章目录
Vue项目–尚品汇
项目简介
1.1前台项目
技术架构:vue+webpack+vuex+vue-router+axios+less…
主要内容:封装通用组件、登入注册、token、守卫、购物车、项目性能优化等。
1.2后台项目
技术架构:vue+webpack+vuex+vue-router+axios+scss+elementUI…
主要内容:elementUI、菜单权限、按钮权限、数据可视化等。
1.3实际代码
源码在gitee中,链接在此:
https://gitee.com/marygood/vue-project-sph/tree/master/app
1.day01
1.1开发准备
在项目当前目录下,输入
cmd
,打开命令行提示符,再输入vue create app
,安装vue2脚手架
(前提是已安装npm)。1.2项目文件夹功能介绍
node_modules文件夹:
放置项目依赖的地方。
public文件夹:
一般放置一些共用的静态资源(图片)。需要注意的是webpack
进行打包的时候,public文件夹
里面的内容会原封不动打包到dist文件夹
里面。
src文件夹
(程序员源代码文件夹):
assets文件夹
:放置静态资源(一般放置多个组件共用的静态资源),需要注意的是webpack
进行打包时会把静态资源当作一个模块,打包到JS文件夹
里面。
components文件夹
:一般放置非路由组件(全局组件)。
App.vue
:唯一的根组件。
main.js
:入口文件(程序最先执行的文件)。
babel.config.js
:配置文件(与babel相关)。注:babel的作用是将
JS语法
进行解析,把高版本的语法解析为低版本的语法,主要是用于兼容。
package.json
:项目的身份证。记录项目名称、项目中有哪些依赖、项目如何运行等。
package-lock.json
缓存性文件。
README.md
项目说明文件,依赖是哪里来的都给你记录了。1.3项目配置
在
package.json
文件中设置项目运行浏览器自动打开
。//package.json "scripts": { "serve": "vue-cli-service serve --open", //项目运行完自动打开浏览器 "build": "vue-cli-service build", "lint": "vue-cli-service lint" }
在
vue.config.js
文件中关闭eslint校验功能
。//vue.config.js module.exports = { lintOnSave:false, }
在
vue.config.js
中设置浏览器打开的IP地址及端口号。//vue.config.js module.exports = defineConfig({ // 设置浏览器打开的IP地址及端口号 devServer: { open: true, host: 'localhost', //这里因为8080端口已经被占用,如果没被占用忽略此步 port: 8000 } })
src
文件夹的别名的设置(现在的版本已经有这项配置){ "compilerOptions": { "baseUrl": "./", "paths": { "@/*": [ "src/*" ] } }, "exclude": [ "node_modules", "dist" ] }
1.4项目路由的分析
vue-router 前端所谓路由:KV键值对。 Key:URL(地址栏中的路径) value:相应的路由组件 注意:项目是上中下结构 跳转的时候只有中间部分在发生变化,所以中间部分应该使用的是路由组件。 路由组件: Home、Search、Login登录路由(没有底部的Footer组件–带有二维码的)、Register注册路由 非路由组件: Header 【首页、搜索页】 Footer【首页、搜索页】,但是登入、注册页是没有的
1.5创建非路由组件Header与Footer业务
项目开发的时候: 1.书写静态页面(html+css) 2.拆分组件 3.获取服务器的数据动态展示 4.完成相应的动态业务逻辑 注意: 1.创建组件的时候需要:组件结构 + 组件样式 + 图片资源 注:复制粘贴的时候一部分一部分来。 2.本项目采用less样式,但是浏览器不识别,所以需要通过安装less、less-loader进行处理。 注:此处安装的是npm i less-loader@5 3.安装完成之后,还是会报错,想让组件识别less样式,需要在style标签上添加lang="less"。 使用组件的步骤(非路由组件): 第一步:创建或定义 第二步:引入 第三步:注册 第四步:使用
1.6路由组件的搭建
安装vue-router注意安装@3版本(vue2只能安装3版本) 路由组件有四个:Home、Search、Login、Register components文件夹:经常存放的是非路由组件(共用全局组件) pages或views文件夹:经常存放路由组件
1.6.1路由的配置
项目当中配置的路由一般放在router文件夹中 router文件夹中创建index.js文件 需要引入Vue和VueRouter 然后暴露路由实例,然后里面配置对象(路由)----就是写一个个对象,里面是path和component 之后将要暴露的路由组件引入–对象中需要告诉路径path和组件component 之后需要路由文件执行一次,路由文件需要在入口文件main.js中注册
1.6.2小结
问:路由组件与非路由组件的区别? 1.路由组件放在pages或views中,非路由组件放在components中。 2.路由组件一般需要在router文件夹中进行注册,而非路由组件一般都以标签的形式使用。(重要) 3.注册完路由不管是路由组件还是非路由组件,都会拥有$route,$router属性。 $route:一般获取路由信息【路径、query、params等】 $router:一般进行编程式导航、路由跳转【push或replace】
1.6.3路由的跳转
路由的跳转就两种形式: 声明式导航router-link和编程式导航push|replace都可以进行路由跳转. 编程式导航更好用,声明式导航可以做的编程式导航都可以做,并且编程式导航除了路由跳转,还可以在路由跳转之前做一些其他的业务逻辑。
1.7Footer组件显示与隐藏
显示和隐藏组件:v-if或v-show(后者更好) Footer组件在主页和搜索页显示,在登入和注册页隐藏。 面试题: v-show与v-if区别? v-show:通过样式display控制。 v-if:通过元素上树与下树进行操作,操作DOM,效率低。
我们可以根据组件身上的
$route
获取当前路由的信息,通过路由路径判断是否显示或隐藏。// 第一种写法 <Footer v-show="$route.path == '/home' || $route.path == '/search'" /> // 第二种写法(优化写法) <Footer v-show="$route.meta.show" />
配置路由时,如果想添加自定义内容时可以给路由添加路由元信息【meta】。
// router/index.js文件 // 第二种写法需要的配置 routes: [ { path: "/home", component: Home, meta: { show: true } }, { path: "/login", component: Login, meta: { show: false } }, ...都要配置meta... ]
1.8路由传参
1.8.1实践代码
params参数:属于路径中的一部分,在配置路由时需要占位。 query参数:不属于路径中的一部分,写法类似于ajax当中queryString(/home?k=v&k=v),不需要占位。
// components/Header/index.vue文件 // 小写是parans参数,大写是query参数(带问号的键值对形式) goSearch() { // 路由传参 // 第一种字符串形式 /* this.$router.push( "/search/" + this.keyword + "?k=" + this.keyword.toUpperCase() ); */ // 第二种模板字符串 /* this.$router.push( `/search/${this.keyword}?k=${this.keyword.toUpperCase()}` ); */ // 第三种对象写法,params要在router/index.js中配置name this.$router.push({ name: "search", params: { keyword: this.keyword, }, query: { k: this.keyword.toUpperCase(), }, }); },
//router/index.js文件 { name: "search", // params需要占位 path: "/search/:keyword", component: Search, meta: { show: true } },
1.8.2路由传参面试题
1.路由传递参数(对象写法)path是否可以结合params参数一起使用? 答:不可以。路由跳转传参时,对象的写法可以是name或者path,但是path写法不能与params参数一起使用。 2.如何指定params参数可传可不传? 答:在配置路由的时候,在占位的后面加上一个问号。path: "/search/:keyword?" 3.params参数可以传递也可以不传递,但是如果传递的是空串,该怎么解决? 答:使用undefind解决。 { name: 'search', params: { keyword: ' ' || undefined }, query: {...} } 4.路由组件能不能传递props数据? 答:可以。 第一种:布尔值方式,不过这种写法只能传递params参数。 在配置路由的时候加上 { props: true } 同时在组件中用 props: ['keyword'] 接收,组件中就可以直接写{{ keyword }},不用写$route.params.XXX。 Header中该传的还得传:this.$router.push("/search/" + this.keyword); 第二种:对象写法,简单讲就是额外给路由组件传递一些参数。 props: { a: 1, b: 2 } 第三种:函数写法,可以传递params参数和query参数,通过props传递给路由组件,最常用。 这种方法也是为了组件获取参数方便,可以直接写{{ keyword }}、{{ k }}。 不过这里老师推荐最开始的写法。(建议使用模版字符串) props: ($route) => { return { keyword: $route.params.keyword, k: $route.query.k } }
1.9后续报错
之前我们为了去除默认样式在public文件夹中引入了
resset.css文件
。由于在reset.css文件中引入不存在的iconfont.css文件
产生报错,所以我们要把@import "./iconfont.css";
语句注释掉,不再引入不存在的文件。
2.day02
2.1重写push和replace方法(了解)
1.编程式导航路由跳转到当前路由(参数不变), 多次执行会抛出NavigationDuplicated的警告错误? -路由跳转由两种形式:编程式导航(push|replace)、声明式导航router-link -声明式导航是没有这种问题,因为vue-router底层已经处理好了。 1.1 编程式导航为什么会出现这种警告现象? 答:由于vue-router版本3.5.2,引入了promise。 1.2解决方案(其实不管这个警告也可以) 第一种解决方案:给push函数传入相应的成功、失败的回调,捕获当前错误。不过这种方案治标不治本。 components/Header/index.vue文件 this.$router.push( { name: "search", params: { keyword: this.keyword }, query: { k: this.keyword.toUpperCase() }, }, () => {}, () => {} ); 第二种解决方案:治标治本。 router/index.js文件 //先把VueRouter原型对象的push方法,先保存一份 let originPush = VueRouter.prototype.push let originReplace = VueRouter.prototype.replace //重写push和replace方法 //第一个参数:告诉原来的push方法,你往哪跳转(传递哪些参数) //第二个参数是成功的回调,第三个是失败的回调 VueRouter.prototype.push = function (location, resolve, reject) { //这里面的this还是VueRouter的实例 if (resolve && reject) { // call与apply // 相同点:都可以调用一次函数,都可以篡改函数的上下文一次 // 不同点:call传递参数用逗号隔开,apply方法执行,传递数组。 originPush.call(this, location, resolve, reject) } else { originPush.call(this, location, () => { }, () => { }) } } //同样的重写replace方法 VueRouter.prototype.replace = function (location, resolve, reject) { if (resolve && reject) { originReplace.call(this, location, resolve, reject) } else { originReplace.call(this, location, () => { }, () => { }) } }
2.2Home模块组件
把Home模块拆分为三级联动、轮播图与快报、猜你喜欢、商品展示等组件。
2.2.1三级联动组件的完成
// main.js文件 // 注册全局组件 // 三级联动组件--全局组件 import TypeNav from '@/pages/Home/TypeNav' // 第一个参数:全局组件的名字,第二个参数:哪个组件 Vue.component(TypeNav.name, TypeNav) new Vue({ render: h => h(App), router, //注册全局组件 TypeNav, }).$mount('#app') // 注意:注册为全局组件之后,在使用该组件时不用再二次注册。
2.2.2其余静态组件完成
HTML + CSS +图片资源 => 放入相应的位置即可。
2.3测试接口
apifox软件
下载地址是https://apifox.com/#pricing
,直接点击免费下载即可。在apifox软件上测试,老师使用的那个软件不是很好用。在get栏中输入如下网址: http://gmall-h5-api.atguigu.cn/api/product/getBaseCategoryList 出现200即请求成功。 说明: http://gmall-h5-api.atguigu.cn(这是服务器) /api/product/getBaseCategoryList(这是接口)
2.4axios二次封装
向服务器发请求的方式有很多:XMLHttpRequest原生的构造函数、fecth、JQ、axios。 1.问:为什么需要二次封装axios? 答:为了请求拦截器和响应拦截器。请求拦截器可以在发送请求之前处理一些业务,响应拦截器可以在服务器返回数据后处理一些业务。 2.在项目中经常在src/api文件夹下放【axios】 接口中路径都带有/api,为避免重复书写,在axios中配置baseURL:"/api"。 3.如果不了解axios的基础知识,可以参考git|NPM中关于axios的文档。 下方为axios二次封装配置文件。
// src/api文件夹下的request.js文件 //对axios进行二次封装 import axios from 'axios' //1.利用axios对象的方法create,去创建一个axios实例 //2.request就是axios,只是就行了一些配置 const requests = axios.create({ //配置对象 //基础路径,发请求的时候,路径中会出现api baseURL: '/api', // 请求超时的时间为5秒,超出5s停止请求 timeout: 5000 }) //请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些处理 requests.interceptors.request.use((config) => { //config:配置对象,对象里面有一个属性很重要,headers请求头 return config; }) //响应拦截器 requests.interceptors.response.use((res) => { //响应成功的回调函数:服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情 return res.data }, (error) => { //响应失败的回调函数 return Promise.reject(new Error(error)) }) //对外暴露 export default requests
2.5接口统一管理
项目很小:完全可以在组件的生命周期函数中发请求。
项目较大:
axios.get('xxx')
。// src/api/index.js文件 //当前模块将所有的API进行统一管理 import requests from "@/api/request"; // 三级联动接口 /api/product/getBaseCategoryList get请求 无参数 // axios发请求返回结果是promise对象 // 下面是axios发送对象请求的方式(三级联动发送数据请求) export const reqCategoryList = () => requests({ url: '/product/getBaseCategoryList', method: 'get' })
// vue.config.js文件 const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, lintOnSave: false, devServer: { //通过代理服务器解决跨域问题。 proxy: { 'api': { target: 'http://gmall-h5-api.atguigu.cn' } } } })
//在mian.js文件中进行测试 //测试发送请求 import { reqCategoryList } from './api' //注意看看使用什么暴露,对应使用什么引入 reqCategoryList() //会发现上面报404错误----跨域了----需要去配置代理服务器
2.6nprogress进度条的使用
安装nprogress插件:在vs终端输入
npm i nprogress
// src/api文件夹下的request.js文件 //对axios进行二次封装 import axios from 'axios' // 引入进度条插件 import nprogress from 'nprogress' // start进度条开始 done进度条结束 // 引入进度条样式 import "nprogress/nprogress.css" //1.利用axios对象的方法create,去创建一个axios实例 //2.request就是axios,只是就行了一些配置 const requests = axios.create({ //配置对象 //基础路径,发请求的时候,路径中会出现api baseURL: '/api', // 请求超时的时间为5秒,超出5s停止请求 timeout: 5000 }) //请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些处理 requests.interceptors.request.use((config) => { //config:配置对象,对象里面有一个属性很重要,headers请求头 nprogress.start() return config; }) //响应拦截器 requests.interceptors.response.use((res) => { //响应成功的回调函数:服务器响应数据回来以后,响应拦截器可以检测到,可以做一些事情 nprogress.done() return res.data }, (error) => { //响应失败的回调函数 return Promise.reject(new Error(error)) }) //对外暴露 export default requests
2.7vuex状态管理库
安装vuex:在vs终端输入
npm i vuex@3.6.2
vuex是官方提供的一个插件:状态管理库,集中管理项目中组件共有的数据,达到共享资源的目的。(简单理解就是它相当于一个仓库) vuex的核心:state、 mutations、 actions、getters、modules 注意: 不是所有项目都需要vuex,小项目不需要,大项目需要。
建立store文件夹,在该文件夹下建立总的index.js文件,再在该文件夹下建立Home和Search两个子文件夹,在两个子文件夹下再分别建立index.js文件。
// main.js文件 import Vue from 'vue' import App from './App.vue' // 三级联动组件--全局组件 import TypeNav from '@/pages/Home/TypeNav' // 第一个参数:全局组件的名字,第二个参数:哪个组件 Vue.component(TypeNav.name, TypeNav) // 引入路由 import router from '@/router' // 引入仓库 import store from '@/store' Vue.config.productionTip = false new Vue({ render: h => h(App), // 注册路由:组件都会拥有$route,$router属性 router, // 注册仓库:组件实例对象身上会多出一个$store属性 store, }).$mount('#app')
// store/index.js文件 import Vue from 'vue' import Vuex from 'vuex' //使用插件 Vue.use(Vuex) //引入小仓库 import home from './home' import search from './search' /* //state:仓库存储数据的地方 const state = {} //actions:响应组件中用户的需求,可以书写业务逻辑,也可以处理异步 const actions = {} //mutations:处理state的唯一手段 const mutations = {} //getters:相当于计算属性,简化仓库数据,让组件获取仓库中的数据更加方便 const getters = {} */ // 对外暴露Store的一个实例对象 export default new Vuex.Store({ /* state, actions, mutations, getters, */ // 注册小仓库 实现vuex仓库的模块式开发 modules: { home, search } })
// store/home/index.js // home小仓库 const state = {} const mutations = {} const actions = {} const getters = {} export default { state, mutations, actions, getters }
// store/search/index.js文件 //search小仓库 const state = {} const mutations = {} const actions = {} const getters = {} export default { state, mutations, actions, getters }
2.8动态展示三级联动数据
这里把之前做的全局组件内容放到了components文件中(所有的全局组件都要放到这个文件中)。
// main.js文件 // 三级联动组件--全局组件 import TypeNav from '@/components/TypeNav'
注:采用命名空间的写法不会报错。
// store/home/index.js // home模块的小仓库 import { reqCategoryList } from "@/api" const home = { namespaced: true, // 开启命名空间 state: { categoryList: [] }, mutations: { CATEGORYLIST(state, categoryList) { state.categoryList = categoryList } }, actions: { // 通过api里面的接口函数调用,向服务器发送请求,获取服务器的数据 async categoryList({ commit }) { let result = await reqCategoryList() if (result.code == 200) { commit("CATEGORYLIST", result.data) } } }, getters: {} } export default home
<!-- components/TypeNav/index.js文件 --> <template> ... <div class="item" v-for="c1 in categoryList.slice(0, 15)" :key="c1.categoryId" > <h3> <a href="">{{ c1.categoryName }}</a> </h3> <div class="item-list clearfix"> <div class="subitem" v-for="c2 in c1.categoryChild" :key="c2.categoryId" > <dl class="fore"> <dt> <a href="">{{ c2.categoryName }}</a> </dt> <dd> <em v-for="c3 in c2.categoryChild" :key="c3.categoryId"> <a href="">{{ c3.categoryName }}</a> </em> </dd> </dl> </div> </div> </div> ... </template> <script> import { mapState } from "vuex"; export default { name: "TypeNav", // 组件挂载完毕:可向服务器发送请求 mounted() { // 通知vuex发请求,获取数据,存储于仓库中 this.$store.dispatch("home/categoryList"); }, computed: { ...mapState("home", ["categoryList"]), }, }; </script>
3.Day03
3.1节流与防抖
节流:在规定的间隔事件范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发。【可以给浏览器充裕的时间解析代码】 防抖:前面的所有触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速触发,只会执行一次。 lodash插件:里面封装函数的防抖与节流的业务【闭包+延迟期】 会引入包的同时还要会手写
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- 引入lodash --> <script src="lodash.js"></script> </head> <body> <div> 输入内容:<input type="text"> </div> <script> let input = document.querySelector('input') // 文本发生变化立即执行 input.oninput = _.debounce(function () { console.log('@') }, 1000) // lodash插件:里面封装函数的防抖与节流的业务【闭包+延迟期】 </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="lodash.js"></script> </head> <body> <div> <h3>计时器<span>0</span></h3> <button>点击加一</button> </div> <script> let span = document.querySelector('span') let button = document.querySelector('button') let count = 0 button.onclick = _.throttle(function () { count++ span.innerHTML = count console.log('@') }, 2000) </script> </body> </html>
3.2三级联动的节流
<!-- components/TypeNav/index.js文件 --> // 对lodash按需引入 默认暴露不用加大括号 // 使用时不要写箭头函数【this指向问题】 // 这里由于我之前运用的是css样式所以没有使用 // import throttle from "lodash/throttle";
3.3三级联动组件的路由跳转与参数传递
三级联动用户可以点击:一级分类、二级分类、三级分类。 点击的时候Home模块跳转到Search模块,以及会把用户选中的产品(产品名字,产品的ID)在路由跳转的时候,进行传递。 路由跳转的方式: 声明式导航router-link 可以实现路由跳转与传递参数,但是需要注意,会出现卡顿现象。 router-link:是一个组件,当服务器的数据返回之后,循环出很多router-link组件(创建组件实例),需要大量内存,因此卡顿。 编程式导航push|replace 单纯的运用编程式导航,需要逐个添加click事件,导致事件处理函数还是很多。 最好的路由跳转方式是编程式导航+事件委派,只需给最外层添加click事件。 但事件委派存在着两个问题: 问题1:如何知道点击的一定是a标签? 问题2:如何知道点击的a标签属于哪级【一共三级】? 答:利用自定义属性解决上述两个问题。
4.Day04
4.1TypeNav菜单过渡动画效果
过渡动画:前提组件或者元素务必要有v-if或者v-show指令才可以进行过渡动画。
4.2三级列表优化
在App根组件中发送请求【根组件mounted】执行一次。
4.3mockjs模拟数据
安装mockjs:
npm i mockjs
。作用:生成随机数据,拦截ajax请求。
特点:前端mock数据不会和你的服务器进行任何通信。
4.4Banner轮播图
第一种解决方法是添加延时器。
setTimeout(() => { var mySwiper = new Swiper(".swiper-container", { slidesPerView: 1, spaceBetween: 30, loop: true, pagination: { el: ".swiper-pagination", clickable: true, }, navigation: { nextEl: ".swiper-button-next", prevEl: ".swiper-button-prev", }, }); }, 500);
第二种解决方案是使用swiper。
第一步:引包(引入相应的js文件与css文件) 第二步:完善页面中的结构(必须要有) 第三步:new Swiper实例【轮播图添加动态效果】
4.6总结
5.Day05
6.Day06
设计组件通信
7.Day07
8.Day08
1)分页器业务
前端三大件:轮播图、分页、日历。这属于前端开发常见三种业务1.1:为什么很多项目中都采用分页功能?
比如电商平台:搜索一个奶粉,奶粉的产品有10000+,一次渲染10000+条数据,可能慢。
数据多的时候,可以选择分页,比如每一次只是展示101.2拆分分页组件(静态组件),注册为全局组件,因为其他模块也在使用分页功能。
2)分页器封装业务分析
封装分页器组件的时候:需要知道哪些条件?
假如你知道条件1、条件2:知道一共多少页 100/3
1:分页器组件需要知道我一共展示多少条数据 ----total【100条数据】2:每一个需要展示几条数据------pageSize【每一页3条数据】
3:需要知道当前在第几页-------pageNo[当前在第几页]
4:需要知道连续页码数【起始数字、结束数字:连续页码数市场当中一般5、7、9】奇数,对称好看 continues
已经条件: total=【99】 pageSize =【3】 pageNo=6 continues 5
4 5 6 7 8
已经条件: total=【99】 pageSize =【3】 pageNo= 1 continues 5
错误:-1 0 1 2 3
正确: 1 2 3 4 5已经条件: total=【99】 pageSize =【3】 pageNo= 2 continues 5
错误: 0 1 2 3 4
正确:1 2 3 4 5已经条件: total=【99】 pageSize =【3】 pageNo= 33 continues 5
错误: 31 32 33 34 35
正确:29 30 31 32 33已经条件: total=【99】 pageSize =【3】 pageNo= 32 continues 5
错误:30 31 32 33 34
正确: 29 30 31 32 333)分页器封装
3.1进行单元测试连续页码5: 8 [6,7,8,9,10]
连续页码7: 8 [5,6,7,8,9,10,11]连续页码5: 8 [6,7,8,9,10]
连续页码7: 8 [5,6,7,8,9,10,11]//正常情况:再回来因该还是第一页【遇见脑袋xxxx产品可能有这种操作】
总结:
对于一个分页器:
1.需要知道数据总条数
2.每一个需要展示数据条数
3.知道当前是第几页
4.连续页码数字
5.自定义事件【子给父通信的】4)数据解释
售卖产品属性的展示与选择,采用排他操作,在工作中经常使用。
{ attr:'颜色', attrValue:['红色','黑色','白色'] }
5)push与replace区别?
编程式导航:push 与 replace
能不能记录历史记录:push(能记住历史记录) replace(不能记住历史记录)
目前项目当中:进行路由跳转(编程式导航)基础都是push
push与replace是有区别的6)项目当中控制台
vue-warn:对于你的代码提出一个警告;对于程序没有任何影响,俗称假报错。
9.Day09重要
10.Day10重要
token面试题:项目当中token过期、失效如何处理?
答:清除本地token(本地存储),让用户回到登录页,获取最新的token。
11.Day11
12.Day12
7)个人中心【二级路由搭建】
13.Day13
路由懒加载:
把不同路由对应的组件分成不同的代码块,当路由被访问时再加载对应的组件。
app\src\router.js文件 //注意:最上面最开始的引入要去掉 { path: "/home", component: ()=>import("@/views/Home"), meta: { show: true } },