一、问题说明
如图所示,在项目中三级联动,要实现路由跳转跳转,有两种方法:
- 编程式导航: this.$router.push( ) 、this.$router.replace( ),通过触发点击事件实现路由跳转,有多少个 a 标签,就会有多少个触发函数。不会造成卡顿,但是也对性能有一定的影响。
- 声明式导航:router-link 标签实现,可以实现路由的跳转以及参数的传递,但是由于 router-link 是一个组件,相当于 VueComponent类的实例对象,当服务器的数据返回之后,一瞬间出现了很多个 router-link 组件,很消耗内存,会出现卡顿的现象。
只使用编程式导航或者声明式导航,都会对性能产生影响。
二、解决方法
1.可以使用编程式导航配合事件委派,实现三级路由跳转的效果。
事件委派把子节点的事件都委托给父节点,只需要调用一次回调函数,即可实现效果。
2.使用事件委派(三级联动)遇到的问题:
(1)把事件委派给父节点之后,父节点下的全部子节点都可以触发事件,怎么判断触发事件的节点是否为 a 标签呢?
(2)如果确定了是 a 标签触发事件,如何确定是一级、二级、三级中的哪一级触发了事件呢?同时,要如何在路由跳转的同时传递参数呢?
3.解决方法
对于第一个问题:给每一级的 a 标签都添加自定义属性 data-categoryName 绑定该商品的名称(其余标签无该属性)
对于第二个问题:给一、二、三级的 a标签分别添加data-category1Id 、data-category2Id 、data-category3Id 自定义属性,绑定该商品的ID,以此区分。同时,在函数中传入参数event ,获取当前的点击事件,通过event.target属性获取当前点击节点。节点有一个dataset 属性,可以获取节点的自定义属性 (event.target.dataset) 。给标签添加自定义属性的时候,把路由跳转时需要传递的参数categoryName和categoryId分别绑定给自定义属性,触发点击事件时,通过event.target.dataset配合解构直接获取,并使用 this.$router.push( )直接传递即可。
注意:event是系统属性,所以我们只需要在函数定义的时候作为参数传入,在函数使用的时候不需要传入该参数。
4.完整代码
<!-- 三级联动 -->
<div class="sort">
<!-- 利用事件委派结合编程式导航实现路由的跳转与传递参数 -->
<div class="all-sort-list2" @click="goSearch">
<!-- 一级分类 -->
<div class="item" v-for="(c1, index) in categoryList.slice(0, 16)" :key="c1.categoryId"
:class="{cur: currentIndex===index}">
<h3 @mouseenter="changeIndex(index)">
<a :data-categoryName="c1.categoryName" :data-category1Id="c1.categoryId">{{c1.categoryName}}</a>
</h3>
<!-- 二级、三级分类 -->
<div class="item-list clearfix" :style="{display: currentIndex===index? 'block':'none'}">
<div class="subitem" v-for="(c2, index) in c1.categoryChild" :key="c2.categoryId">
<dl class="fore">
<dt>
<a :data-categoryName="c2.categoryName" :data-category2Id="c2.categoryId">{{c2.categoryName}}</a>
</dt>
<dd>
<em v-for="(c3, index) in c2.categoryChild" :key="c3.categoryId">
<a :data-categoryName="c3.categoryName"
:data-category3Id="c3.categoryId">{{c3.categoryName}}</a>
</em>
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
触发点击事件的 goSearch 函数:
// 进行路由跳转的方法
goSearch(event) {
// 最好的解决方案就是利用 编程式导航 + 事件委派
// 存在一些问题:事件委派,是把全部的子节点【h3 dt dl em】的事件委派给父节点
// 点击a标签才会进行路由的跳转【1:判断点击的是否是a标签 2:如何获取参数【1、2、3级分类的产品的名字、ID】(如何确定点击的是 1级、2级还是3级分类的a标签)
// 第一个问题:把子节点当中a标签,加上自定义属性 data-categoryName,其余子节点没有
let element = event.target;
// 获取到当前触发事件的节点,有可能是各种元素,需要带有 data-categoryname 属性的节点【一定是a标签】
// 节点有一个属性,dataset 属性,可以获取节点的自定义属性 event.target.dataset , event.target.dataset.categoryName
let { categoryname, category1id, category2id, category3id } = element.dataset;
// 如果标签身上有 categoryname 属性,一定是 a 标签
if (categoryname) {
// 当点击标签,参数包括 name id,整理路由跳转的参数
let location = { name: 'search' };
let query = { categoryName: categoryname };
// 一级分类、二级分类、三级分类的 a 标签,再分别添加属性 data-category1Id data-category2Id data-category3Id 以此区分一、二、三级分类
if (category1id) {
query.category1Id = category1id;
} else if (category2id) {
query.category2Id = category2id;
} else {
query.category3Id = category3id;
}
// 整理完参数
location.query = query;
// 路由跳转
this.$router.push(location);
}
}