Vue学习——指令(三)

本文承接上文,继续对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>

要说明的是:

  1. 方法是在选项对象的methods属性中定义的,该属性是一个对象属性。在methods属性中定义的方法,可以直接通过Vue实例来访问。

本例可以在Chrome浏览器控制台窗口中以如下形式访问greet()和say()方法

vm.greet()
vm.say("John")
  • 注意:一定不要使用箭头函数来定义method方法(如plus:() => this.a++)。因为箭头函数绑定的是父级作用域的上下文,所以this将不会按照期望指向Vue实例,this.a将是undefined。
  1. 虽然v-on指令的表达式中可以直接书写JavaScript语句,但在实际开发中,由于事件处理逻辑通常比较复杂,所以通常并不使用这种方式。

  2. 在页面渲染的结果中,并不会在v-on指令所在的元素上出现对应的JavaScript事件属性。

渲染结果如下图所示:


image
  1. 当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>

要说明的是:

  1. DOM事件规范支持两种事件模型,即捕获型事件和冒泡型事件,捕获型事件从最外层的对象(大部分兼容标准的浏览器使用window对象作为最外层对象)开始,直到引发事件的对象;冒泡型事件从引发事件的对象开始,一直向上传播,直到最外层的对象结束。任何发生在DOM事件模型中的事件,首先进入捕获阶段,直到达到目标对象,再进入冒泡阶段。v-on指令提供的.stop和.capture修饰符即与此有关,所以了解JavaScript的DOM事件模型,就很容易理解这两个修饰符的作用。
  2. 修饰符可以串联在一起使用,但顺序很重要。例如,使用v-on:click.prevent.self会阻止所有的单击,而v-on:click.self.prevent只会阻止对元素自身的单击。
  3. 如果某个事件只需要响应一次,可以使用.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学习——指令(四)”

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,657评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,889评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,057评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,509评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,562评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,443评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,251评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,129评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,561评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,779评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,902评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,621评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,220评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,838评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,971评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,025评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,843评论 2 354