编程式路由跳转到当前路由(参数不变),多次执行会抛出NavigationDuplicated的警告错误【不影响程序运行,但看着烦】
路由跳转两种方式:声明式导航,编程式导航
此类错误只会出现在编程式导航中,不会出现在声明式导航中,因为vue-router底层已经处理好了
此项目中vue-router版本是3.6.5版本,引入了promise
this.$router.push({name:'search',params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}})上面是编程式导航写法,其中push返回promise,相当于
function push(){ return new Promise((resolve,reject)=>{ }) }解决办法:
给push方法传递相应的成功、失败的回调函数,可以捕获到当前的错误,可以解决【只治标不治本,只能解决当前跳转错误】
this.$router.push({name:'search',params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}},()=>{},()=>{})push不是实例;this指vc,vc身上有个VueRouter的实例叫$router,这个实例的原型(也就是VurRouter)上有个push方法。所以对原型方法push进行修改,修改结果就会作用于组件实例的$router实例。【下面是解决办法:重写push|replace方法】
// 解决vue-router在3.0版本以上重复点报错问题// 先把VueRouter原型对象的push方法备份// 此时originalPush的this是windowconst originalPush = VueRouter.prototype.pushconst originalReplace = VueRouter.prototype.replace// 重写 push|replace// 参数:location表示告诉原来的push方法往哪里跳;resolve:成功的回调;reject:失败的回调// call和apply的区别// 相同点:都可以调用函数一次,篡改函数上下文一次【改变this指向】// 不同点:call传参用逗号隔开,apply传参用数组VueRouter.prototype.push = function push(location,resolve,reject) {// 如果成功和失败的回调都传了,则调用原来的push方法,即originalPush// 但是此时的originalPush的上下文this是window,而要求push方法的this指向VueRouter的实例,所以用callif(resolve && reject){originalPush.call(this, location,resolve,reject)}else{// 如果成功和失败的回调没传,则给原来的push方法添加成功和失败的回调:()=>{},()=>{},此时同样要保证this指向VueRouter的实例originalPush.call(this, location,()=>{},()=>{})}// return originalPush.call(this, location).catch(err => err)}VueRouter.prototype.replace = function replace(location,resolve,reject) {if(resolve && reject){originalReplace.call(this, location,resolve,reject)}else{originalReplace.call(this, location,()=>{},()=>{})}}三级联动组件
此组件在home、search、detail页面都被使用,所以将三级联动组件注册为全局组件
在main.js中注册
// 三级联动组件--全局组件import TypeNav from '@/pages/Home/TypeNav'// 参数:第一个:全局组件的名字;第二个:哪一个组件Vue.component(TypeNav.name,TypeNav);先在home页面使用<TypeNav></TypeNav>
拆分其他home页面组件
注意结构、样式、图片资源
测试接口
axios二次封装
为什么要二次封装?
目的是为了设置请求拦截器和响应拦截器
请求拦截器:在发请求前处理一些业务
响应拦截器:在服务器数据返回后处理一些业务
安装axios【0.24.0】我这里为1.2.0

在src下新建api文件,项目中的API文件夹通常放置关于axios请求的,在里面对axios进行二次封装// 对axios进行二次封装
// 对axios进行二次封装// 引入axiosimport axios from "axios";// 1、利用axios对象的方法create,创建一个axios实例// 2、request就是axios,只不过可以稍微配置一下const requests=axios.create({// 配置对象// 基础路径,当发请求时,路径中会自动出现/api,不用自己手动写baseURL:'/api',// 超时设置5stimeout:5000,});// 请求拦截器:在发请求前处理一些业务requests.interceptors.request.use((config)=>{// config:配置对象,里面 headers请求头 属性很重要return config;})// 响应拦截器:在服务器数据返回后处理一些业务requests.interceptors.response.use((res)=>{// 成功的回调return res.data;},(error)=>{// 失败的回调// 终结promise链return Promise.reject(new Error('faile'))})// 对外暴露export default requests;接口的统一管理
如果项目很小,只有一两个接口,完全可以在组件的生命周期函数中发送请求
如果项目较大,有一两百个接口,使用axios.get('xxx'),但如果接口要更改,则很麻烦,所以需要接口统一管理
代码写在一个文件里,通过暴露函数,让其他模块访问接口
// 统一管理API接口// 引入封装后的axios,即requestsimport requests from './request'// 三级联动的接口// 请求地址:/api/product/getBaseCategoryList GET请求,无参数// 对外暴露函数,让别的模块拿到这个函数就可以发请求了// 发请求,axios发送请求返回的结果是promise对象// 简写 分别暴露引入要用{}export const reqCatagoryList=()=> requests({url:'/product/getBaseCategoryList',method:'get'})跨域问题解决
JSONP
CROS
代理服务器【√】
配置文件中设置
devServer:{proxy:{'/api':{target:'http://gmall-h5-api.atguigu.cn',}}}nprogress进度条
安装

使用
在请求和响应拦截器里使用
引入:
// 引入nprogress进度条import nprogress from 'nprogress'// 引入进度条样式,颜色可以改(改源码)import "nprogress/nprogress.css"nprogress上的start方法:进度条开始,done方法:进度条结束
// 请求拦截器:进度条开始动nprogress.start();// 响应拦截器:进度条结束nprogress.done()Vuex状态管理库
管理组件间共用的数据
配置对象
state:仓库存储数据的地方
mutations:修改state的唯一手段
actions:处理action,可以书写自己的业务逻辑,也可以处理异步
getters:理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
modules
安装:【3版本】

使用
在src下新建store文件夹
import Vue from 'vue';import Vuex from 'vuex';// 使用VuexVue.use(Vuex)const state={};const mutations={};const actions={};const getters={};// 对外暴露Store类的一个实例// Vuex其实是一个对象,对象身上有Store方法,这个方法是个构造函数,可以初始化Vue仓库export default new Vuex.Store({// 配置对象state,mutations,actions,getters,});main.js中引入并注册store
// 引入Vuex的仓库store import store from '@/store'// 注册Vuex仓库,此时,组件实例对象身上会多一个$store属性store,vuex实现模块式开发
当项目过大,组件过多,数据过多,接口很多,可以采用模块式开发,将大仓库拆分成多个小仓库

在小仓库中获取api数据,交给组件
// home模块的小仓库// 引入reqCatagoryList的api接口函数import {reqCatagoryList} from '@/api';// 仓库存储数据的地方const state={// 起始值【起始值不能乱写,要看服务器返回的数据是什么类型】categoryList:[],};// 修改state的唯一手段const mutations={CATEGORYLIST(state,categoryList){state.categoryList=categoryList;}};// 处理action,可以书写自己的业务逻辑,也可以处理异步const actions={// 这里可以书写业务逻辑,但是不能修改state// 通过API里面的接口函数调用,向服务器发送请求,获取数据async categoryList({commit}){// 调用api接口函数,返回的是promise对象,利用async和await,获取成功的结果let result= await reqCatagoryList();if(result.code==200){commit("CATEGORYLIST",result.data)}}};// 理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便const getters={};// 对外暴露export default {state,mutations,actions,getters,}在组件中使用
引入
// 获取到仓库中的数据,引入mapState// 注意mapState和mapGetters是映射在计算属性里面的,而mapActions和mapMutations是映射在methods里面的import {mapState} from 'vuex'发送请求,接收数据
// 当组件挂载完毕,就可以向服务器发请求mounted() {// 通知Vuex发请求,获取数据,存储于仓库中this.$store.dispatch('categoryList')},computed:{...mapState({// 右侧需要的是一个函数,参数state即为大仓库中的数据// categoryList:(state)=>{// return state.home.categoryList;// },// 简写为categoryList:state=>state.home.categoryList})},利用插值语法将获取的数据写入页面
完成一级分类动态添加背景颜色
方法一:采用样式完成

方法二:采用JS完成
先设置data,currentIndex,用于存储用户鼠标移动到哪一个一级分类上面

再定义鼠标进入事件,获取索引值并更改currentIndex,根据索引添加类cur


最后定义cur类的样式

通过JS控制二三级商品分类的显示与隐藏
目前通过样式display:none|block实现


隐藏上图:hover样式后,利用JS实现

文章转载自LLL的小屋,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




