浅谈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 相关文章推荐
Jquery Validation插件防止重复提交表单的解决方法
Mar 05 Javascript
一个轻量级的javascript库 pj介绍
Dec 19 Javascript
JQuery里面的几种选择器 查找满足条件的元素$(&quot;#控件ID&quot;)
Aug 23 Javascript
基于jquery的loading 加载提示效果实现代码
Sep 01 Javascript
javascript 弹出的窗口返回值给父窗口具体实现
Nov 23 Javascript
深入理解JavaScript系列(39):设计模式之适配器模式详解
Mar 04 Javascript
JavaScript获得url查询参数的方法
Jul 02 Javascript
jQuery移动页面开发中的触摸事件与虚拟鼠标事件简介
Dec 03 Javascript
js 调用百度分享功能
Feb 27 Javascript
JS鼠标滚动分页效果示例
Jul 05 Javascript
JS库之Three.js 简易入门教程(详解之一)
Sep 13 Javascript
vue 使用鼠标滚动加载数据的例子
Oct 31 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
PHP字符串处理的10个简单方法
2010/06/30 PHP
使用PHP生成二维码的方法汇总
2015/07/22 PHP
functional继承模式 摘自javascript:the good parts
2011/06/20 Javascript
javascript 随机展示头像实现代码
2011/12/06 Javascript
通过JS自动隐藏手机浏览器的地址栏实现原理与代码
2013/01/02 Javascript
JavaScript类属性的访问方式详解
2014/02/11 Javascript
js数组的基本操作(很全自己整理的)
2014/10/16 Javascript
JS简单操作select和dropdownlist实例
2014/11/26 Javascript
js实现每日自动换一张图片的方法
2015/05/04 Javascript
JS点击某个图标或按钮弹出文件选择框的实现代码
2016/09/27 Javascript
javascript中Date对象的使用总结
2016/11/21 Javascript
基于jquery实现的银行卡号每隔4位自动插入空格的实现代码
2016/11/22 Javascript
详解堆的javascript实现方法
2016/11/29 Javascript
JS实现含有中文字符串的友好截取功能分析
2017/03/13 Javascript
Vue2.0 axios前后端登陆拦截器(实例讲解)
2017/10/27 Javascript
微信小程序全局变量功能与用法详解
2019/01/22 Javascript
JavaScript中的一些实用小技巧总结
2019/04/07 Javascript
JS中的变量作用域(console版)
2020/07/18 Javascript
jQuery实现本地存储
2020/12/22 jQuery
[56:57]LGD vs VP 2019DOTA2国际邀请赛淘汰赛 胜者组赛BO3 第一场 8.20.mp4
2019/08/22 DOTA
python PyTorch预训练示例
2018/02/11 Python
Python实现的质因式分解算法示例
2018/05/03 Python
Python进阶之全面解读高级特性之切片
2019/02/19 Python
Python-jenkins模块获取jobs的执行状态操作
2020/05/12 Python
Python使用xpath实现图片爬取
2020/09/16 Python
幼儿师范毕业生自荐信
2013/11/09 职场文书
个人自我评价和职业目标
2014/01/24 职场文书
党支部公开承诺践诺书
2014/03/28 职场文书
公司捐款倡议书
2014/05/14 职场文书
护士求职信范文
2014/05/24 职场文书
人大调研汇报材料
2014/08/14 职场文书
事业单位个人查摆问题及整改措施
2014/10/28 职场文书
2014办公室年度工作总结
2014/12/09 职场文书
spring cloud 配置中心native配置方式
2021/09/25 Java/Android
MySQL基于索引的压力测试的实现
2021/11/07 MySQL
分享CSS盒子模型隐藏的几种方式
2022/02/28 HTML / CSS