Day2
1、编程式导航路由跳转到当前路由(参数不变), 多次执行会抛出NavigationDuplicated的警告错误?
注意:编程式导航(push|replace)才会有这种情况的异常,声明式导航是没有这种问题,因为声明式导航内部已经解决这种问题。
这种异常,对于程序没有任何影响的。
为什么会出现这种现象:
由于vue-router最新版本3.5.3,引入了promise,当传递参数多次且重复,会抛出异常,因此出现上面现象,
第一种解决方案:是给push函数,传入相应的成功的回调与失败的回调,可以捕获到
第一种解决方案可以暂时解决当前问题,但是以后再用push|replace还是会出现类似现象,因此我们需要从‘根’治病;
this:当前组建的实例
this.$router属性:当前这个属性,属性值VueRouter类的实例,当在入口文件注册路由的时候,给组件实例添加$router|$route属性
push:VueRouter类的一个实例
this.$router.push({name:"search",params:{keyword:this.keyword},query:{k:this.keyword.toUpperCase()}},()=>{},()=>{})
在配置路由的地方
//先把VueRouter原型对象的push,先保存一份
let originPush = VueRouter.prototype.push;
//重写push|replace
VueRouter.prototype.push = function(location,resolve,reject){
//第一个参数:告诉原来的push方法,你往哪里跳转(传递那些参数)
//第二个参数:成功的回调
//第三个参数,失败的回调
if(resolve && reject){
//call|apply区别
//相同点:都可以调用函数一次,都可以篡改函数的上下文一次
//不同点:call与apply传递参数:call传递参数用逗号隔开,apply方法执行,传递数组。
originPush.call(this,location,resolve,reject);
}else{
originPush.call(this,location,()=>,()=>);
}
}
2、Home模块组件拆分
--先把静态页面完成
--拆分出静态组件
--获取服务器的数据进行展示
--动态业务
3、三级联动组件完成
--由于三级联动,在Home、Search、Detail出现,把三级联动注册成一个全局组件
好处:只需要注册一次,就可以在项目的任何地方使用。
3.1 开始工作
1、在pages/Home文件夹中创建TypeNav文件夹,在其中创建index.vue文件。
......
2、在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'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
//注册路由信息:这里书写router的时候,组件身上拥有$route,$router属性
router
}).$mount('#app')
3、在Home的index.vue中使用
4、完成其余静态组件
HTML+CSS+图片资源
ListContainer
在Home文件夹中创建ListContainer文件夹,再创建index.vue
尚品汇快报
更多 >
[特惠]备战开学季 全民半价购数码
[公告]备战开学季 全民半价购数码
[特惠]备战开学季 全民半价购数码
[公告]备战开学季 全民半价购数码
[特惠]备战开学季 全民半价购数码
话费
机票
电影票
游戏
彩票
加油站
酒店
火车票
众筹
理财
礼品卡
白条

在ListContainer中创建images文件夹放置相关图片资源
在Home文件夹下的index.vue引入并且注册组件,之后引用组件
Recommend
在Home文件夹中创建Recommend文件夹,再创建index.vue和images文件夹放置图片资源
之后在Home文件夹下的index.vue中进行组件的注册,引用
引入
import Recommend from '@/pages/Home/Recommend'
注册
export default {
name: "Home",
components: {
ListContainer,
Recommend
}
}
引用
Rank
Like\Floor\Brand
4、postman测试接口
开发服务器接口
http://gmall-h5-api.atguigu.cn
首页三级分类:
请求地址
/api/product/getBaseCategoryList
在postman中新建一个new request,测试是否能够成功
"code": 200,成功
http://gmall-h5-api.atguigu.cn/api/product/getBaseCategoryList
5、axios二次封装
5.1 为什么需要进行二次封装axios
请求拦截器:可以在发请求之前处理一些事务
响应拦截器:当服务器数据返回以后,可以处理一些事情
5.2 安装axios ----可以参考git|NPM关于axios文档
D:\项目\project-hph\app>cnpm install --save axios
在src文件夹中创建一个api文件夹【axios】,创建一个request.js文件
接口当中:路径都带有/api
baseURL:"/api"
//对axios进行二次封装,主要是用到它的请求和响应拦截器
//引入axios
import axios from "axios";
//1:利用axios对象的方法,去创建一个axios实例
//2:request就是axios,只不过稍微配置一下
const requests = axios.create({
//配置对象
// 基础路径,发请求的时候,路径当中会出现/api
baseURL:"/api",
//请求超时的时间,五秒
timeout:5000,
});
//请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config)=>{
// config:配置对象,对象里面有一个属性很重要:header请求头
return config
})
//响应拦截器
requests.interceptors.response.use((res)=>{
//成功回调的函数:服务器相应数据回来以后,响应拦截器可以检测到,可以做一些事情
return res.data;
},(error)=>{
// 响应失败的回调函数
return Promise.reject(new Error('fail'))
});
//对外暴露
export default axios;
6、API接口统一管理
项目很小:完全可以在组建的生命周期函数中发送请求
大:axios.get('xxx')
在api文件夹中创建index.js文件
//当前这个模块:对API进行统一管理
import requests from './request';
//三级联动的接口:/api/product/getBaseCategoryList GET请求 参数无
//对外暴露一个函数
export const reqCategoryList = ()=>
//发请求:axios发请求返回结果Promise对象
requests({
url:'/product/getBaseCategoryList' ,method:'get'
});
在main.js中进行测试
//测试
import {reqCategoryList} from '@/api';
reqCategoryList();
6.1 跨域问题
什么是跨域:协议、域名、端口号不同请求,称之为跨域
http://localhost:8080/#/home前端项目本地服务器
http://gmall-h5-api.atguigu.cn后台服务器
jsonp、cros、代理
在vue.config.js中配置代理
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave:false,/关闭校验功能/
devServer: {
host: 'localhost', port: 8080,
proxy:{
'/api':{
target:'http://gmall-h5-api.atguigu.cn',
// pathRewrite:{'^/api':''}
}
}
}
})
重启服务器
7、nprogress进度条的使用
在控制栏中安装
D:\项目\project-hph\app>cnpm install --save nprogress
nprogress方法
NProgress.start() // 进度条开始
NProgress.set() // 将进度设置到具体的百分比位置,取值范围是0到1.0
NProgress.inc() // 如果少量增加进度,进度将永远不会得到100%
NProgress.done() // 进度条结束消失
NProgress.configure() // 进度条参数配置
===================================================================================================
可以通过调用 .set(n)来设置进度,n是0-1的数字。
NProgress.set(0.0); // Sorta same as .start()
NProgress.set(0.4);
NProgress.set(1.0); // Sorta same as .done()
可以使用inc()随机增长进度条,注意,这个方法永远不会让进度条达到100%。
NProgress.inc();
NProgress.configure({ showSpinner: false }) //禁用进度环
NProgress.configure({ trickle : false }) //关闭进度条步进
NProgress.configure({ trickleRate : 10}) //每次步进增长多少
NProgress.configure({ trickleSpeed : 200}) //每次步进间隔,单位毫秒ms
NProgress.configure({ easing: 'linear'}) //动画方向
NProgress.configure({ speed : 10}) //动画速度,单位毫秒ms
NProgress.configure({ minimum : 0.08}) //最小百分比
进度条在request.js中使用
//对axios进行二次封装,主要是用到它的请求和响应拦截器
//引入axios
import axios from "axios";
//引入进度条
import nprogress from 'nprogress';
//引入进度条样式
import "_nprogress@0.2.0@nprogress/nprogress.css"
//start:进度条开始 done:进度条结束
//1:利用axios对象的方法,去创建一个axios实例
//2:request就是axios,只不过稍微配置一下
const requests = axios.create({
//配置对象
// 基础路径,发请求的时候,路径当中会出现/api
baseURL:"/api",
//请求超时的时间,五秒
timeout:5000,
});
//请求拦截器:在发请求之前,请求拦截器可以检测到,可以在请求发出去之前做一些事情
requests.interceptors.request.use((config)=>{
// config:配置对象,对象里面有一个属性很重要
// 进度条开始动
nprogress.start();
return config;
})
//响应拦截器
requests.interceptors.response.use((res)=>{
//成功回调的函数:服务器相应数据回来以后,响应拦截器可以检测到,可以做一些事情
// 进度条结束
nprogress.done();
return res.data;
},(error)=>{
// 响应失败的回调函数
return Promise.reject(new Error('fail'))
});
//对外暴露
export default requests;
8、vuex状态管理库
8.1 vuex
vuex是官方提供的一个插件,状态管理库,集中式管理项目中组件公用的数据。
项目大,组件很多,数据很多,数据维护麻烦,需要使用
vue2项目需要用vuex 3版本
D:\项目\project-hph\app>cnpm install --save vuex 安装最新版本的
D:\项目\project-hph\app>npm install vuex@3.6.2 指定版本安装
8.2 vuex的基本使用
在src文件夹下,创建store文件夹,在其中创建index.js文件
import Vue from 'vue';
import Vuex from 'vuex';
//需要使用vuex一次
Vue.use(Vuex);
// state:仓库存储数据的地方
const state = {};
// mutations:修改state的唯一手段
const mutations = {};
// actions:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {};
// getters:理解为计算属性,用于简化仓库数据,让组件获取仓库更加方便
const getters = {};
//对外暴露Store类的一个实例
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
在mainjs中引入仓库
import Vue from 'vue'
import App from './App.vue'
//三级联动组件---全局组件
import TypeNav from '@/pages/Home/TypeNav'
//第一个参数:全局组件的名字,第二个参数:哪一个组件
Vue.component(TypeNav.name,TypeNav);
//引入路由
import router from '@/router'
Vue.config.productionTip = false
//引入仓库
import store from '@/store';
//测试
import {reqCategoryList} from '@/api';
reqCategoryList();
new Vue({
render: h => h(App),
//注册路由信息:这里书写router的时候,组件身上拥有$route,$router属性
router,
// 注册仓库:
store
}).$mount('#app')
8.3 使用:实现计数器的使用
在Home文件夹下的index.vue中先将所有引用的组件注释了
仓库的数据{{count}}
去仓库store中存放数据的地方
import Vue from 'vue';
import Vuex from 'vuex';
//需要使用vuex一次
Vue.use(Vuex);
// state:仓库存储数据的地方
const state = {
count:1
};
// mutations:修改state的唯一手段
const mutations = {
};
// actions:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {
};
// getters:理解为计算属性,用于简化仓库数据,让组件获取仓库更加方便
const getters = {
};
//对外暴露Store类的一个实例
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
刚在index.vue中写的组件想要获取,仓库的数据。需要用到咱们的辅助函数
<button @click="add">点击我加1
仓库的数据{{count}}
给button绑定单击事件
<button @click="add">点击我加1
绑定事件后,需在methods中要写相关的方法,和派发action
<button @click="add">点击我加1
仓库的数据{{count}}
派发ation后需要回到store的index.js中的actions中
import Vuex from 'vuex';
//需要使用vuex一次
Vue.use(Vuex);
// state:仓库存储数据的地方
const state = {
count:1
};
// mutations:修改state的唯一手段
const mutations = {
ADD(state){
state.count++;
}
};
// actions:处理action,可以书写自己的业务逻辑,也可以处理异步
const actions = {
// 这里可以书写业务逻辑,但是不能修改state
add({commit}){
commit("ADD");
}
};
// getters:理解为计算属性,用于简化仓库数据,让组件获取仓库更加方便
const getters = {
};
//对外暴露Store类的一个实例
export default new Vuex.Store({
state,
mutations,
actions,
getters
})
8.4 vuex模块式开发
在store文件夹下创建,所有组建的对应名字的小仓库和index.js文件
之后需要将俩个小仓库合并到大仓库中
在大仓库中引入两个小仓库
import Vue from 'vue';
import Vuex from 'vuex';
//需要使用vuex一次
Vue.use(Vuex);
//引入小仓库
import home from './home';
import search from './search';
//对外暴露Store类的一个实例
export default new Vuex.Store({
// 实现vuex仓库模块化开发存储数据
modules:{
home,
search
}
})
9、完成TypeNav三级联动展示数据业务
将TypeNav文件夹放置到components文件夹中,别忘了将main.js路径修改一下
在home的index.js中
import {reqCategoryList} from '@/api';
//home模块的小仓库
const state = {
//state中数据默认初始值要与服务器中的一致。服务器返回对象,服务器返回数组。(根本接口的返回值进行初始化)
categoryList:[],
};
const mutations = {
CATEGORYLIST(state,categoryList){
state.categoryList = categoryList;
}
};
const actions = {
//通过api里面的接口函数调用,向服务器发请求,获取服务器的数据
async categoryList({commit}){
let result = await reqCategoryList();
console.log(result);
if(result.code==200){
commit("CATEGORYLIST",result.data);
}
}
};
const getters = {
};
export default {
state,
mutations,
actions,
getters
}
{{commit}}是结构赋值的结果
dispatch是异步操作,用action接收,actions出来的是promise,需要用async 和 await进行异步操作
之后在TypeNavd的index.vue中iu修改相关数据
注意分析结构
[
{
id:1,
name:'电子书',
child:[
{
id:2,
name:"喜羊羊",
child:[
{
id:3,
name:"灰太狼"
}
]
}
]
}
]
10、完成一级分类动态添加背景颜色
10.1 第一种解决方案:采用样式解决
.item:hover{
background: deepskyblue;
}
10.2 第二种解决方案:通过js完成
1、鼠标移上去时背景颜色会变蓝
<h3 @mouseenter="changeIndex(index)">
{{c1.categoryName}}--{{index}}
在.all-sort-list2中书写样式代码
.cur{
background: lightskyblue;
}
2、鼠标移动走之后颜色会变回去
<h3 @mouseenter="changeIndex(index)" @mouseleave="leaveIndex">
methods:{
//鼠标进入修改响应式数据currentIndex属性 (index)接受index的值
changeIndex(index){
// index:鼠标移动到某一个一级分类上时,一级分类元素的索引值
this.currentIndex = index;
},
// 一级分类鼠标移除的事件回调
leaveIndex(){
this.currentIndex = -1
}
},
事件委派
此时当鼠标完全离开一级菜单和标题时,背景颜色才会变成白色。
<div @mouseleave="leaveIndex">
全部商品分类
...........
11、通过JS二三级商品分类的显示与隐藏
最开始的时候,是通过CSS样式display: block|none显示与隐藏二三级商品分类
12、演示卡顿现象:节流和防抖
正常:事件触发非常频繁,而且每一次触发,回调函数都要去执行(如果时间很短,而回调函数内部有计算,那么可能出现浏览器卡顿)
节流:在规定的间隔范围内不会触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发。技能有cd,在规定的时间里点几次。
我是计数器
0
防抖:前面的所有的触发都被取消,最后一次执行在规定的事件之后才会触发,也就说如果连续快速的触发,只会执行一次。回城你扣b使劲扣,也就是触发一次回城
鼠标移动速度过快,然后菜单的index只能显示几个
13、完成三级联动节流的操作
14、三级联动组件的路由与传递参数
三级联动用户可以点击的:一级分类,二级分类,三级分类,当你点击的时候
Home模块跳转到Search模块。以及会把用户选中的产品(产品的名字和ID)在路由跳转的时候,进行传递。
路由跳转:
声明式导航:router-link 耗内存,卡顿
<router-link to
编程式导航:push|replace
<a @click="goSearch">
goSearch(){
this.$router.push('/search')
}
编程式导航加上事件的委派
15、完成三级联动的路由跳转和传递参数
<div @mouseleave="leaveIndex">
全部商品分类
<div class="all-sort-list2" @click="goSearch">





浙公网安备 33010602011771号