视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
浅谈Vue.js中如何实现自定义下拉菜单指令
2020-11-27 22:02:17 责编:小采
文档

我们利用  Vue.js 的自定义指令能力,来实现一个自定义下拉菜单功能。描述如下:

  1. 点击按钮,弹出下拉菜单。
  2. 点击下拉菜单之外的区域,关闭下拉菜单。

1基础版

html:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
 <link rel="stylesheet" type="text/css" href="style.css" rel="external nofollow" >
</head>
<body>

 <div id="app" v-cloak>
 <div class="main" v-outside-click="close">
 <button @click="isShow=!isShow">点击</button>
 <div class="dropDown" v-show="isShow">
 <p>零售新物种:药店和便利店合体之后</p>
 </div>
 </div>
 </div>

<script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
<script src="index.js"></script>

</body>
</html>

我们为按钮绑定了 isShow 变量,当点击按钮时,显示 class="dropDown" 的 div 元素。

js:

Vue.directive('outside-click', {
 bind: function (el, binding, vnode) {
 //定义点击函数
 function clickHandler(e) {
 if (el.contains(e.target)) {//如果点击区域在所在指令元素内部,则直接返回
 return false;
 }
 if (binding.expression) {//如果定义了表达式,则执行表达式中的函数
 binding.value(e);
 }
 }

 el.vueOutsideClick = clickHandler;
 document.addEventListener('click', clickHandler);//绑定到 document 的点击事件
 },
 unbind: function (el, binding, vnode) {
 document.removeEventListener('click', el.vueOutsideClick);//解绑
 delete el.vueOutsideClick;//销毁
 }

});

var app = new Vue({
 el: '#app',
 data: {
 isShow: false
 },
 methods: {
 close: function () {
 this.isShow = false;
 }
 }
});

bind 中:

  1. 首先在定义了点击函数,内部逻辑为:如果点击区域在所在指令元素内部,则直接返回;如果定义了表达式,则执行表达式中的函数(示例中是 close)。
  2. 这里用到了 contains 函数, A.contains(B) 是判断元素 A 是否包含了元素 B。
  3. 接着在 el 中定义了一个变量,用于存放刚才定义的点击函数。bind() 与 unbind() 通过 el 变量进行参数传递。
  4. 然后绑定到 document 的点击事件。

unbind 中:

  1. 解绑在 bind 中绑定的点击事件。
  2. 销毁该变量。

css:

[v-cloak] {
 display: none;
}

.main {
 width: 125px;
}

button {
 display: block;
 width: 100%;
 color: #ffffff;
 background-color: #99CC66;
 border: 0;
 padding: 6px;
 text-align: center;
 font-size: 12px;
 border-radius: 4px;
 cursor: pointer;
 position: relative;
 outline: none;
}

button:active {
 top: 1px;
 left: 1px;
}

.dropDown {
 width: 100%;
 height: 150px;
 margin: 5px 0;
 font-size: 12px;
 background-color: #ffffff;
 border-radius: 4px;
 box-shadow: 0 1px 6px rgba(0, 0, 0, .2);
}

.dropDown p {
 display: inline-block;
 padding: 6px;
}

效果:

2  ESC 关闭

现在让我们做个优化,即在按下键盘的 ESC 键时,也能关闭下拉菜单。

js:

bind: function (el, binding, vnode) {
 function clickHandler(e) {
 if (el.contains(e.target) && e.keyCode !== 27) {
 return false;
 }
 ...
 }

 ...
 document.addEventListener('keyup', clickHandler, false);//绑定键盘事件
},
unbind: function (el, binding, vnode) {
 ...
 document.removeEventListener('keyup', el.vueOutsideClick);//解绑
 ...
}

在 bind 函数中,强化了判断,如果点击区域在所在指令元素内部并且没有按下 ESC 键时,才直接返回。即按下  ESC 键时,会执行后续操作(执行表达式中的函数)。

在  unbind 函数中,也解绑了 keyup 事件。

效果:

3 ESC 为可选项

我们可以把 ESC 作为可选项,而这可以通过修饰符来实现。

js:

bind: function (el, binding, vnode) {
 //定义点击函数
 function clickHandler(e) {

 //是否开启开关
 var escSwitch = (binding.modifiers && binding.modifiers.esc);

 if (el.contains(e.target)) {//如果点击区域在所在指令元素内部时
 if (escSwitch && e.keyCode === 27) {//带有了 esc 修饰符,则让程序往下执行
 } else {//直接返回
 return false;
 }
 }
 if (binding.expression) {//如果定义了表达式,则执行表达式中的函数
 binding.value(e);
 }
 }

 ...
}

我们通过 binding.modifiers 来判断自定义指令是否设置了 esc 修饰符,然后以此为基础,来编写后续逻辑。

html:

<div id="app" v-cloak>
 <div class="main" v-outside-click.esc="close">
 ...
 </div>
</div>

本文示例代码

下载本文
显示全文
专题