浅谈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 获取span标签中的值的代码 支持ie与firefox
Aug 24 Javascript
JQuery实现简单验证码提示解决方案
Dec 20 Javascript
JS实现静止元素自动移动示例
Apr 14 Javascript
js实现双击图片放大单击缩小的方法
Feb 17 Javascript
jquery获取当前元素索引值用法实例
Jun 10 Javascript
JavaScript重载函数实例剖析
May 13 Javascript
JavaScript判断浏览器对CSS3属性是否支持的多种方法
Nov 13 Javascript
浅谈箭头函数写法在ReactJs中的使用
Aug 22 Javascript
vue父组件向子组件传递多个数据的实例
Mar 01 Javascript
详解Vue的钩子函数(路由导航守卫、keep-alive、生命周期钩子)
Jul 24 Javascript
性能优化篇之Webpack构建速度优化的建议
Apr 03 Javascript
VSCode 添加自定义注释的方法(附带红色警戒经典注释风格)
Aug 27 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如何得到当前页和上一页的地址?
2006/11/27 PHP
Breeze 文章管理系统 v1.0.0正式发布
2006/12/14 PHP
有关PHP中MVC的开发经验分享
2012/05/17 PHP
php笔记之:数据类型与常量的使用分析
2013/05/14 PHP
PHP如何通过AJAX方式实现登录功能
2015/11/23 PHP
关于Curl在Swoole协程中的解决方案详析
2019/09/12 PHP
用Greasemonkey 脚本收藏网站会员信息到本地
2009/10/26 Javascript
javascript与jquery中跳出循环的区别总结
2013/11/04 Javascript
JS长整型精度问题实例分析
2015/01/13 Javascript
JavaScript插件化开发教程 (一)
2015/01/27 Javascript
JavaScript组件焦点与页内锚点间传值的方法
2015/02/02 Javascript
IE下使用jQuery重置iframe地址时内存泄露问题解决办法
2015/02/05 Javascript
基于BootstrapValidator的Form表单验证(24)
2016/12/12 Javascript
JSON中key动态设置及JSON.parse和JSON.stringify()的区别
2016/12/29 Javascript
bootstrap滚动监控器使用方法解析
2017/01/13 Javascript
ajax分页效果(bootstrap模态框)
2017/01/23 Javascript
JS异步宏队列微队列原理详解
2020/09/09 Javascript
vue实现点击按钮“查看详情”弹窗展示详情列表操作
2020/09/09 Javascript
python网络编程之UDP通信实例(含服务器端、客户端、UDP广播例子)
2014/04/25 Python
python中字典(Dictionary)用法实例详解
2015/05/30 Python
python实现逆序输出一个数字的示例讲解
2018/06/25 Python
python基础 range的用法解析
2019/08/23 Python
python之MSE、MAE、RMSE的使用
2020/02/24 Python
python 3.8.3 安装配置图文教程
2020/05/21 Python
python如何快速生成时间戳
2020/07/21 Python
pandas将list数据拆分成行或列的实现
2020/12/13 Python
python简单实现插入排序实例代码
2020/12/16 Python
一个非常简单好用的Python图形界面库(PysimpleGUI)
2020/12/28 Python
C语言变量的命名规则都有哪些
2013/12/27 面试题
五一家具促销方案
2014/01/10 职场文书
理工大学毕业生自荐信范文
2014/02/22 职场文书
导游词之韩国济州岛
2019/10/28 职场文书
python实现Thrift服务端的方法
2021/04/20 Python
为什么你写的height:100%不起作用
2021/05/10 HTML / CSS
了解Redis常见应用场景
2021/06/23 Redis
Java 常见的限流算法详细分析并实现
2022/04/07 Java/Android