<template>
<!-- 商品分类导航 -->
<div class="type-nav">
<div class="container">
<!-- 事件委派 -->
<div @mouseleave="leaveIndex" @click.prevent="goSearch">
<h2 class="all">全部商品分类</h2>
<div class="sort">
<div class="all-sort-list2">
<div
class="item"
v-for="(item, index) in categoryList"
:key="item.categoryId"
:class="{ bo: currentIndex == index }"
>
<h3 @mouseenter="changeIndex(index)">
<a href="" :data-categoryName="item.categoryName" :data-category1Id="item.categoryId">{{ item.categoryName }}</a>
</h3>
<!-- 二级、三级分类 -->
<div
class="item-list clearfix"
:style="{ display: currentIndex == index ? 'block' : 'none' }"
>
<div
class="subitem"
v-for="subitem in item.categoryChild"
:key="subitem.categoryId"
>
<dl class="fore">
<dt>
<a href="" :data-categoryName="subitem.categoryName" :data-category2Id="subitem.categoryId">{{ subitem.categoryName }}</a>
</dt>
<dd>
<em
v-for="item3 in subitem.categoryChild"
:key="item3.categoryId"
>
<a href="" :data-categoryName="item3.categoryName" :data-category3Id="item3.categoryId">{{ item3.categoryName }}</a>
</em>
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
</div>
<nav class="nav">
<a href="###">服装城</a>
<a href="###">美妆馆</a>
<a href="###">尚品汇超市</a>
<a href="###">全球购</a>
<a href="###">闪购</a>
<a href="###">团购</a>
<a href="###">有趣</a>
<a href="###">秒杀</a>
</nav>
</div>
</div>
</template>
<script>
import { mapState } from "vuex";
// 引入第三方插件使用节流
import throttle from "lodash/throttle";
export default {
name: "TypeNav",
data() {
return {
// 鼠标滑过的一级菜单的index,切记初始值不能为0
currentIndex: -1,
};
},
mounted() {
// 分发action,通知vuex,可以向服务器发送请求,获取数据,存取在仓库当中
this.$store.dispatch("categoryList");
},
computed: {
// 预测需要是一个函数,当这个计算属性使用时,这个函数就执行一次
// 会注入一个state,这个state就是大仓库中的state
...mapState({
categoryList: (state) => state.home.categoryList,
}),
},
methods: {
// 鼠标进入修改响应式数据currentIndex的值
// 节流:用户操作很频繁,但是把频繁的操作变成少量的的操作,【可以给浏览器有充裕的时间解析代码】
// 防抖:用户操作很频繁,只执行最后一次
changeIndex: throttle(function (index) {
this.currentIndex = index;
}, 50),
leaveIndex() {
this.currentIndex = -1;
},
//精益求精
//将全部的子节点的事件委派给父节点->事件回调就一个
goSearch(event) {
//第一个问题:div父节点子元素太多【h3、h2、em、dt、dd、dl...a】?你怎么知道你点击的一定是a
//第二个问题:要区分一级分类、二级分类、三级分类的a标签【category1Id|category2Id|category2Id】
let targetNode = event.target;
//获取触发事件节点的自定义属性【a:data-categoryName】
let { categoryname, category1id, category2id, category3id } =
targetNode.dataset;
//判断点击的是a【不管是1|2|3】
if (categoryname) {
//点击只要是a,就是往search模块跳转
var locations = {
name: "search",
query: { categoryName: categoryname },
};
//一级分类的a
if (category1id) {
console.log("category1id-------", category1id);
locations.query.category1Id = category1id;
} else if (category2id) {
//二级分类的a
locations.query.category2Id = category2id;
} else {
//三级分类的a
locations.query.category3Id = category3id;
}
//点击商品分类按钮的时候,如果路径当中携带params参数,需要合并携带给search模块
if (this.$route.params.keyword) {
locations.params = this.$route.params;
}
//目前商品分类这里携带参数只有query参数
this.$router.push(locations);
}
},
},
};
</script>
<style lang="less" scoped>
.type-nav {
border-bottom: 2px solid #e1251b;
.container {
width: 1200px;
margin: 0 auto;
display: flex;
position: relative;
.all {
width: 210px;
height: 45px;
background-color: #e1251b;
line-height: 45px;
text-align: center;
color: #fff;
font-size: 14px;
font-weight: bold;
}
.nav {
a {
height: 45px;
margin: 0 22px;
line-height: 45px;
font-size: 16px;
color: #333;
}
}
.sort {
position: absolute;
left: 0;
top: 45px;
width: 210px;
height: 461px;
position: absolute;
background: #fafafa;
z-index: 999;
.all-sort-list2 {
.item {
h3 {
line-height: 30px;
font-size: 14px;
font-weight: 400;
overflow: hidden;
padding: 0 20px;
margin: 0;
a {
color: #333;
}
}
.item-list {
display: none;
position: absolute;
width: 734px;
min-height: 460px;
background: #f7f7f7;
left: 210px;
border: 1px solid #ddd;
top: 0;
z-index: 9999 !important;
.subitem {
float: left;
width: 650px;
padding: 0 4px 0 8px;
dl {
border-top: 1px solid #eee;
padding: 6px 0;
overflow: hidden;
zoom: 1;
&.fore {
border-top: 0;
}
dt {
float: left;
width: 54px;
line-height: 22px;
text-align: right;
padding: 3px 6px 0 0;
font-weight: 700;
}
dd {
float: left;
width: 415px;
padding: 3px 0 0;
overflow: hidden;
em {
float: left;
height: 14px;
line-height: 14px;
padding: 0 8px;
margin-top: 5px;
border-left: 1px solid #ccc;
}
}
}
}
}
}
.bo {
background-color: skyblue;
}
}
}
}
}
</style>
下面是我的路由配置文件
// 配置路由, 一定要注意这里是routes,不是routers
routes: [
{
path: '/home',
component: Home,
meta: {
show: true
}
},
{
path: '/login',
name: 'login',
component: Login,
meta: {
show: false
}
},
{
// 注意占位符是:开头,占位符后面加上一个问号,可传可不传
path: '/search/:keyword?',
name: 'search',
component: Search,
meta: {
show: true
}
},
{
path: '/register',
component: Regsiter,
meta: {
show: false
}
},
{
path: '/',
redirect: '/home'
}
]
. capture:捕获冒泡,即有冒泡发生时,有该修饰符的dom元素会先执行,如果有多个,从外到内依次执行,然后再按自然顺序执行触发的事件。
. self:将事件绑定到自身,只有自身才能触发,通常用于避免冒泡事件的影响
. once:设置事件只能触发一次,比如按钮的点击等。
. passive:该修饰符大概意思用于对DOM的默认事件进行性能优化,根据官网的例子比如超出最大范围的滚动条滚动的。
. native:在父组件中给子组件绑定一个原生的事件,就将子组件变成了普通的HTML标签,不加’. native’事件是无法触 发的。
.stop:阻止冒泡
.stop.prevent:串联修饰符