详解Vue用自定义指令完成一个下拉菜单(select组件)


Posted in Javascript onOctober 31, 2017

这次分享的是关于Vue自定义指令的使用方法,学习完基础后我们再来实战完成一个下拉列表,废话不多说,直接上干货

基本用法

//全局注册
Vue.directive('my-directive', {
 // 指令选项
})

// 局部注册
var app = new Vue({
 el: '#app'
 directives: {
  'my-directive': {
    // 指令选项
  }
})

相信对Vue比较熟悉的人看完都知道,directive的写法与组件 基本类似,只是方法名由component改为了directive。上例只是注册了自定义指令v-my-directive,还没实现具体功能,下面具体介绍 自定义指令的各个选项。

指令定义函数提供了几个钩子函数 (可选):

  1. bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
  2. inserted:被绑定元素插入父节点时调用 (父节点存在即可调用,不必存在于 document 中)。
  3. update:所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
  4. componentUpdated:所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
  5. unbind:只调用一次,指令与元素解绑时调用。

可根据需求在不同的钩子函数 内完成逻辑代码,如下面v-focus,我们希望在元素插入父节点时就调用,那用到的最好的就是inserted了。示例代码如下

// html部分
<div id="app" v-focus>
// js部分
Vue.directive('focus', {
 // 当绑定元素插入到 DOM 中。
 inserted: function (el) {
  // 聚焦元素
  el.focus()
 }
})

效果如下图所示

详解Vue用自定义指令完成一个下拉菜单(select组件)

自定义指令 v-focus.png

可以看到,打开这个页面,input输入框就自动获取焦点了,成为可输入状态。

每个钩子函数 都可以有几个参数可用,比如我们上面用到了el。它们 的含义如下:

  1. el:指令所绑定的元素,可以用来直接操作 DOM 。
  2. binding:一个对象,包含以下属性:
    1. name:指令名,不包括 v-前缀。
    2. value:指令的绑定值,例如:v-my-directive="1 + 1", value 的值是 2。
    3. oldValue:指令绑定的前一个值,仅在 update和 componentUpdated钩子中可用。无论值是否改变都可用。
    4. expression:绑定值的字符串形式。例如 v-my-directive="1 + 1" ,expression 的值是 "1 + 1"。
    5. arg:传给指令的参数。例如 v-my-directive:foo,arg 的值是 "foo"。
    6. modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
  3. vnode:Vue 编译生成的虚拟节点,查阅 VNode API 了解更多详情。
  4. oldVnode:上一个虚拟节点,仅在 update和 componentUpdated钩子中可用。

下面是结合了以上参数 的一些具体示例,代码如下

// HTML部分
<div id="app" v-demo:msg.a.b="message">
 <div v-text:msg.a.b="message"></div>
</div>
// JS部分
Vue.directive('demo', {
 bind: function (el, binding, vnode) {
  var s = JSON.stringify
  el.innerHTML =
   'name: '    + binding.name + '<br>' +
   'value: '   + binding.value + '<br>' +
   'expression: ' + binding.expression + '<br>' +
   'argument: '  + binding.arg + '<br>' +
   'modifiers: ' + JSON.stringify(binding.modifiers).modifiers + '<br>' +
   'vnode keys: ' + Object.keys(vnode).join(',')
 }
})
new Vue({
 el: '#app',
 data: {
  message: 'some text'
 }
})

执行后,<div>的内容会使用innerHTML重置,结果为

name: "test"
value: "some text"
expression: "message"
argument: "msg"
modifiers: {"a":true,"b":true}
vnode keys: tag, data, children, text, elm, ns, context, functionalContext, functionalOptions, functionalScopeId, key, componentOptions, componentInstance, parent, raw, isStatic, isRootInsert, isComment, isCloned, isOnce, asyncFactory, asyncMeta, isAsyncPlaceholder

在多数使用场景,我们会在bind钩子里绑定一些事件,比如在document上用addEventListerer绑定,在unbind里有
removeEventListener 解绑,比较典型的示例就是让这个元素随着鼠标拖拽。

如果需要更多个值,自定义指令也可以传入一个JavaScript对象字面量, 只要是合法类型的JavaScript表达式都是可以的。示例代码如下:

// HTML部分
<div id="app" v-demo:msg.a.b="message">
 <div v-test="{msg: 'hello', name: 'Aresn'}"></div>
</div>

//JS部分
Vue.directive('test', {
 bind: function (el, binding, vnode) {
  console.log(binding.value.msg)
  console.log(binding.value.name)
 }
})
var app = new Vue({
 el: '#app'
})

Vue 2.x很移除大量Vue 1.x自定义指令的配置。在使用自定义指令时,应该充分解业务需求,因为很多时候你需要的可能并不是自定义指令,而是组件。

基础的东西讲完了,我们来根据directive提供的API来写一个点击外部区域可以让其下拉列表消失的菜单

// HTML部分
<div id="app" v-clock>
 <div class="main" v-clickoutside="handleClose">
  <button @click="show = !show">点击显示下拉菜单</button>
  <div class="dropdown" v-show="show">
   <p>下拉框内容,点击外面区域可以关闭</p>
  </div>
</div>

// JS部分
var app = new Vue({
 el: '#app',
 data: {
  show: false
 },
methods: {
 handleClose() {
  this.show = false;
 }
}
})

Vue.directive('clickoutside', {
 bind: function(el, binding, vode) {
  function documentHandler (e) {
   if (el.contains(e.target)) {
    return false
   }
   if (binding.expression) {
    binding.value(e)
   }
  }
  el.__vueClickOutSide__ = documentHandler
  document.addEventListener('click', documentHandler)
 },
 unbind: function(el, binding) {
  document.removeEventListener('click', el.__vueClickOutSide__)
  delete el.__vueClickOutSide__
 }
})

要在document上绑定click事件,所以在bind钩子内声明了一个函数documentHandler,并将它作为句柄定在document的click事件上。documentHandler函数做了两个判断,第一个是判断点击的区域是否是指令所在的元素内部,如果是,就跑出函数,不信下继续执行

contains方法是用来判断元素A是否包含了元素 B,包含返回true,不包含返回false

// HTML
<div id="parent">
 父元素
 <div id="children">子元素</div>
</div>
// JS
var a = doucment.getElemengById('parent')
var b = doucment.getElemengById('children')
console.log(A.contains(B)) // true
console.log(B.contains(A)) // false

第二个判断是当前 的指令v-clickoutside有没有写表达式,在该自定义指令中,表达 式应该是第一个函数 ,在过滤了内部元素后,点击外面任何区域应该招待用户表达 式中的函数 ,所以binding.value就用来执行上下文methods中指定的函数的

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
html数组字符串拼接的最快方法
Sep 16 Javascript
JavaScript 学习笔记(十三)Dom创建表格
Jan 21 Javascript
jquery post方式传递多个参数值后台以数组的方式进行接收
Jan 11 Javascript
jquery禁用右键单击功能屏蔽F5刷新
Mar 17 Javascript
JS 新增Cookie 取cookie值 删除cookie 举例详解
Oct 10 Javascript
HTML,CSS,JavaScript速查表推荐
Dec 02 Javascript
Javascript 6里的4个新语法
Aug 25 Javascript
阿里云ecs服务器中安装部署node.js的步骤
Oct 08 Javascript
vue router嵌套路由在history模式下刷新无法渲染页面问题的解决方法
Jan 25 Javascript
Angular ng-animate和ng-cookies用法详解
Apr 18 Javascript
小程序和web画三角形实现解析
Sep 02 Javascript
JS数组进阶示例【数组的几种函数用法】
Jan 16 Javascript
原生js实现仿window10系统日历效果的实例
Oct 31 #Javascript
ES6使用Set数据结构实现数组的交集、并集、差集功能示例
Oct 31 #Javascript
Vue实战之vue登录验证的实现代码
Oct 31 #Javascript
jQuery ajax读取本地json文件的实例
Oct 31 #jQuery
ES6解构赋值的功能与用途实例分析
Oct 31 #Javascript
js原生日历的实例(推荐)
Oct 31 #Javascript
CheckBox多选取值及判断CheckBox选中是否为空的实例
Oct 31 #Javascript
You might like
人族 Terran 魔法与科技
2020/03/14 星际争霸
PHP屏蔽蜘蛛访问代码及常用搜索引擎的HTTP_USER_AGENT
2013/03/06 PHP
解决yii2左侧菜单子级无法高亮问题的方法
2016/05/08 PHP
PHP实现的DES加密解密类定义与用法示例
2020/11/02 PHP
javascript实现的像java、c#之类的sleep暂停的函数代码
2010/03/04 Javascript
基于jquery的tab切换 js原理
2010/04/01 Javascript
编写自己的jQuery插件简单实现代码
2011/04/19 Javascript
借助FileReader实现将文件编码为Base64后通过AJAX上传
2015/12/24 Javascript
JavaScript实现图片滑动切换的代码示例分享
2016/03/06 Javascript
原生JS封装ajax 传json,str,excel文件上传提交表单(推荐)
2016/06/21 Javascript
基于JS+Canves实现点击按钮水波纹效果
2016/09/15 Javascript
jQuery得到多个值只能用取Class ,不能用取ID的方法
2016/12/04 Javascript
jQuery点击弹出层弹出模态框点击模态框消失代码分享
2017/01/21 Javascript
Angular4项目中添加i18n国际化插件ngx-translate的步骤详解
2017/07/02 Javascript
基于rem的移动端响应式适配方案(详解)
2017/07/07 Javascript
理解nodejs的stream和pipe机制的原理和实现
2017/08/12 NodeJs
Vue数据驱动表单渲染,轻松搞定form表单
2019/07/19 Javascript
操作按钮悬浮固定在微信小程序底部的实现代码
2019/08/02 Javascript
JS实现排行榜文字向上滚动轮播效果
2019/11/26 Javascript
vue项目中极验验证的使用代码示例
2019/12/03 Javascript
微信小程序之导航滑块视图容器功能的实现代码(简单两步)
2020/06/19 Javascript
Antd下拉选择,自动匹配功能的实现
2020/10/24 Javascript
js实现验证码干扰(静态)
2021/02/22 Javascript
[46:57]EG vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
基于Python开发chrome插件的方法分析
2018/07/07 Python
Python中三元表达式的几种写法介绍
2019/03/04 Python
python实现控制电脑鼠标和键盘,登录QQ的方法示例
2019/07/06 Python
python openvc 裁剪、剪切图片 提取图片的行和列
2019/09/19 Python
使用python实现希尔、计数、基数基础排序的代码
2019/12/25 Python
CSS3 三维变形实现立体方块特效源码
2016/12/15 HTML / CSS
CSS3实现的炫酷菜单代码分享
2015/03/12 HTML / CSS
Java Servlet的主要功能和作用是什么
2014/02/14 面试题
关于工资低的辞职信
2014/01/14 职场文书
幼儿园中班教学反思
2014/02/10 职场文书
农村婚庆司仪主持词
2014/03/15 职场文书
使用python生成大量数据写入es数据库并查询操作(2)
2022/09/23 Python