浅谈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编程起步(第二课)
Jan 10 Javascript
找出字符串中出现次数最多的字母和出现次数精简版
Nov 07 Javascript
window.location不跳转的问题解决方法
Apr 17 Javascript
Javascript学习笔记之函数篇(四):arguments 对象
Nov 23 Javascript
JavaScript设计模式之工厂模式和构造器模式
Feb 11 Javascript
跟我学习javascript的undefined与null
Nov 17 Javascript
JavaScript实现搜索框的自动完成功能(一)
Feb 25 Javascript
javascript先序遍历DOM树的方法
Feb 27 Javascript
深入理解JavaScript中为什么string可以拥有方法
May 24 Javascript
Vue.js仿微信聊天窗口展示组件功能
Aug 11 Javascript
jQuery中使用validate插件校验表单功能
May 24 jQuery
Vue3.0中Ref与Reactive的区别示例详析
Jul 07 Vue.js
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
2006/12/23 PHP
php实现的Curl封装类Curl.class.php用法实例分析
2015/09/25 PHP
基于ThinkPHP实现的日历功能实例详解
2017/04/15 PHP
PHP实现正则匹配所有括号中的内容
2018/06/22 PHP
Laravel框架实现多数据库连接操作详解
2019/07/12 PHP
怎么选择Javascript框架(Javascript Framework)
2013/11/22 Javascript
javascript实现九宫格相加数值相等
2020/05/28 Javascript
使用Angular.js实现简单的购物车功能
2016/11/21 Javascript
浅谈Angular4实现热加载开发旅程
2017/09/08 Javascript
微信小程序中换行空格(多个空格)写法详解
2018/07/10 Javascript
LayUI表格批量删除方法
2018/08/15 Javascript
详解webpack模块加载器兼打包工具
2018/09/11 Javascript
解决angular2在双向数据绑定时[(ngModel)]无法使用的问题
2018/09/13 Javascript
js实现一个页面多个倒计时的3种方法
2019/02/25 Javascript
jQuery中实现text()的方法
2019/04/04 jQuery
微信小程序实现获取用户信息并存入数据库操作示例
2019/05/07 Javascript
深入学习Vue nextTick的用法及原理
2019/10/08 Javascript
Vue数据双向绑定原理实例解析
2020/05/15 Javascript
Vue this.$router.push(参数)实现页面跳转操作
2020/09/09 Javascript
Python实现网站注册验证码生成类
2017/06/08 Python
numpy判断数值类型、过滤出数值型数据的方法
2018/06/09 Python
Python学习小技巧总结
2018/06/10 Python
python求质数的3种方法
2018/09/28 Python
pywinauto自动化操作记事本
2019/08/26 Python
使用Django搭建web服务器的例子(最最正确的方式)
2019/08/29 Python
PyTorch笔记之scatter()函数的使用
2020/02/12 Python
Pandas缺失值2种处理方式代码实例
2020/06/13 Python
如何基于Python爬取隐秘的角落评论
2020/07/02 Python
python 爬虫之selenium可视化爬虫的实现
2020/12/04 Python
“型”走纽约上东区:Sam Edelman
2017/04/02 全球购物
健身场所或家用健身设备:Life Fitness
2017/11/01 全球购物
Bloomingdale’s阿联酋:选购奢华时尚、美容及更多
2020/09/22 全球购物
2015年党风廉政建设目标责任书
2015/05/08 职场文书
教育读书笔记
2015/07/02 职场文书
Mysql效率优化定位较低sql的两种方式
2021/05/26 MySQL
python的netCDF4批量处理NC格式文件的操作方法
2022/03/21 Python