Vue 通过自定义指令回顾v-内置指令(小结)


Posted in Javascript onSeptember 03, 2018

Vue.js 的各种指令(Directives)更加方便我们去数据驱动 DOM,例如 v-bind、v-on、v-model、v-if、v-for、v-once 等内置指令,这些指令的职责就是当表达式改变时将某些行为应用到 DOM 上,尽量不去操作增删改 DOM。通过了解如何去自定义指令,可以想象内置指令是如何完成的。

内置指令

指令名称 描述 使用
v-model 绑定数据
v-text 输出文本,不能解析标签
v-html 输出文本,可解析标签 /p>
v-once 只绑定一次数据 {{message}}
v-bind 绑定属性
v-if 控制是否显示容器 值转为布尔为false时 注释该容器,反之显示
v-show 控制是否显容器,改变的时display:none/block
v-for 循环遍历数组、对象 {{val}}
v-cloak 在还没有执行到vue代码的时候隐藏元素,可解决‘闪烁'问题 {{message}}

自定义指令

在需要特殊功能时,使用自定义指令对 DOM 进行底层操作

注册

自定义指令的注册分为全局注册和局部注册,类似组件的注册,只是方法名为 directive,写法如下:

// 全局注册 自定义指令
Vue.directive(‘mydir',{
  // 指令选项
});
// 全局注册 自定义指令函数
Vue.directive('mydir', function () {
 // 这里将会被 `bind` 和 `update` 调用
})
// 局部注册(只针对组件内元素)
export default {
  directives: {
    mydir: {
      // 指令选项
    }
  }
}

需要注意的是:Vue.directive( ) 注册指令要在实例初始化 new Vue( ) 之前才能全局注册指令。定义指令时驼峰式写法会报错,所以一般小写。

指令选项

自定义指令的选项是由几个钩子函数(可选)组成,可以根据需求选择不同的钩子,例如使用全局注册一个指令时:

Vue.directive('mydir', {
 bind: function () {
  // 只调用一次,指令第一次绑定到元素时调用,用于在绑定元素时执行一次的初始化动作。
  },
 update: function () {
  // 第一次是紧跟在 bind 之后调用,获得的参数是绑定的初始值,
  // 之后被绑定元素所在的模板更新时调用,而不论绑定值是否变化,可以忽略不必要的模板更新。  
  }, 
 inserted: function () {
  // 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
  },
 componentUpdated: function () {
  // 被绑定元素所在模板完成一次更新周期时调用。
  },
 unbind: function () {
  // 只调用一次, 指令与元素解绑时调用。
  }
})

以上每个钩子函数都有几个参数可用:

  1. el:指令所绑定的元素,可以用来直接操作 DOM;
  2. binding:包含指令信息的一个对象;
  3. vnode:Vue 编译的生成虚拟节点;
  4. oldVnode:上一次的虚拟节点,仅在update和componentUpdated钩子函数中可用。

示例

// 一个带自定义指令的元素
<div v-mytest:foo.m1.m2="1+1">MyDirective</div>

// 部分 JS 代码
export default {
  directives:{
   mytest: {
    bind: function (el, binding, vnode) {
     console.log(el)
     console.log(binding)
     console.log(vnode)
    }
   }
  }
}

控制台输出截图:

Vue 通过自定义指令回顾v-内置指令(小结)

其中对于 binding 对象输出的属性有:

  1. rawName: "v-mytest:foo.m1.m2" // 自定义指令
  2. name: "mytest" // 指令名称
  3. arg: "foo" // 指令的参数
  4. modifiers: {m1: true, m2: true} // 指令的修饰符
  5. expression: "1+1" // 指令绑定值的字符串形式
  6. value: 2 // 指令的绑定值

v-bind || : 绑定属性

Vue 内置指令 v-bind 用于动态更新 HTML 元素属性,使用 v-bind:someAttr = "someData"或者语法糖 :someAttr = "someData"就可以在 someData 改变时更新绑定的 someAttr 属性。

基本用法

绑定单一的属性值

<a :href="url" rel="external nofollow" rel="external nofollow" :id="linkID">链接</a>

测试 data 如下:

// js
data : {
  url: 'https://www.baidu.com/',
  linkID : 'myid'
}

元素渲染输出:

<a href="https://www.baidu.com/" rel="external nofollow" rel="external nofollow" id="myid">链接</a>

对象语法

v-bind 最常用的是绑定 class 或 style 属性来动态改变样式。例如可以给 :class 设置一个对象来动态切换 class 的值:

<!-- class 绑定 -->
<div :class="{colorRed: isRed}"></div>

当 isRed:true 时渲染输出:

<div class="colorRed"></div>

对象中可以传入多个属性值来动态切换 class:

<!-- class 绑定,传入多个属性 -->
<div :class="{ classA: isA, classB: isB }">

当 isA、isB 变化时 classA、classB 会动态更新,当都为 true 时显然渲染结果为:

<div class="classA classB"></div>

同理对于 style 可以传入对象属性,并且可以使用字符串拼接:

<!-- style 绑定 -->
<div :style="{ fontSize: size + 'px' }"></div>

对于元素中的各个对象可以统一用 v-bind 绑定:

<!-- 绑定一个有属性的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

数组语法

class 可以传入多值,给 :class 绑定一个数组就可以使用 class 列表

<div :class="[activeA, activeB]"></div>

例如当 {activeA: 'class1', activeB: 'class2'} 时渲染结果为:

<div class="class1 class2"></div>

还可以在数组语法中使用三元表达式切换 class,例如:

<div :class="[isA ? activeA : '', activeB]">

在 class 有多个条件时使用三元表达式比较繁琐,可以在数组语法中使用对象语法:

<div :class="[{activeA: isA}, activeB]">

修饰符

v-bind 的修饰符很少,API 中只提供.prop、.camel和.sync,并且多用于组件,使用方式示例:

<!-- 通过 prop 修饰符绑定 DOM 属性 (property) -->
<div v-bind:text-content.prop="text"></div>

<!-- .camel 修饰符(2.1.0+)将 v-bind 属性名称 kebab-case 驼峰化为 camelCase -->
<svg :view-box.camel="viewBox"></svg>

<!-- .sync 修饰符(2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器-->
<text-document v-bind:title.sync="doc.title"></text-document>
<!-- 批量绑定,将 doc 对象中的每一个属性 (如 title) 都作独立的 prop ,各自添加 v-on 监听器-->
<text-document v-bind.sync="doc"></text-document>

v-on || @ 监听事件

v-on 用于动态绑定事件监听器,使用 v-on:someEvent = "someFunction"或者语法糖 @someEvent = "someFunction"就可以监听 someEvent 进行交互。

基本用法

@someEvent 调用的方法名后面可以不跟(),例如:

<a :href="url" rel="external nofollow" rel="external nofollow" :id="linkID">链接</a>
<!-- 监听一个事件 -->
<button @click="changeFun">change button</button>

可以在 methods 中添加函数:

// 部分 JS 代码
methods :{
 changeFun : function () {
  this.linkID = 'changeID' // 指向当前组件本身
 }
}

点击 button 按钮后 a 元素的 id 改变:

<a href="https://www.baidu.com/" rel="external nofollow" rel="external nofollow" id="changeID">链接</a>

当然 v-on 还可以使用对象语法监听多个事件:

<!-- v2.4.0+ -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>

对于在 HTML 元素上监听的事件,当 ViewModel 销毁时,所有的事件处理器会自动删除,无需自己清理。

修饰符

Vue 可以将原生事件对象参数 event 传入事件方法中,并提供了特殊变量$event用来访问元素 DOM 事件。此外可以通过一些事件修饰符来实现特定的事件,如 .stop、.prevent、.capture、.once 等,常用的使用示例:

<!-- 停止单击事件冒泡,调用 event.stopPropagation()-->
<button @click.stop="doThis"></button>

<!-- 阻止默认行为,调用 event.preventDefault() -->
<button @submit.prevent="doThis"></button>

<!-- 添加事件侦听器时使用 capture 事件捕获模式 -->
<button @click.capture="doThis"></button>

<!-- 点击回调只会触发一次 -->
<button @click.once="doThis"></button>

<!-- 只当点击鼠标左键时触发(2.2.0) -->
<button @click.left="doThis"></button>

<!-- 串联修饰符 -->
<button @click.stop.prevent="doThis"></button>

此外,v-on 还提供按键修饰符来监听键盘事件,键值为 .keyCode,常用有.entry、.delete、.tab、.esc、.space、.down等,如下:

<!-- 只有在 `keyCode` 是 5 时调用 `vm.submit()` -->
<input v-on:keyup.5="submit">

<!-- 为重要的 keyCode 如 enter 提供别名-->
<input v-on:keyup.enter="submit">

<!-- 缩写语法 -->
<input @keyup.enter="submit">

此外还有系统修饰符监听键盘事件,不同的系统其键盘/系统修饰符不一样。这些按键修饰符可以任意组合使用。

v-if、v-show 条件渲染

条件渲染 v-if 根据表达式的值的真假条件渲染元素,在表达式为真时渲染,为假时移除。

<p v-if="status === 1">当 status 为 1 时显示此行</p>

<p v-else-if="status === 1">当 status 为 2 时显示此行</p>

<p v-else>其它情况默认显示此行</p>

v-show 也是条件渲染,但只切换元素的 CSS 属性 display,无论条件真假都会被编译,相比于 v-if 更适用于频繁切换场景。

<p v-show="status === 1">当 status 为 1 时显示此行</p>

当 data: {status: 2} 时隐藏,但依旧会被编译,渲染结果为:

<p style="display: none;">当 status 为 1 时显示此行</p>

显然在 Vue.js 内置的 <template> 元素上可以使用 v-if,但不能使用 v-show,可以思考下为什么。

v-for 列表渲染

列表渲染指令 v-for 常用于数组遍历或枚举一个对象的循环显示,必须结合 in 使用特定语法 alias in expression 为当前遍历的元素提供别名:

<!-- 遍历一个数组 -->
<div v-for="item in items">{{ item.text }}</div>

<!-- 提供第二个的参数为数组的索引 -->
<div v-for="(item, index) in items">{{ index }} - {{ item.text }}</div>

<!-- 遍历对象属性 -->
<div v-for="value in object">{{ value }}</div>

<!-- 提供第二个可选的参数:对象的键名 -->
<div v-for="(value, key) in object">{{ key }}: {{ value }}</div>

<!-- 提供第三个的可选参数:对象的索引 -->
<div v-for="(value, key, index) in object">{{ index }}. {{ key }}: {{ value }}</div>

可以用 of 替代 in 作为分隔符

当 v-for 和 v-if 在同一节点一起使用时,v-for 的优先级比 v-if 更高。

v-model 表单控件双向绑定

v-model 其实也是一个特殊的语法糖,其实实现的数据双向绑定也可用v-bind和v-on实现,但v-model在不同表单上会有更加智能的处理。

文本框

经典的使用案例是对<input>、<textarea>文本框的双向数据绑定:

<!-- 输入框 -->
<input type="text" v-model="message" placeholder="edit me">
<!-- 文本域 -->
<textarea v-model="message" placeholder="edit me"></textarea>
<!-- 实时更新 -->
<p>Message is: {{ message }}</p>

动态选择

对于单选按钮,复选框及选择框的选项,v-model配合 Vue 实例的数据作为value属性值实现不同效果,即会忽略所有表单元素的 value、checked、selected 特性的值。

<!--单选按钮的互斥效果-->
<div id="example-radio">
 <input type="radio" id="one" value="One" v-model="picked">
 <label for="one">One</label>
 
 <input type="radio" id="two" value="Two" v-model="picked">
 <label for="two">Two</label>
 
 <!-- picked 显示的是 value 的值 -->
 <p>Picked: {{ picked }}</p>
</div>

<!--多选按钮-->
<div id='example-checkbox'>
 <input type="checkbox" id="one" value="One" v-model="checkedNames">
 <label for="jack">Jack</label>
 <input type="checkbox" id="two" value="Two" v-model="checkedNames">
 <label for="john">John</label>

  <!-- Checked 显示的是 value 组成的数组 -->
 <p>Checked: {{ checkedNames }}</p>
</div>

修饰符

v-model的修饰符的使用限制在<input>、<select>、<textarea> 和组件。

  1. .lazy - 取代 input 监听 change 事件
  2. .number - 输入字符串转为数字
  3. .trim - 输入首尾空格过滤

v-pre、v-cloak、v-once

这三个指令的共同点是无需表达式,用法如下:

<!-- 不显示未编译的标签直到实例初始化完 -->
<div v-cloak>{{ message }}</div>
<!-- 需要配合 CSS 隐藏样式 [v-cloak]{ display: none;}-->

<!-- 只渲染一次,随后的渲染将被视为静态内容并跳过 -->
<div v-once>{{ message }}</div>

<!-- 不会被编译,直接显示显示原始{{ }}标签 -->
<div v-pre>{{ message }}</div>

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

Javascript 相关文章推荐
不间断滚动JS打包类,基本可以实现所有的滚动效果,太强了
Dec 08 Javascript
利用Ext Js生成动态树实例代码
Sep 08 Javascript
javascript判断用户浏览器插件安装情况的代码
Jan 01 Javascript
EasyUI 中 MenuButton 的使用方法
Jul 14 Javascript
js(JavaScript)实现TAB标签切换效果的简单实例
Feb 26 Javascript
JS判断网页广告是否被浏览器拦截过滤的代码
Apr 05 Javascript
JavaScript中instanceof运算符的使用示例
Jun 08 Javascript
jquery点击切换背景色的简单实例
Aug 25 Javascript
浅谈jquery拼接字符串效率比较高的方法
Feb 22 Javascript
bootstrap table实现合并单元格效果
Dec 24 Javascript
JQuery常用简单动画操作方法回顾与总结
Dec 07 jQuery
jQuery列表动态增加和删除的实现方法
Nov 05 jQuery
JavaScript日期工具类DateUtils定义与用法示例
Sep 03 #Javascript
Angular5中状态管理的实现
Sep 03 #Javascript
JavaScript创建对象方法实例小结
Sep 03 #Javascript
vue自定义底部导航栏Tabbar的实现代码
Sep 03 #Javascript
解决vue单页路由跳转后scrollTop的问题
Sep 03 #Javascript
webpack4 SCSS提取和懒加载的示例
Sep 03 #Javascript
vue自定v-model实现表单数据双向绑定问题
Sep 03 #Javascript
You might like
php时区转换转换函数
2014/01/07 PHP
PHP实现的迪科斯彻(Dijkstra)最短路径算法实例
2017/09/16 PHP
ASP 过滤数组重复数据函数(加强版)
2010/05/31 Javascript
jquery调用asp.net 页面后台的实现代码
2011/04/27 Javascript
JavaScript高级程序设计 阅读笔记(十三) js定义类或对象
2012/08/14 Javascript
有关json_decode乱码及NULL的问题
2015/10/13 Javascript
jQuery EasyUI之DataGrid使用实例详解
2016/01/04 Javascript
jquery-mobile表单的创建方法详解
2016/11/23 Javascript
基于Bootstrap框架实现图片切换
2017/03/10 Javascript
微信小程序 在线支付功能的实现
2017/03/14 Javascript
深入探究AngularJs之$scope对象(作用域)
2017/07/20 Javascript
微信小程序实现发红包功能
2018/07/11 Javascript
微信头像地址失效踩坑记附带解决方案
2019/09/23 Javascript
Vue+elementUI实现多图片上传与回显功能(含回显后继续上传或删除)
2020/03/23 Javascript
js 执行上下文和作用域的相关总结
2021/02/08 Javascript
Python中实现结构相似的函数调用方法
2015/03/10 Python
python中Apriori算法实现讲解
2017/12/10 Python
django admin后台添加导出excel功能示例代码
2019/05/15 Python
使用OpCode绕过Python沙箱的方法详解
2019/09/03 Python
python构建指数平滑预测模型示例
2019/11/21 Python
python输出pdf文档的实例
2020/02/13 Python
django中url映射规则和服务端响应顺序的实现
2020/04/02 Python
python中sort sorted reverse reversed函数的区别说明
2020/05/11 Python
linux面试题参考答案(11)
2012/05/01 面试题
校园之声广播稿
2014/01/31 职场文书
秋季运动会广播稿
2014/02/22 职场文书
信息学院毕业生自荐信范文
2014/03/04 职场文书
没有孩子的离婚协议书怎么写
2014/09/17 职场文书
民主评议政风行风整改方案
2014/09/17 职场文书
2014年大学生党员评议表自我评价
2014/09/20 职场文书
2015年社区综治工作总结
2015/04/21 职场文书
机关单位保密工作责任书
2015/05/11 职场文书
MySQL的存储函数与存储过程的区别解析
2022/04/08 MySQL
Python捕获、播放和保存摄像头视频并提高视频清晰度和对比度
2022/04/14 Python
Win10 Anaconda安装python-pcl
2022/04/29 Servers
vscode远程免密登入Linux服务器的配置方法
2022/06/28 Servers