本文承接上文,继续对Vue的指令进行介绍,建议读者先阅读上篇文章,以免有不解之处。前文请参考“Vue学习——指令(二)”
内置指令
v-on
v-on指令用于监听DOM事件,并在触发时运行一些JavaScript代码。v-on指令表达式可以是一段JavaScrip代码,也可以是一个方法的名字或者方法调用语句。
代码示例如下
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<p>
<!-- click 事件直接使用JavaScript语句 -->
<button v-on:click="count += 1">Add 1</button>
<span>count: {{count}}</span>
</p>
<p>
<!-- click 事件直接绑定一个方法 -->
<button v-on:click="greet">Greet</button>
<!-- 缩写语法 -->
<button @click="greet">Greet</button>
</p>
<p>
<!-- click 事件使用内联语句调用方法 -->
<button v-on:click="say('Hi')">Hi</button>
</p>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
count: 0,
message: 'Hello!'
},
// 在选项对象的methods属性对象中定义方法
methods: {
greet: function() {
// 方法内this指向vm
alert(this.message)
},
// 对象方法的简写语法
say(msg) {
alert(msg)
}
}
})
</script>
</body>
</html>
要说明的是:
- 方法是在选项对象的methods属性中定义的,该属性是一个对象属性。在methods属性中定义的方法,可以直接通过Vue实例来访问。
本例可以在Chrome浏览器控制台窗口中以如下形式访问greet()和say()方法
vm.greet()
vm.say("John")
- 注意:一定不要使用箭头函数来定义method方法(如plus:() => this.a++)。因为箭头函数绑定的是父级作用域的上下文,所以this将不会按照期望指向Vue实例,this.a将是undefined。
虽然v-on指令的表达式中可以直接书写JavaScript语句,但在实际开发中,由于事件处理逻辑通常比较复杂,所以通常并不使用这种方式。
在页面渲染的结果中,并不会在v-on指令所在的元素上出现对应的JavaScript事件属性。
渲染结果如下图所示:
- 当Vue实例销毁时,所有的事件处理器都会被自动删除,所以无需担心如何清理它们。
如果在事件绑定的方法中需要访问原始的DOM事件,可以使用特殊变量$event把它传入方法。我们知道,在单击链接的时候,会跳转到链接指向的页面,然而有时候会根据某个条件是否达成来决定是否跳转,如果条件不满足,这时会调用事件对象的preventDefault()方法来阻止跳转。在使用v-on指令绑定事件处理器时,就可以使用$event传入原始的DOM事件对象,然后在事件处理器方法中访问原生的事件对象。
代码示例如下:
<a href="/login" v-on:click="login($event)">登陆</a>
<!-- 省略非关键代码 -->
methods: {
login(event) {
// ...
event.preventDefault()
}
}
上述代码也可以使用事件修饰符.prevent来实现相同的功能。
此外,在事件方法中如果要访问事件绑定的原始DOM元素节点对象,可以调用event.currentTarget来得到。
1. 事件修饰符
在事件处理程序中调用event.preventDefault()或event.stopPropagation()是非常常见的需求,为了解决这个问题,Vue.js提供了事件修饰符,让我们可以专注于纯粹的数据逻辑,而不需要去考虑如何处理DOM事件细节。
修饰符是由圆点(.)开头的指令后缀来表示的,紧接在事件名称后书写。针对v-on指令,Vue提供了以下的修饰符:
- .stop: 调用event.stopPropagation()
- .prevent: 调用event.preventDefault()
- .capture: 添加事件监听器时使用capture模式
- .self: 只当事件是从侦听器绑定的元素本身触发时才触发回调
- .{keyCode | keyAlias}: 只当事件是从特定按键触发时才触发回调
- .native: 监听组件根元素的原生事件
- .once: 只触发一次回调
- .left: 只当按鼠标左键时触发
- .right: 只当按鼠标右键时触发
- .middle: 只当按鼠标中键时触发
- .passive: 以{passive: true} 模式添加侦听器
针对前面调用event.preventDefault()方法来阻止默认的链接跳转行为的需求,使用事件修饰符就可以轻松实现相同的功能。代码 示例如下
<a href="/login" v-on:click.prevent="login">登陆</a>
<!-- 省略非关键代码 -->
methods: {
login(event) {
// ...
}
}
下面来看上述部分事件修饰符的用法:
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重新加载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在该事件处理函数中处理,然后交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在event.target是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 单击事件处理函数将只执行一次 -->
<a v-on:click.once="doThis"></a>
要说明的是:
- DOM事件规范支持两种事件模型,即捕获型事件和冒泡型事件,捕获型事件从最外层的对象(大部分兼容标准的浏览器使用window对象作为最外层对象)开始,直到引发事件的对象;冒泡型事件从引发事件的对象开始,一直向上传播,直到最外层的对象结束。任何发生在DOM事件模型中的事件,首先进入捕获阶段,直到达到目标对象,再进入冒泡阶段。v-on指令提供的.stop和.capture修饰符即与此有关,所以了解JavaScript的DOM事件模型,就很容易理解这两个修饰符的作用。
- 修饰符可以串联在一起使用,但顺序很重要。例如,使用v-on:click.prevent.self会阻止所有的单击,而v-on:click.self.prevent只会阻止对元素自身的单击。
- 如果某个事件只需要响应一次,可以使用.once修饰符。
2. 按键修饰符
在监听键盘事件时,经常需要检查详细的按钮,为此,可以在v-on监听键盘事件时添加按钮修饰符。
<!-- 只有在按键是回车键时调用submit()方法 -->
<input v-on:keyup.enter="submit">
<!-- 使用回车键的按键码 -->
<input v-on:keyup.13="submit">
为了在必要的情况下支持旧的浏览器,Vue提供了绝大多数常用的按键码的别名:
- .enter
- .tab
- .delete(捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
此外,Vue还在2.1.0版本中新增了如下的系统修饰键,用来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器:
- .ctrl
- .alt
- .shift
- .meta
在不同的系统下,按键对应有所区别。在Mac系统键盘上,meta对应command键(⌘);在Windows系统键盘上,meta对应Windows徽标键(⊞);在Sun操作系统键盘上,meta对应实心宝石键(♦︎)。
<!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
- 注意:修饰键与常规按键并不相同,在和keyup事件一起使用时,事件触发时修饰键必须处于按下状态。例如下面的代码:
<input @keyup.ctrl.67="doSomething">
当同时按下Ctrl + C时,doSomething()方法并不会被调用,只有在按住Ctrl键的情况下释放字母键c才能触发doSomething()方法的调用。要想在同时按下Ctrl+某个键时触发keyup.ctrl,那么需要使用Ctrl的虚拟键代码17来代替Ctrl修饰键。如下:
<input @keyup.17.67="doSomething">
3. .exact修饰符
.exact修饰符是2.5.0版本中新增的,用于精确控制系统修饰符组合触发的事件。
<!-- 即使同时按下Alt或Shift键,也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 只有在按住Ctrl建而不按其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 只有在没有按下系统修饰键时才会触发 -->
<button @click.exact="onClick">A</button>
4. 鼠标按键
在2.2.0版本中新增了如下鼠标按钮修饰符,分别对应鼠标的左键,右键,中键。
- .left
- .right
- .middle
<!-- 下面的代码只有在鼠标右键单击时才会触发 -->
<input @click.right="doSomething">
v-text
v-text元素用于更新元素的文本内容。
代码示例如下:
<span v-text="message"></span>
<!-- 等价于
<span v-text>{{message}}</span>
-->
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello!'
}
})
</script>
渲染结果如下:
<span>Hello!</span>
如果只是更新部分文本内容,那么还是用{{message}}插值形式。
v-html
v-html指令用于更新元素的innerHTML,该部分内容作为普通的HTML代码插入,不会作为Vue模版进行编译。
代码示例如下:
<div v-html="hElt"></div>
<script>
var vm = new Vue({
el: '#app',
data: {
hElt: '<h1>Hello</h1>'
}
})
</script>
- 注意:在网站上动态渲染任意的HTML是非常危险的,因为很容易导致XSS攻击。切记,只在可信的内容上使用v-html,永远不要在用户提交的内容上使用v-html。
v-once
v-once指令可以让元素或组件只渲染一次,该指令不需要表达式。之后再次渲染时,元素/组件及其所有的子节点将被视为静态内容并跳过,这可以用于优化更新性能。
代码示例如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
a {
margin: 20px;
}
</style>
</head>
<body>
<div id="app">
<h1>{{title}}</h1>
<a v-for="nav in navs" href="nav.url" v-once>{{nav.name}}</a>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
title: 'v-once指令的用法',
navs: [
{name: '首页', url: '/home'},
{name: '新闻', url: '/news'},
{name: '视频', url: '/video'}
]
}
})
</script>
</body>
</html>
这时,在浏览器上看到的渲染结果并没有什么特殊之处,我们可以通过浏览器的Console窗口,输入下面的语句:
vm.navs.push({name: '论坛', url: '/bbs'})
这个语句执行后,我们发现页面并没有任何变化,这就是v-once指令的作用,只渲染一次,渲染结果在之后将作为静态内容而存在。
v-pre
v-pre指令也不需要表达式,用于跳过这个元素和它的子元素的编译过程。v-pre指令可以用来显示原始Mustache标签。对于大量没有指令的节点使用v-pre指令可以加快编译速度。
代码示例如下:
<h1 v-pre>{{message}}</h1>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello'
}
})
</script>
渲染结果为{{message}}。
v-cloak
v-cloak指令也不需要表达式,这个指令保持在元素上直到关联实例编译结束,编译结束后该指令被移除。当和CSS规则如[v-cloak]{display:none}一起使用时,这个指令可以隐藏未编译的Mustache标签直到实例准备完毕。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style>
[v-cloak] {
display: none;
}
</style>
</head>
<body>
<div id="app">
<h1 v-cloak>{{message}}</h1>
</div>
<script src="vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Hello'
}
})
</script>
</body>
</html>
浏览器在加载页面时,如果网速较慢或者页面较大,那么浏览器在构造完DOM树后会在页面中直接显示{{message}}字样,直到Vue的JS文件加载完毕,Vue实例创建、模版编译后,{{message}}才会被替换为数据对象中的内容。这个过程中,页面是会有闪烁的,这给用户的体验不好。
但是如果加了上述CSS规则:[v-cloak]{display: none},配合v-cloak指令一起使用,就可以解决这个问题了。
在Vue.js独立版本的页面开发中,使用v-cloak解决初始化慢所导致的页面闪烁是非常有效的。但是在较大的项目中,由于都是采用模块化的开发,项目的主页面只有一个空的div元素,剩下的内容都是由路由去挂载不同的组件来完成的,也就没必要使用v-cloak指令了。
v-slot
v-slot指令用于提供命名的插槽或需要接受prop的插槽,这部分内容会在后续介绍插槽时进行介绍。
由于篇幅有限,本篇文章就先介绍到这里,其余指令将在下篇文章继续介绍。后续更多内容请参考“Vue学习——指令(四)”