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中先将所有引用的组件注释了

去仓库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绑定单击事件


<button @click="add">点击我加1

绑定事件后,需在methods中要写相关的方法,和派发action


派发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、完成三级联动的路由跳转和传递参数

posted @ 2022-09-27 16:35  孤舟蓑衣客  阅读(39)  评论(0)    收藏  举报