您的位置:首页 > Web前端 > Vue.js

vue实现下拉效果

2019-05-14 11:22 1236 查看

手把手教你实现vue下拉菜单组件
96 阿乾哥
0.4 2019.02.26 00:20* 字数 2050 阅读 930评论 0喜欢 3

这篇文章我们一起来实现一个vue的下拉菜单组件。
像这种基本UI组件,网上已经有很多了,为什么要自己实现呢?其实并不是有意重复造轮子,而是想通过这个过程回顾一下vue组件开发的一些细节和注意事项。

为什么选择下拉菜单组件?
因为:麻雀虽小五脏俱全,这个小小的组件涉及到了不少vue组件开发的知识点。
好了,那就开始吧!

首先创建一个vue-cli的项目,笔者用的是vue-cli3,创建过程略,然后创建一个vue组件:DropDownList.vue

在编写模板之前,我们来分析一下这个组件的视图结构和功能。
下拉菜单组件应该由两部分组成:

选中项的文本
待选菜单(默认隐藏)

它的主要功能包括:

鼠标经过下拉菜单组件,显示待选菜单
鼠标滑出下拉菜单组件,隐藏待选菜单
鼠标点击待选菜单中的条目,选中项文本更新,组件派发change事件
我们编写如下这样的模板:

选中项文本右侧的i标签,用来实现下拉菜单的三角形图标,在下文的css中我们用背景图来实现。
我们给根元素div已经添加了鼠标经过和滑出的回调函数,具体实现见下文。

接下来我们为这个下拉菜单编写样式,在模板下方添加style标签,为了防止和其他组件的样式发生冲突,笔者建议大家在开发组件时,都给style加上scoped属性。另外,笔者在这里用到了scss,具体代码如下:

关于样式,这里就不详细展开了,只说其中几个需要注意的点:

那个i元素的样式,我用到了一个网络图片,大家可以自行更换
待选菜单ul在css里并没有让它隐藏,因为我们要通过js来控制,具体原因见下文
待选菜单ul使用了绝对定位,因为当它展开的时候,不应该影响页面上其他元素的布局

现在这个组件大概长这个样子:

1.png

我们继续为这个组件定义属性,很显然,待选菜单应该作为属性传进来,一定不能是内部写死的,属性定义如下:

这个页面引入并使用了我们的DropDownList组件,:dataList=“dplist” 绑定了当前页面的dplist数组到组件的dataList属性上,这个数组中的对象有一个city字段,我们希望此字段显示在下拉菜单上,因此我们设置组件的labelProperty为city,我们还给这个组件注册了change事件,这个组件内部需要派发这个事件,见下文。

现在我们回到组件的模板部分,发现它都还是静态内容,我们把这些静态内容修改为通过属性渲染。

其中待选菜单li的文本是 item[labelProperty] 这样就能正确的显示开发者指定的字段了。
我们看看选中项的文本表达式:dplLabel,我们并没有定义这个属性,也没有定义这个内部数据,它是哪儿来的?选中项的文本应该是 dataList[activeIndex][labelProperty] (这个很好理解吧,有问题请留言),但这个表达式太长了,写在模板里不利于维护,我们就把它写到计算属性里吧。

computed:{
dplLable(){
return this.dataList[this.activeIndex][this.labelProperty]
}
}

于是才有了上面的dplLabel,计算属性真的很好用呢。

现在下拉菜单的视图和数据关联部分我们已经写完了,接下来我们要实现它的功能。

第一步是先让待选菜单默认隐藏起来,这里我们为什么不直接用css的display:none呢,然后鼠标经过的时候display:block不就可以了吗?因为这样的话,我们无法实现点击待选菜单条目的时候让它隐藏,体验不好。我们用js来控制,但vue对直接访问dom元素支持的并不好,我们要想在组件初始化的时候访问dom元素,有一个最方便的做法,那就是:自定义指令。

我们为下拉菜单组件添加局部自定义指令,代码如下:

directives:{
dpl:{
bind(el){
el.style.display = “none”;
}
}
},

这个dpl就是自定义指令啦,请忽略我笨拙的命名哈!然后我们在自定义指令的钩子函数bind方法中,访问el元素,控制它的style属性display:none; 最后,把这个自定义指令加到模板里面的ul标签上。别忘了要加v-,现在看看效果,待选菜单已经隐藏了。

我们利用自定义指令钩子函数访问dom元素,实现了对dom的控制,这一点非常实用!

让我们继续实现最开始为下拉菜单定义的鼠标经过和鼠标滑出的监听,实现待选菜单的显示与隐藏。

onDplOver(event){
let ul = event.currentTarget.childNodes[1];
ul.style.display = “block”;
},
onDplOut(event){
let ul = event.currentTarget.childNodes[1];
ul.style.display = “none”;
},

我们在鼠标事件中,访问event的currentTarget对象,为什么不是target?因为下拉菜单的子元素也会触发这个事件,如果访问target,可能不会是我们预期的顶层元素。

最后一步,我们实现待选菜单条目的点击事件,点击后,待选菜单隐藏,修改内部状态,派发change事件。

onLiClick(index){
let path = event.path || (event.composedPath && event.composedPath()) //兼容火狐和safari
path[1].style.display = “none”;
this.activeIndex = index;
this.$emit(“change”, {
index:index,
value:this.dataList[index]
})
}

这里有一个细节需要注意,我们要通过li元素找到外层ul元素,但path不支持火狐和safari,好在这两个浏览器支持composedPath,因此才有了第一行代码的兼容写法。然后通过修改内部数据activeIndex实现选中项文本的更新,最后调用emit方法向父元素派发change事件,别忘了把事件对象封装好传出去。

完整的代码如下:

以上为大家展示了vue如何实现一个下拉菜单组件,虽然比较简单,但也基本涉及到了组件开发常用的一些特性。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: