Vue学习——指令(二)

本文承接上文,继续对Vue的指令进行介绍,建议读者先阅读上篇文章,以免有不解之处。前文请参考“Vue学习——指令(一)”

内置指令

v-for

3. 过滤和排序

有时想要显示一个数组经过过滤或排序后的版本,但不实际改变或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数据。

代码示例如下

<li v-for="n in evenNumbers">{{n}}</li>

data: {
    numbers: [1, 2, 3, 4, 5]
},
computed: {
    evenNumbers: function() {
        return this.numbers.filter(function(number) {
            return number % 2 === 0
        })
    }
}

在计算属性不适用的情况下(例如,在嵌套v-for循环中),也可以使用一个方法。

<li v-for="n in even(numbers)">{{n}}</li>

data: {
    numbers: [1, 2, 3, 4, 5]
},
computed: {
    even: function(numbers) {
        return this.numbers.filter(function(number) {
            return number % 2 === 0
        })
    }
}
4. 遍历整数

v-for指令也可以接受整数。在这种情况下,它会把模版重复对应次数。

代码示例如下

<div>
    <span v-for="n in 10">{{n}}</span>
</div>

输出内容如下图所示:


image
5. v-for遍历对象

遍历对象的语法形式和遍历数组是一样的,即value in object,其中object是被迭代的对象,value是被迭代的对象属性的别名。

代码示例如下

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

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    book: {
                        title: 'Book',
                        author: 'John',
                        isbn: '1234567890'
                    }
                }
            })
        </script>
    </body>
</html>

渲染后的结果如下图所示:


image

如果要获取对象的属性名,可以使用可选的属性名参数(也就是键名)作为第二个参数。

修改代码中的<li>元素

<li v-for="(value, key) in book">{{key}} : {{value}}</li>

遍历对象的表达式中还可以使用第三个参数作为索引

<li v-for="(value, key, index) in book">{{index}}. {{key}} : {{value}}</li>

最终的渲染结果如下图所示:


image
6. 对象更新检测

由于JavaScript的限制,Vue不能检测对象属性的添加和删除。要解决这个问题,只能使用Vue全局的set()和delete()方法,或者通过Vue实例的set()和delete()方法来执行属性的操作,并触发视图更新。

代码示例如下

// 使用Vue的全局set()方法添加属性
Vue.set(vm.book, 'publishDate', '2020-8-27')
// 使用Vue实例的$set()方法添加属性
vm.$set(vm.book, 'publishDate', '2020-8-27')

// 使用Vue的全局delete()方法删除属性
Vue.delete(vm.book, 'isbn')
// 使用Vue实例的$delete()方法删除属性
vm.$delete(vm.book, 'isbn')
7. 在<template>上使用v-for

类似于v-show和v-if,也可以利用带有v-for指令的<template>来循环渲染一段包含多个元素的内容。

代码示例如下

<ul>
    <template v-for="item in items">
        <li>{{item.msg}}<li>
        <li>{{item.code}}<li>
    </template>
</ul>
8. key属性

先来看这段代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <p>
                ID: <input type="text" v-model="bookId">
                书名: <input type="text" v-model="title">
                <button v-on:click="add()">添加</button>
            </p>
            <p v-for="book in books">
                <input type="checkbox">
                <span>ID: {{book.id}} , 书名: {{book.title}}</span>
            </p>
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    bookId: '',
                    title: '',
                    books: [
                        {id: 1, title: 'book1'},
                        {id: 2, title: 'book2'},
                        {id: 3, title: 'book3'}
                    ]
                },
                methods: {
                    add() {
                        this.books.unshift({
                            id : this.bookId,
                            title : this.title
                        })
                        this.bookId = '',
                        this.title = ''
                    }
                }
            })
        </script>
    </body>
</html>

这段代码预先定义了一个books数组对象,通过v-for指令遍历该数组,同时提供了两个输入框,在用户输入了图书的ID和书名后,向数组中添加一个新的图书对象。我们使用的是数组的unshift()方法,该方法向数组的开头添加一个或多个元素。

使用浏览器打开该页面,将显示如下画面:


image

向列表中输入内容并点击添加按钮,画面更新如下所示:


image

这时我们发现一个问题,之前选中的id为1的图书,在我们添加新图书后,选中指向不正确。

而产生这个问题的原因是:当Vue正在更新使用v-for渲染的元素列表时,它默认使用“就地更新”策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。

在本例中,当勾选id:1的书籍时,指令只记住了勾选的数组下标为0,当数组更新后,虽然数组长度发生了变化,但是指令只记得你当时勾选的数组下标,于是添加新元素后,显示的勾选就变成了id:5的书籍。

为了给Vue一个提示,以便它能够跟踪每个节点的身份,从而重用和重新排序现有元素,需要为列表的每一项提供一个唯一key属性。key属性的类型只能是string或者number类型。

修改上述代码,在v-for指令后添加key属性

<p v-for="book in books" v-bind:key="book.id">

在浏览器中刷新页面,再次执行之前的操作,结果显示将如下图所示:


image
9. v-for-v-if

当v-for与v-if一起使用时,v-for的优先级比v-if要高,这意味着v-if将分别重复运行于每个v-for循环中。如果在渲染一个列表时,对列表的某些项需要根据条件来判断是否渲染,那么就可以使将v-for和v-if联合一起使用。

代码示例如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <h1>已完成的工作计划</h1>
            <ul>
                <li v-for="plan in plans" v-if="plan.isComplete">
                    {{plan.content}}
                </li>
            </ul>
            <h1>未完成的工作计划</h1>
            <ul>
                <li v-for="plan in plans" v-if="!plan.isComplete">
                    {{plan.content}}
                </li>
            </ul>
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    plans: [
                        {content: 'planA', isComplete: false},
                        {content: 'planB', isComplete: true},
                        {content: 'planC', isComplete: false},
                        {content: 'planD', isComplete: true},
                        {content: 'planE', isComplete: false}
                    ]
                }
            })
        </script>
    </body>
</html>

渲染结果如下图所示:


image

如果仅仅是要根据某个条件的真假来决定是否跳过整个循环的执行,那么可以将v-if置于外层元素(或<template>)上

<ul v-if="plans.length">
    <li v-for="plan in plans">
        {{plan.content}}
    </li>
</ul>
<p v-else>没有工作计划</p>

v-bind

v-bind指令在之前已经进行了初步介绍,主要用于响应更新HTML元素的属性,将一个或多个属性或者一个组件的prop动态绑定到表达式。

代码示例如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <!-- 绑定一个属性 -->
            <img v-bind:src="imgSrc">

            <!-- 缩写 -->
            <img :src="imgSrc">

            <!-- 动态属性名(2.6.0+) -->
            <a v-bind:[attrname]="url">链接</a>

            <!-- 内联字符窜拼接 -->
            <img :src="'images/' + fileName">
        </div>

        <script src="vue.js"></script>
        <script>
            var vm = new Vue({
                el: '#app',
                data: {
                    attrname: 'href',
                    url: 'http://www.sina.com.cn/',
                    imgSrc: 'images/bg.jpg',
                    fileName: 'bg.jpg'
                }
            })
        </script>
    </body>
</html>

v-bind指令还可以直接绑定一个有属性的对象

<div id="app">
    <form v-bind="formObj">
        <input type="text">
    </form>
</div>

<script src="vue.js"></script>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            formObj: {
                method: 'get',
                action: '#'
            }
        }
    })
</script>

v-model

v-model指令用来在表单<input>、<textarea>及<select>元素上创建双向数据绑定,它会根据控件类型自动选取正确的方法来更新元素。v-model本质上是“语法糖”,它负责监听用户的输入事件以更新数据,并对一些极端场景进行特殊处理。

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J.Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

v-model代码示例如下

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <div id="app">
            <input type="text" v-model="message">
        </div>

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

使用浏览器打开该页面,可以看到文本输入空间中的内容为Hello World,这时在Console窗口中输入以下内容:

vm.message = "Welcome you"

可以看到输入控件中的内容也发生了改变,如下图所示:


image

接下来在输入控件中随意输入些内容,在Console窗口中输入下面的内容:

vm.message

可以看到message的值也发生了变化,如下图所示:


image

关于v-model的用法还有更多内容,不在本文更多赘述了,在后续介绍Vue表单控件时会进行相应的补充。

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

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