Vue学习——指令(一)

概述

指令是带有v-前缀的特殊属性,其值限定为单个表达式。指令的作用是,当表达式的值发生改变时,将其产生的连带影响应用到DOM上。

此外,一些指令还可以带有参数,在指令名称之后以冒号表示。从Vue.js 2.6.0版本开始,指令的参数可以是动态参数,语法为指令:[JavaScript表达式]。

内置指令

Vue.js针对一些常用的页面功能提供了以指令来封装的使用形式,以HTML元素属性的方式使用,这些指令数量并不是很多。

v-show

v-show指令根据表达式的值的真假,来显示或隐藏HTML元素。

代码示例如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-show 指令</title>
    </head>
    <body>
        <div id="app">
            <h1 v-show="yes">Yes!</h1>
            <h1 v-show="no">No!</h1>
            <h1 v-show="age <= 25">Age: {{age}}</h1>
            <h1 v-show="name.indexOf('John') >= 0">Name: {{name}}</h1>
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    yes: true,
                    no: false,
                    age: 18,
                    name: 'Will John'
                }
            })
        </script>
    </body>
</html>

我们用Chrome浏览器打开上述页面,使用开发者工具展开div元素,结果如下图所示:


image

从上图中可以看到,因为数据对象中的no属性为false,因此使用v-show指令计算no表达式的<h1>元素没有显示;其他表达式的值计算都为true,所以这些表达式所在的<h1>元素都正常显示了。

从Chrome浏览器的Elements窗口中可以看到,使用v-show指令,元素本身是要被渲染的,至于显示与否是通过设置css样式属性display来控制的,如果表达式的值计算为false,则设置样式"display: none"。接下来切换到Console窗口,修改age属性的值为28(vm.age = 28),然后切换回Elements窗口,如下图所示:


image

由此可以进一步确认v-show指令是通过css样式属性displa来控制元素的显示与否。

指令都是在某个元素上使用,如果要显示或隐藏多个元素,其实并不需要在每个元素上都使用v-show指令。我们可以使用HTML 5新增的<template>元素来包裹需要切换显示与隐藏的多个元素,然后在<template>元素上使用v-show指令,最终的渲染结果中是不会包含<template>元素的。实际上,<template>元素是被当作一个不可见的包裹元素,主要用于分组的条件判断和列表渲染。

使用<template>标签实现多个元素显示隐藏

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-show 指令</title>
    </head>
    <body>
        <div id="app">
            <template v-show="!isLogin">
                <form>
                    <p>username: <input type="text"></p>
                    <p>password: <input type="password"></p>
                </form>
            </template>
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    isLogin: false
                }
            })
        </script>
    </body>
</html>

渲染结果如图所示:


image

v-if / v-else-if / v-else

v-if、v-else-if、v-else这三个指令用于实现条件判断。

1. v-if

v-if指令根据表达式的值的真假来生成或删除一个元素。

代码示例如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-if 指令</title>
    </head>
    <body>
        <div id="app">
            <h1 v-if="yes">Yes!</h1>
            <h1 v-if="no">No!</h1>
            <h1 v-if="age <= 25">Age: {{age}}</h1>
            <h1 v-if="name.indexOf('John') >= 0">Name: {{name}}</h1>
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    yes: true,
                    no: false,
                    age: 18,
                    name: 'Will John'
                }
            })
        </script>
    </body>
</html>

使用Chrome浏览器打开页面,如下图所示:


image

从上图可以看到,包含no表达式(值为false)的<h1>元素并没有生成,其他表达式的值为true的<h1>元素正常生成了。也就是说,v-if指令在HTML元素的显示与否的实现机制上与v-show指令不同,当表达式的值计算为false时,v-if指令不会创建该元素,只有当表达式的值为true时,v-if指令才会真正创建该元素;而v-show指令不管表达式的值是真是假,元素本身都会被创建。

切换到Console窗口,修改age属性的值为28(vm.age = 28),然后切换回Elements窗口,如下图所示:


image

与v-show指令一样,如果v-if需要控制多个元素的创建或删除,可以用<template>元素来包裹这些元素,然后在<template>元素上使用v-if指令。

一般来说,v-if有更高的切换开销,而v-show有更高的出事渲染开销。因此,如果需要非常频繁地切换元素的显示或隐藏,则使用v-show较好;如果在运行时条件很少改变,则使用v-if较好。

2. v-else-if / v-else

v-else-if指令是在Vue.js 2.1.0版本中新增的,与v-if一起使用,可以实现互斥的条件判断。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <span v-if="score >= 85">优秀</span>
            <span v-else-if="score >= 75">良好</span>
            <span v-else-if="score >= 60">及格</span>
            <span v-else>不及格</span>
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    score: 90
                }
            })
        </script>
    </body>
</html>

当一个条件满足时,后续的条件都不会再判断。

  • 使用时,v-else-if和v-else要紧跟在v-if或v-else-if之后
3. 用key管理可复用的元素

Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染,这么做使Vue渲染效率变得非常高。

不使用key的情况

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>v-if-key</title>
    </head>
    <body>
        <div id="app">
            <template v-if="loginType === 'username'">
                <label>用户名:</label>
                <input placeholder="请输入你的用户名">
            </template>
            <template v-else>
                <label>Email:</label>
                <input placeholder="请输入你的Email">
            </template>
            <p><button v-on:click="changeLoginType">切换登陆方式</button></p>
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    loginType: 'username'
                },
                methods: {
                    changeLoginType() {
                        if (this.loginType === 'username') {
                            this.loginType = "email"
                        } else {
                            this.loginType = "username"
                        }
                    }
                }
            })
        </script>
    </body>
</html>

使用浏览器打开上述页面,初始显示的是用户名输入框,可以在其中任意输入些内容,在点击“切换登陆方式”按钮后,之前输入的内容会被保留下来。如下图所示:


image

image

这是因为在两个模版中使用了相同的<input>元素,Vue为了提高渲染效率,复用了<input>元素,因此,在切换登陆时,<input>不会被替换掉,仅仅是替换了它的placeholder属性。

但有时这并不是我们想要的,我们不希望在Email输入框中看到之前输入的用户名,这时我们可以通过为<input>元素添加一个具有唯一值的key属性,来取消复用。

修改上述代码,为<input>标签添加key属性

<template v-if="loginType === 'username'">
    <label>用户名:</label>
    <input placeholder="请输入你的用户名" key="username-input">
</template>
<template v-else>
    <label>Email:</label>
    <input placeholder="请输入你的Email" key="email-input">
</template>

使用浏览器再次打开该页面,可以发现切换时,输入框会被重新渲染。

v-for

顾名思义,v-for指令就是通过循环的方式来渲染一个列表,循环的对象可以是数组,也可以是一个JavaScript对象。

1. v-for遍历数组

表达式的语法形式为item in times,其中items是源数据数组,而item则是被迭代的数组元素的别名

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <ul>
                <li v-for="book in books">{{book.title}}</li>
            </ul>
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    books: [
                        {title: 'Book1'},
                        {title: 'Book2'},
                        {title: 'Book3'}
                    ]
                }
            })
        </script>
    </body>
</html>

Vue实例的数据对象中定义了一个数组属性books,然后在<li>元素上使用v-for指令遍历该数组,这将循环渲染<li>元素。在v-for块中,可以访问所有父作用域的属性,book是数组中元素的别名,每次循环,book的值都被重置为数组当前索引的值,在<li>元素内部,可以通过Mustache语法来引用该变量值。

最终渲染结果如下图:


image
  • v-for指令的表达式也可以使用of替代in作为分隔符,它更接近JavaScript迭代器的语法,如<div v-for="item of items"></div>

v-for指令的表达式还支持一个可选的参数作为当前项的索引。

修改代码中的<li>元素

<li v-for="(book, index) in books">{{index}} - {{book.title}}</li>

多个参数需要放到圆括号中,最后的渲染结果如下图所示:


image
2. 数组更新检测

Vue的核心是数据与视图的双向绑定,为了检测数组中元素的变化,以便能及时将变化反映到视图中,Vue对数组的下列变异方法(mutation method)进行了包裹。

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

我们可以直接使用Chrome浏览器的Console窗口输入下列语句

vm.books.push({title: 'Book4'})

数组中还有一些非变异方法(non-mutating method),如filter()、concat()和slice(),它们不会改变原始数组,而总是返回一个新数组。对于这些方法,要想让Vue帮我们自动更新视图,可以使用新数组来替换原来的数组。

依然是上述代码,在浏览器控制台输入下面的语句

vm.books = vm.books.concat([{title: 'Book5'}, {title: 'Book6'}])

Vue在检测到数组变化时,并不是直接重新渲染整个列表,而是最大化地复用DOM元素,替换的数组中,含有相同元素的项不会被重新渲染,因此可以大胆地使用新数组来替换旧数组,不用担心性能问题。

  • 要注意的是,通过下述方法引起的数组变动,Vue不能检测到
// 通过索引直接设置数组值
vm.books[0] = {title: 'Book'}
// 修改数组的长度
vm.books.length = 1

要解决上述第一类问题,可以采用下面两种方式,这两种方式都可以实现vm.books[0] = {...}相同的效果

// 使用Vue的全局set()方法
Vue.set(vm.books, 0, {title: 'BookA'})
// 使用数组原型的splice()方法
vm.books.splice(0, 1, {title: 'BookB'})

作为替代,也可以使用Vue实例的$set方法,该方法是全局方法Vue.set的一个别名

// 使用Vue实例的$set()方法
vm.$set(vm.books, 0, {title: 'BookC'})

前述第二类问题也是使用数组原型的splice()方法来解决的,代码如下

vm.books.splice(1)

由于篇幅有限,本篇文章就先介绍到这里,v-for的更多用法以及其余指令将在下篇文章继续介绍。后续更多内容请参考“Vue学习——指令(二)”

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

推荐阅读更多精彩内容

  • 本文承接上文,继续对Vue的指令进行介绍,建议读者先阅读上篇文章,以免有不解之处。前文请参考“Vue学习——指令(...
    Tierney_John阅读 297评论 0 0
  • 通过指令实现下拉菜单 下拉菜单在实际应用中很常见,当鼠标移动到某个菜单上时会弹出一个子菜单列表,每个子菜单都是可以...
    Tierney_John阅读 411评论 0 1
  • 本文承接上文,继续对Vue的指令进行介绍,同时也是指令系列的终章。建议读者先阅读上篇文章,以免有不解之处。前文请参...
    Tierney_John阅读 604评论 0 1
  • 本文承接上文,继续对Vue的指令进行介绍,建议读者先阅读上篇文章,以免有不解之处。前文请参考“Vue学习——指令(...
    Tierney_John阅读 422评论 0 0
  • 本文为转载,原文:Vue学习笔记入门篇——安装及常用指令介绍 介绍 Vue.js是当下很火的一个JavaScrip...
    ChainZhang阅读 395评论 0 1