浅谈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 相关文章推荐
js+css实现的简单易用兼容好的分页
Dec 30 Javascript
jQuery 获取兄弟元素的几种不错方法
May 23 Javascript
js实现简单选项卡与自动切换效果的方法
Apr 10 Javascript
javascript精确统计网站访问量实例代码
Dec 19 Javascript
学习javascript面向对象 理解javascript原型和原型链
Jan 04 Javascript
jquery实现点击弹出可放大居中及关闭的对话框(附demo源码下载)
May 10 Javascript
轻松掌握JavaScript单例模式
Aug 25 Javascript
JS原型与原型链的深入理解
Feb 15 Javascript
angular中实现控制器之间传递参数的方式
Apr 24 Javascript
使用yeoman构建angular应用的方法
Aug 14 Javascript
关于在vue 中使用百度ueEditor编辑器的方法实例代码
Sep 14 Javascript
uni-app自定义导航栏按钮|uniapp仿微信顶部导航条功能
Nov 12 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
PHP4实际应用经验篇(6)
2006/10/09 PHP
PHP 表单提交给自己
2008/07/24 PHP
PHP之数组学习
2011/05/29 PHP
PHP实现批量修改文件后缀名的方法
2015/07/30 PHP
php搜索文件程序分享
2015/10/30 PHP
实现超用户体验 table排序javascript实现代码
2009/06/22 Javascript
nodejs win7下安装方法
2012/05/24 NodeJs
node.js中的path.isAbsolute方法使用说明
2014/12/08 Javascript
Jquery结合HTML5实现文件上传
2015/06/25 Javascript
jquery特效 点击展示与隐藏全文
2015/12/09 Javascript
详解AngularJS实现表单验证
2015/12/10 Javascript
JS+CSS实现DIV层的展开、收缩效果
2016/01/28 Javascript
Node.js本地文件操作之文件拷贝与目录遍历的方法
2016/02/16 Javascript
判断js的Array和Object的实现方法
2016/08/29 Javascript
类似于QQ的右滑删除效果的实现方法
2016/10/16 Javascript
如何学JavaScript?前辈的经验之谈
2016/12/28 Javascript
Vue通过input筛选数据
2020/10/26 Javascript
JS监控关闭浏览器操作的实例详解
2017/09/12 Javascript
Python处理PDF及生成多层PDF实例代码
2017/04/24 Python
Pytest参数化parametrize使用代码实例
2020/02/22 Python
Python使用pyyaml模块处理yaml数据
2020/04/14 Python
python opencv实现直线检测并测出倾斜角度(附源码+注释)
2020/12/31 Python
Html5之svg可缩放矢量图形_动力节点Java学院整理
2017/07/17 HTML / CSS
Debenhams百货英国官方网站:Debenhams UK
2016/07/12 全球购物
JACK & JONES英国官方网站:欧洲领先的男装生产商
2017/09/27 全球购物
三星新西兰官网:Samsung新西兰
2019/03/05 全球购物
瑞士网球商店:Tennis-Point
2020/03/12 全球购物
Linux开机引导的步骤是什么
2014/02/26 面试题
Java面试题:Java类的Main方法如果是Private将会怎么样
2016/08/18 面试题
市场开发与营销专业求职信
2013/12/31 职场文书
医生进修自我鉴定
2014/01/19 职场文书
大学生党员自我评价范文
2014/04/09 职场文书
刘公岛导游词
2015/02/05 职场文书
60句有关成长的名言
2019/09/04 职场文书
mysql 体系结构和存储引擎介绍
2022/05/06 MySQL
Java获取字符串编码格式实现思路
2022/09/23 Java/Android