浅谈Vue.js中如何实现自定义下拉菜单指令


Posted in Javascript onJanuary 06, 2019

我们利用  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;
}

效果:

浅谈Vue.js中如何实现自定义下拉菜单指令

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 事件。

效果:

浅谈Vue.js中如何实现自定义下拉菜单指令

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>

本文示例代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
用Javascript数组处理多个字符串的连接问题
Aug 20 Javascript
node.js中的http.createServer方法使用说明
Dec 14 Javascript
jquery隔行换色效果实现方法
Jan 15 Javascript
JavaScript判断变量是否为空的自定义函数分享
Jan 31 Javascript
使用AJAX实现Web页面进度条的实例分享
May 06 Javascript
基于JS如何实现类似QQ好友头像hover时显示资料卡的效果(推荐)
Jun 09 Javascript
Bootstrap modal 多弹窗之叠加显示不出弹窗问题的解决方案
Feb 23 Javascript
详解JS数组Reduce()方法详解及高级技巧
Aug 18 Javascript
vue-router 组件复用问题详解
Jan 22 Javascript
详解vscode中vue代码颜色插件
Oct 11 Javascript
解决Vue的文本编辑器 vue-quill-editor 小图标样式排布错乱问题
Aug 03 Javascript
js对象属性名驼峰式转下划线的实例代码
Sep 17 Javascript
react-router4按需加载(踩坑填坑)
Jan 06 #Javascript
React 实现拖拽功能的示例代码
Jan 06 #Javascript
Next.js实现react服务器端渲染的方法示例
Jan 06 #Javascript
vue.js引入外部CSS样式和外部JS文件的方法
Jan 06 #Javascript
Bootstrap4 gulp 配置详解
Jan 06 #Javascript
jQuery实现获取当前鼠标位置并输出功能示例
Jan 05 #jQuery
node.js连接mysql与基本用法示例
Jan 05 #Javascript
You might like
全国FM电台频率大全 - 21 海南省
2020/03/11 无线电
php,不用COM,生成excel文件
2006/10/09 PHP
轻松修复Discuz!数据库
2008/05/03 PHP
实例讲解php实现多线程
2019/01/27 PHP
JS类库Bindows1.3中的内存释放方式分析
2007/03/08 Javascript
jQuery select控制插件
2009/08/17 Javascript
一个收集图片的bookmarlet(js 刷新页面中的图片)
2010/05/27 Javascript
ExtJS 设置级联菜单的默认值
2010/06/13 Javascript
js 通用javascript函数库整理
2011/08/14 Javascript
javascript实现文字图片上下滚动的具体实例
2013/06/28 Javascript
javascript的回调函数应用示例
2014/02/20 Javascript
JS面向对象编程详解
2016/03/06 Javascript
AngularJS中的过滤器filter用法完全解析
2016/04/22 Javascript
js实现人民币大写金额形式转换
2016/04/27 Javascript
玩转NODE.JS(四)-搭建简单的聊天室的代码
2016/11/11 Javascript
JS实现的表头列头固定页面功能示例
2017/01/10 Javascript
vue2.0中click点击当前li实现动态切换class
2017/06/21 Javascript
js中el表达式的使用和非空判断方法
2018/03/28 Javascript
使用D3.js构建实时图形的示例代码
2018/08/28 Javascript
JavaScript实现抖音罗盘时钟
2019/10/11 Javascript
[04:14]从西雅图到上海——玩家自制DOTA2主题歌曲应援TI9
2019/07/11 DOTA
python 数据加密代码
2008/12/24 Python
通过数据库向Django模型添加字段的示例
2015/07/21 Python
Pycharm学习教程(2) 代码风格
2017/05/02 Python
Django框架模板用法入门教程
2019/11/04 Python
学习Python需要哪些工具
2020/09/04 Python
Python爬虫之App爬虫视频下载的实现
2020/12/08 Python
世界上最大的售后摩托车零配件超市:J&P Cycles
2017/12/08 全球购物
机械化及自动化毕业生的自我评价分享
2013/11/06 职场文书
考察现实表现材料
2014/05/19 职场文书
竞选班长演讲稿400字
2014/08/22 职场文书
物理课外活动总结
2014/08/27 职场文书
群众路线对照检查材料思想汇报怎么写
2014/09/18 职场文书
升职自荐信怎么写
2015/03/05 职场文书
内勤岗位职责范本
2015/04/13 职场文书
培训心得体会怎么写
2016/01/25 职场文书