浅谈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 EasyUI 中文API Button使用实例
Apr 14 Javascript
ExtJs 表单提交登陆实现代码
Aug 19 Javascript
jquery iframe操作详细解析
Nov 20 Javascript
jQuery源码分析之Callbacks详解
Mar 13 Javascript
jquery性能优化高级技巧
Aug 24 Javascript
jQuery实现连续动画效果实例分析
Oct 09 Javascript
jQuery Tree Multiselect使用详解
May 02 jQuery
Bootstrap Table使用整理(二)
Jun 09 Javascript
微信小程序实现选项卡功能
Jun 19 Javascript
jQuery实现的上传图片本地预览效果简单示例
Mar 29 jQuery
基于Node.js搭建hexo博客过程详解
Jun 25 Javascript
jquery实现图片放大镜效果
Dec 23 jQuery
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 preg_match_all结合str_replace替换内容中所有img
2008/10/11 PHP
删除无限分类并同时删除它下面的所有子分类的方法
2010/08/08 PHP
phpmyadmin出现Cannot start session without errors问题解决方法
2014/08/14 PHP
PHP文件及文件夹操作之创建、删除、移动、复制
2016/07/13 PHP
PHP页面输出时js设置input框的选中值
2016/09/30 PHP
laravel5.1 ajax post 传值_token示例
2019/10/24 PHP
javascript 全角转换实现代码
2009/07/17 Javascript
JavaScript 异步调用框架 (Part 6 - 实例 &amp; 模式)
2009/08/04 Javascript
javascript 节点排序 2
2011/01/31 Javascript
各浏览器对click方法的支持差异小结
2011/07/31 Javascript
JS过滤url参数特殊字符的实现方法
2013/12/24 Javascript
jquery移除、绑定、触发元素事件使用示例详解
2014/04/10 Javascript
js如何判断访问是来自搜索引擎(蜘蛛人)还是直接访问
2015/09/14 Javascript
jQuery使用经验小技巧(推荐)
2016/05/31 Javascript
AngularJS入门教程之控制器详解
2016/07/27 Javascript
JS简单封装的图片无缝滚动效果示例【测试可用】
2017/03/22 Javascript
基于BootStrap multiselect.js实现的下拉框联动效果
2017/07/28 Javascript
JS中Attr的用法详解
2017/10/09 Javascript
微信小程序ajax实现请求服务器数据及模版遍历数据功能示例
2017/12/15 Javascript
使用Jenkins部署React项目的方法步骤
2019/03/11 Javascript
jQuery实现中奖播报功能(让文本滚动起来) 简单设置数值即可
2020/03/20 jQuery
2020淘宝618理想生活列车自动领喵币js脚本的代码
2020/06/02 Javascript
Vue实现摇一摇功能(兼容ios13.3以上)
2021/01/26 Vue.js
对Python中实现两个数的值交换的集中方法详解
2019/01/11 Python
详解Python静态网页爬取获取高清壁纸
2019/04/23 Python
python super的使用方法及实例详解
2019/09/25 Python
python网络编程:socketserver的基本使用方法实例分析
2020/04/09 Python
css3实现简单的白云飘动背景特效
2020/10/28 HTML / CSS
儿科主治医生个人求职信
2013/09/23 职场文书
自我评价范文点评
2013/12/04 职场文书
出差报告怎么写
2014/11/06 职场文书
2015年质量月活动总结报告
2015/03/27 职场文书
2015年个人实习工作总结
2015/05/28 职场文书
政审证明材料
2015/06/19 职场文书
2016应届大学生自荐信模板
2016/01/28 职场文书
JavaScript 反射学习技巧
2021/10/16 Javascript