问题1:
代码:
原因分析:因为缺少mapState引入,所以报错mapState不认识,添加引入即可
import { mapState } from "vuex";
简单总结使用步骤:
详细使用步骤:
import {getCategoryList} from '@/api'
//Home模块的小仓库
//actions代表一系列动作,可以书写自己的业务逻辑,也可以处理异步
const actions = {
//getCategoryList返回的是一个Promise对象
//需要用await接受成功返回的结果,await必须要结合async一起使用(CP)
async getCategoryList(context) {
let response = await getCategoryList();
if (response.code == 200) {
context.commit("GETCATEGORYLIST", response.data)
}
}
}
//mutations代表维护,操作维护的是state中的数据,且state中数据只能在mutations中处理
const mutations = {
GETCATEGORYLIST(state, categoryList) {
state.categoryList = categoryList
}
}
//state代表仓库中的数据
const state = {
//home仓库中存储三级菜单的数据
categoryList:[]
}
//getters理解为计算属性,用于简化仓库数据,让组件获取仓库的数据更加方便
const getters = {}
//创建并暴露store
export default {
actions,
mutations,
state,
getters
}
mounted() {
//派发一个action||获取商品分类的三级列表的数据
this.$store.dispatch("getCategoryList")
}
computed:{
...mapState({categoryList:state=>state.home.categoryList})
}
问题2:为啥actions定义的getCategoryList函数要使用async+await?
答案:因为getCategoryList函数函数最后返回的是一个promise的对象,如图,而我们直接想要的是成功的回调函数,所以用async+await可直接获取到。
效果如下:
共有2种方式:
//方式1::hover
.item:hover {
background: skyblue;
}
methods: {
//用于修改组件实例身上的currentIndex的属性值
//当用户鼠标移入到h3身上的时候就会立即出发一次
changeIndex(index) {
this.currentIndex = index;
},
//当鼠标离开的时候,让商品分类列表进行隐藏
leaveIndex() {
this.currentIndex = -1;
}
}
.cur {
background: skyblue;
}
注意点1
:mouseenter:当鼠标移入元素本身(不包含元素的子元素)会触发事件,事件不会叠加。对应的移除事件是 mouseleave。
注意点2
:现在想实现个新效果,鼠标从第一项划入“全部商品分类”也不会去除背景色,具体效果如图,具体方案可采用“事件委派”指的是把事件委派给父亲元素去控制,逻辑就是把“全部商品分类”和一级菜单用一个div单独包起来,在外侧进行划出控制。
15.3控制二三级商品分类的显示与隐藏
共有2种方式:
- 方式1:通过css的:hover控制display的block|none显示与隐藏
.item-list {
display: none;
...
}
&:hover {
.item-list {
display: block;
}
}
- 方式2:通过js的方式控制display的显示与隐藏
问题:css中的&:hover,中的&啥意思?
答案:
贴个CSS代码进行讲解
.box{
&:before{
border-color: red;
}
&:after{
border-color: green;
}
}
& 表示在嵌套层次中回溯一层,即&:before相当于.box:before
15.4演示卡顿现象引入防抖与节流
正常:事件触发非常频繁,而且每一次的触发,回调函数都要去执行(如果时间很短,而回调函数内部有计算,那么很可能出现浏览器卡顿现象),正常效果如图1,错误效果如,2。
如图1
如图2
节流:在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发【给浏览器有充裕的时间解析代码】。
防抖:前面的所有的触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速的触发只会执行一次。
注意点0:
安装命令:cnpm install --save lodash
使用方式:
//引入lodash:是把lodash全部封装好的函数全都引入进来了
//按需引入:只是引入节流函数,其他的函数没有引入(模块),这样做的好处是,当你打包项目的时候体积会小一些
import throttle from "lodash/throttle";
changeIndex: throttle(function(index) {
//修改当前currentIndex索引值
//函数节流:在20MS时间之内只能执行一次
this.currentIndex = index;
}, 20),
注意点1
:可使用lodash插件:里面封装函数的防抖与节流的业务方法【闭包+延迟器】
注意点2
:防抖与节流区别是啥?
答案:“节流”是规定时间内只执行一次,而“防抖”是无论多长时间我都是最后执行一次。
注意点3
:lodash官网:https://www.lodashjs.com/
防抖:debounce(func, [wait=0], [options=])
节流:throttle(func, [wait=0], [options=])
15.5三级联动组件的路透跳转与传递参数
三级联动用户可以点击的:一级分类、二级分类、三级分类,当你点击的时候Home模块跳转到Search模块,一级会把用户选中的产品(产品名字,产品ID)在路由跳转的时候,进行传递。
路由跳转:
-
声明式导航:router-link
-
编程式导航:push|replace
问题1:选用“声明式导航”还是“编程式导航“?
答案:应该选用编程式导航。如果使用声明式导航router-link,可以实现路由的跳转与传递参数,但是需要注意,会出现卡顿现象,因为三级联动菜单是循环遍历产生的,如果循环遍历1000次那得新生成/标签,很占用内存,肯定会卡顿。
问题2:既然选择”编程式导航“,那么是/标签绑定点击事件?还是采用其他方式?
答案:不能采用a标签绑定事件方式,应该采用“父元素委托事件”方式。因为这样只需定义一次函数即可,而采用a标签我还得循环遍历定义1000次函数。
问题3:我们想要效果是点击a标签才跳转路由,如何确认a标签?
答案:给a标签绑定自定义属性,使用event.target.dataset可以获取自定义属性名称,能获取自定义属性名称的一定是我们要的a标签。
问题4:采用“父元素委托事件”方式后,会出现如图错误效果:当点击1级菜单时 -> 先跳转到搜索页 -> 又自动跳转到首页
答案:把/标签的href属性必须删掉
问题5:自定义属性名为啥叫 data-xxx,输出打印的dataset名称全是小写,但是为啥前面的data-没了?举例说明自定义属性名称叫:data-categoryName,为啥最后dataset获取的名称却是categoryname,明显前缀data-没了,而且莫名变成小写了?
答案:JS中要想使用dataset获取自定义属性,那么在HTML模板中自定义属性名必须叫“data-xxx”。
下方为别人博客摘抄:
HTML5 中添加了 data-* 的方式来自定义属性,实际上就是在自定义属性名前加上前缀data- 即可,使用这样的结构可以进行数据存放。使用data-* 可以解决自定义属性混乱无管理的现状。
一个自定义一旦加上了前缀 data- ,那么在 JS 中就可以通过 elementNodeObject.dataset拿到这个属性,显然 dataset 是 attribute 集合的一个子集。
dataset 属性的值是 DOMStringMap的一个实例,也就是一个名值对儿的映射。在这个映射中,每个 data-name 形式的属性都会有一个对应的属性,只不过没有 data- 前缀。
完整代码 src/commponents/TypeNav/index.vue
------------------------------------------------------------------------------------------------------
//进行路由跳转的回调函数
goSearch(event) {
//最好的解决方案:编程式导航+事件委派
//存在一些问题:事件委派,是把全部的子节点【h3、dt、dl、em】的事件委派给父亲节点
//问题1:点击a标签的时候,才会进行路由跳转【怎么能确认点击的一定是a标签?】
//答案:给a标签绑定自定义data-categoryName属性,只要能获取到自定义属性就代表是a标签
//event.target:获取到的是触发事件的元素(div、h3、a、em、dt、dl)
let element = event.target;
//节点有一个属性dataset,可以过去节点的自定义属性与属性值
let {categoryname, category1id, category2id, category3id} = element.dataset;
//如果标签身上带有categoryname一定是a标签,且当前这个if语句:一定是a标签才会进入
if (categoryname) {
//准备路由跳转的参数对象
let location = {name: 'search'}
let query = {categoryName: categoryname}
//一级目录
if(category1id) {
query.category1Id = category1id
//二级目录
} else if (category2id) {
query.category2Id = category2id
//三级目录
} else {
query.category3Id = category3id
}
//动态给location配置对象添加query属性
location.query = query;
//路由跳转
this.$router.push(location);
}
}
问题6:Vue项目启动默认打开http://0.0.0.0:8080,浏览器显示无法访问,而输入http://localhost:8080就能展示页面
解决方案:在vue.config.js文件中新增一行:host: 'localhost’即可。
module.exports = {
productionSourceMap:false,
// 关闭ESLINT校验工具
lintOnSave: false,
devServer: {
//代理服务器解决跨域
proxy: {
"/api": {
target: "http://39.98.123.211:8510"
},
},
//解决默认打开浏览器,会出现0.0.0.0:8080,浏览器显示无法访问
host: 'localhost'
}
};
本人其他相关文章链接
1.vue尚品汇商城项目-day02【9.Home组件拆分+10.postman测试接口】
2.vue尚品汇商城项目-day02【vue插件-13.nprogress进度条的使用】
3.vue尚品汇商城项目-day02【11.对axios二次封装+12.接口统一管理】
4.vue尚品汇商城项目-day02【14.vuex状态管理库】
5.vue尚品汇商城项目-day02【15.动态展示三级菜单联动】