![](https://img.haomeiwen.com/i19781462/e006c9656a4cad24.png)
在index.html里面引入。
![](https://img.haomeiwen.com/i19781462/f3326b4b0851d368.png)
在menu.js脚本里编写代码。
首先写个class关键字定义class类。
![](https://img.haomeiwen.com/i19781462/67ead1a6ee8610b3.png)
constructor定义一个构造构造函数。
![](https://img.haomeiwen.com/i19781462/6ef7405fdeeb2c0c.png)
参数id对应html里面的样式。
![](https://img.haomeiwen.com/i19781462/08071ef75aaccd9c.png)
init定义初始方法和调用
![](https://img.haomeiwen.com/i19781462/38bb0bcc7db1426b.png)
在方法里面输出控制台语句,为后面实例的创建作检验。
![](https://img.haomeiwen.com/i19781462/d83864a52a51f2d7.png)
回到index.html里面new(创建)一个实例对象来使用我们在脚本里面定义的class类。
![](https://img.haomeiwen.com/i19781462/f33919632a615628.png)
逻辑对应关系
![](https://img.haomeiwen.com/i19781462/6920cefef89e55b2.png)
控制台查看到输出,检验到初始化方法是可用的,证明class类定义的整个流程都能跑通了,能将class引进来且生效了。
![](https://img.haomeiwen.com/i19781462/e8a11883f9eac502.png)
下面实现是功能实现
![](https://img.haomeiwen.com/i19781462/296f42aa3c0da0bd.png)
我们想获取盒子(box)下面ul和li标签,和二级菜单下的class样式
![](https://img.haomeiwen.com/i19781462/6410aec936863d36.png)
回到menu.js脚本,那怎么在class类中获取到DOM?
![]()
我们要实现一个类似京东网站的鼠标滑动功能。
可以看到这样一个二级菜单效果,首先有一个延迟效果(计时器的实现),鼠标移入移出事件,鼠标可以斜着锚点,不同于:hover的曲线救国方式。
![]()
我们来看下曲线救国方式:css样式中:hover伪类,虽然可以实现,但还是有点不同。鼠标不能斜着移动,会跳到其他二级菜单取,体验并不好。
![]()
两种方式对比路径。
![]()
我的表达可能不太清晰哈,大家可以去京东网站,手动体验下。
以上就是我们想要实现的一个效果。
我们回到脚本编辑页面。接下来我们在init中设计逻辑功能,所谓的功能都是为了增强用户的交互体验。
![]()
给所有li标签绑定一个监听事件
![]()
去掉箭头函数的原型是这样的:
![]()
语法分析:
HTML DOM addEventListener() 方法,类似遍历的关系
JavaScript forEach() 方法
续上
![](https://img.haomeiwen.com/i19781462/503908934ffe6a2d.png)
我们只想要target,我们输出console.log(event),在控制台找到它。
![](https://img.haomeiwen.com/i19781462/e720cfb333f43950.png)
然后打印
![](https://img.haomeiwen.com/i19781462/7dbd7b8dc82be6a6.png)
看看e.target又是啥。
![](https://img.haomeiwen.com/i19781462/21bfc17d2959a4a4.png)
接下来我们检验鼠标移出移入是否成功
![](https://img.haomeiwen.com/i19781462/5c494b072b75f66a.png)
![](https://img.haomeiwen.com/i19781462/78b9a40620297f6b.gif)
没有问题,已经生效了。
接下来声明一个定时器
![](https://img.haomeiwen.com/i19781462/bfc4ba057a61ee91.png)
延迟200ms后去控制.active
![](https://img.haomeiwen.com/i19781462/1eae92408450126b.png)
![](https://img.haomeiwen.com/i19781462/ca202c516db9f783.png)
我们来看下效果:
![](https://img.haomeiwen.com/i19781462/455935e9e6477c3b.gif)
![](https://img.haomeiwen.com/i19781462/162c9a0f3563309f.png)
效果:
可以看到每次鼠标移出去,二级菜单都会关闭。鼠标一进来,打开二级菜单。
![](https://img.haomeiwen.com/i19781462/3aa203e261ff7bc9.gif)
我们迅速滑动鼠标,这行代码就是只触发鼠标最后一次停留的,中间掠过的不算。(防抖操作)
![](https://img.haomeiwen.com/i19781462/5ee5a5ccd86dff30.png)
我们看下原来的效果先。
![](https://img.haomeiwen.com/i19781462/ec641612ddfad6ea.gif)
清除了计时器后(做了防抖操作后的效果)。
只触发鼠标最后一次停留的,中间掠过的不算。
![](https://img.haomeiwen.com/i19781462/80e007f3b9c09957.gif)
这个代码避免了曲线救国的尴尬(可以斜着拉鼠标到二级菜单,而不是在:hover伪类下走7字的路径)(同样是防抖)
![](https://img.haomeiwen.com/i19781462/d5fda14616d7d46a.png)
![](https://img.haomeiwen.com/i19781462/986ada9df3b4b289.gif)
class Menu {
constructor(id) {
this.box = document.querySelector(id)
this.ul = this.box.querySelector('ul')
this.lis = this.box.querySelectorAll('li')
this.subMenuEles = this.box.querySelectorAll('.sub-menu')
this.timer1 = null;
this.timer2 = null;
this.init()
}
init () {
//console.log('menu');
this.lis.forEach(item => {
item.addEventListener("mouseenter", e=> {
let li = e.target
console.log("mouseenter")
if (this.timer1 != null) {
clearTimeout(this.timer1)
}
this.timer1 = setTimeout(() => {
this.subMenuEles.forEach((item) => {
item.classList.remove("active")
})
li.children[1].classList.add("active")
},200)
})
});
this.lis.forEach(item => {
item.addEventListener("mouseleave", e=> {
let li = e.target
console.log("mouseleave")
if (this.timer2 != null) {
clearTimeout(this.timer2)
}
this.timer2 = setTimeout(() => {
this.subMenuEles.forEach((item) => {
li.children[1].classList.remove("active")
})
},200)
})
});
}
}
网友评论