1.1、v-if

在字符串模板中,如 Handlebars ,我们得像这样写一个条件块:

<!-- Handlebars 模板 -->
{{#if ok}}
  <h1>Yes</h1>
{{/if}}

在 Vue.js ,我们使用 v-if 指令实现同样的功能:

<h1 v-if="ok">Yes</h1>

也可以用 v-else 添加一个 “else” 块:

<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>

1.1.1、template v-if

因为 v-if 是一个指令,需要将它添加到一个元素上。但是如果我们想切换多个元素呢?此时我们可以把一个 <template> 元素当做包装元素,并在上面使用 v-if,最终的渲染结果不会包含它。

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

示例:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>条件渲染</title>
    </head>

    <body>
        <div id="app1">
            <p>
                <button type="button" @click="isShow=!isShow">Toggle isShow</button>
            </p>
            <h1 v-if="isShow">Yes</h1>
            <h1 v-else>No</h1>
            
            
            <template v-if="!isShow">
                <p>item1</p><p>item2</p><p>item3</p>
            </template>
            <template v-else>
                <p>item4</p><p>item5</p><p>item6</p>
            </template>
            
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var app1 = new Vue({
                el: "#app1",
                data: {
                    isShow: true
                }
            });
        </script>
    </body>

</html>

结果:

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

切换

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

1.1.2、v-else

可以用 v-else 指令给 v-if 添加一个 “else” 块:

<div v-if="Math.random() > 0.5">
  Sorry
</div>
<div v-else>
  Not sorry
</div>

v-else 元素必须紧跟在 v-if 元素的后面——否则它不能被识别。

1.1.3、v-else-if

2.1.0 新增v-else-if,顾名思义,充当 v-if 的“else-if 块”,可以连续使用:

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

类似于 v-elsev-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

示例:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>条件渲染</title>
    </head>

    <body>
        <div id="app1">
            <div v-if="Math.random() > 0.5">
                Sorry
            </div>
            <div v-else>
                Not sorry
            </div>

            <div v-if="type === 'A'">
                A
            </div>
            <div v-else-if="type === 'B'">
                B
            </div>
            <div v-else-if="type === 'C'">
                C
            </div>
            <div v-else>
                Not A/B/C
            </div>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var app1 = new Vue({
                el: "#app1",
                data: {
                    type:"C"
                }
            });
        </script>
    </body>

</html>

 

结果:

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

1.1.4、用 key 管理可复用的元素

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>

自己动手试一试,在输入框中输入一些文本,然后按下切换按钮:那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder

示例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>条件渲染</title>
    </head>
    <body>
        <div id="app1">
            <template v-if="type==='username'">
                <label>帐号:</label>
                <input placeholder="请输入您的帐号" />
            </template>
            <template v-else>
                <label>邮箱:</label>
                <input placeholder="请输入您的电子邮箱" />
            </template>
            <p>
                <a href="" @click.prevent="type='username'">用户名登录</a> | <a href="" @click.prevent="type='email'">邮箱登录</a> 
            </p>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var app1 = new Vue({
                el: "#app1",
                data: {
                    isShow: true,
                    type: "username"
                }
            });
        </script>
    </body>
</html>

 

结果:

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

点击邮箱登录

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key 属性即可:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

现在,每次切换时,输入框都将被重新渲染。

        <div id="app1">
            <template v-if="type==='username'">
                <label>帐号:</label>
                <input placeholder="请输入您的帐号" key="username"/>
            </template>
            <template v-else>
                <label>邮箱:</label>
                <input placeholder="请输入您的电子邮箱" key="email"/>
            </template>
            <p>
                <a href="" @click.prevent="type='username'">用户名登录</a> | <a href="" @click.prevent="type='email'">邮箱登录</a> 
            </p>
        </div>

注意,<label> 元素仍然会被高效地复用,因为它们没有添加 key 属性。

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

1.1.5、v-show

另一个根据条件展示元素的选项是 v-show 指令。用法大体上一样:

<h1 v-show="ok">Hello!</h1>

不同的是有 v-show 的元素会始终渲染并保持在 DOM 中。v-show 是简单的切换元素的 CSS 属性 display 。

注意 v-show 不支持 <template> 语法。

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

1.2、v-if vs. v-show

v-if 是真实的条件渲染,因为它会确保条件块在切换当中适当地销毁与重建条件块内的事件监听器和子组件。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——在条件第一次变为真时才开始局部编译(编译会被缓存起来)。

相比之下, v-show 简单得多——元素始终被编译并保留,只是简单地基于 CSS 切换。

一般来说, v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换使用 v-show 较好,如果在运行时条件不大可能改变则使用 v-if 较好。

官方文档: http://vuejs.org/guide/conditional.html

二、列表渲染

2.1、v-for

我们用 v-for 指令根据一组数组的选项列表进行渲染。 v-for 指令需要以item in items 形式的特殊语法, items 是源数据数组并且 item 是数组元素迭代的别名。

基本用法

<ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      {message: 'foo' },
      {message: 'Bar' }
    ]
  }
})

结果:

  • Foo
  • Bar

在 v-for 块中,我们拥有对父作用域属性的完全访问权限。 v-for 还支持一个可选的第二个参数为当前项的索引。

<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Parent',
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})

结果:

  • Parent - 0 - Foo
  • Parent - 1 - Bar

你也可以用 of 替代 in 作为分隔符,因为它是最接近 JavaScript 迭代器的语法:

<div v-for="item of items"></div>

2.1.1、Template v-for

如同 v-if 模板,你也可以用带有 v-for 的 <template> 标签来渲染多个元素块。例如:

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider"></li>
  </template>
</ul>

2.1.2、对象迭代 v-for

你也可以用 v-for 通过一个对象的属性来迭代。

<ul id="repeat-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
new Vue({
  el: '#repeat-object',
  data: {
    object: {
      FirstName: 'John',
      LastName: 'Doe',
      Age: 30
    }
  }
})

结果:

  • John
  • Doe
  • 30

你也可以提供第二个的参数为键名:

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

第三个参数为索引:

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

在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。

2.1.3、整数迭代 v-for

v-for 也可以取整数。在这种情况下,它将重复多次模板。

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

结果:

1 2 3 4 5 6 7 8 9 10
 
示例:
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>列表渲染</title>
    </head>

    <body>
        <div id="app1">
            <ul>
                <template v-for="(user,index) in users">
                    <li>{{index+1}} - {{user.name}}</li>
                    <li>
                        <hr/>
                    </li>
                </template>
            </ul>

            <h3>遍历对象中的所有属性value</h3>
            <p v-for="value in product">
                {{value}}
            </p>
            <h3>遍历对象中的所有属性value - key</h3>
            <p v-for="(value,key) in product">
                {{key}} - {{value}}
            </p>

            <h3>遍历对象中的所有属性value - key - index</h3>
            <p v-for="(value,key,index) in product">
                {{index}} - {{key}} - {{value}}
            </p>
            <h3>整数迭代 v-for</h3>
            <span v-for="n in 20">
                {{n}} - 
            </span>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var app1 = new Vue({
                el: "#app1",
                data: {
                    users: [{
                            name: "tom",
                            age: 18
                        },
                        {
                            name: "rose",
                            age: 87
                        },
                        {
                            name: "mark",
                            age: 16
                        }
                    ],
                    product: {
                        name: "苹果",
                        price: 5.8,
                        unit: '千克'
                    }
                }
            });
        </script>
    </body>

</html>
结果:
前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

2.1.4、组件 和 v-for

了解组件相关知识,查看  组件 。Feel free to skip it and come back later.

在自定义组件里,你可以像任何普通元素一样用 v-for 。

<my-component v-for="item in items"></my-component>

然而他不能自动传递数据到组件里,因为组件有自己独立的作用域。为了传递迭代数据到组件里,我们要用 props :

<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index">
</my-component>

不自动注入 item 到组件里的原因是,因为这使得组件会紧密耦合到 v-for 如何运作。在一些情况下,明确数据的来源可以使组件可重用。

下面是一个简单的 todo list 完整的例子:

<div id="todo-list-example">
  <input
    v-model="newTodoText"
    v-on:keyup.enter="addNewTodo"
    placeholder="Add a todo"
  >
  <ul>
    <li
      is="todo-item"
      v-for="(todo, index) in todos"
      v-bind:title="todo"
      v-on:remove="todos.splice(index, 1)"
    ></li>
  </ul>
</div>
Vue.component('todo-item', {
  template: '
    <li>
      {{ title }}
      <button v-on:click="$emit(\'remove\')">X</button>
    </li>',
  props: ['title']
})
new Vue({
  el: '#todo-list-example',
  data: {
    newTodoText: '',
    todos: [
      'Do the dishes',
      'Take out the trash',
      'Mow the lawn'
    ]
  },
  methods: {
    addNewTodo: function () {
      this.todos.push(this.newTodoText)
      this.newTodoText = ''
    }
  }
})

示例:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>列表渲染</title>
    </head>
    <body>
        <div id="app1">
            任务:<input v-model="newTask" @keyup.enter="addNew" placeholder="请输入您要完成的任务" />
            <ul>
                <li is="todoitem" v-for="(task,index) in tasks" :title="task" @remove="removeItem(index)"></li>
            </ul>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            Vue.component("todoitem", {
                template: "<li>{{title}} <button @click='$emit(\"remove\")'>X</button></li>",
                props: ['title']
            });

            var app1 = new Vue({
                el: "#app1",
                data: {
                    newTask: '',
                    tasks: ["买一本书", "给爸妈打电话", "整理自己的硬盘"]
                },
                methods: {
                    addNew: function() {
                        this.tasks.unshift(this.newTask);
                        this.newTask = '';
                    },
                    removeItem: function(index) {
                        if(confirm('确定要移除吗?')) {
                            this.tasks.splice(index, 1);
                        }
                    }
                }
            });
        </script>
    </body>
</html>

结果:

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

2.2、key

当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,而不是移动 DOM 元素来匹配数据项的顺序, Vue 将简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似 Vue 1.x 的track-by="$index" 。

这个默认的模式是有效的,但是只适用于不依赖子组件状态或临时 DOM 状态(例如:表单输入值)的列表渲染输出。

为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。理想的 key 值是每项都有唯一 id。这个特殊的属性相当于 Vue 1.x 的 track-by ,但它的工作方式类似于一个属性,所以你需要用v-bind 来绑定动态值(在这里使用简写):

<div v-for="item in items" :key="item.id">
  <!-- 内容 -->
</div>

建议尽可能使用 v-for 来提供 key ,除非迭代 DOM 内容足够简单,或者你是故意要依赖于默认行为来获得性能提升。

因为它是 Vue 识别节点的一个通用机制, key 并不特别与 v-for 关联,key 还具有其他用途,我们将在后面的指南中看到其他用途。

2.3、数组更新检测

2.3.1、变异方法

Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:

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

你打开控制台,然后用前面例子的 items 数组调用突变方法:example1.items.push({ message: 'Baz' }) 。

2.3.2、重塑数组

变异方法(mutation method),顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异(non-mutating method)方法,例如: filter()concat()slice() 。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

你可能认为这将导致 Vue 丢弃现有 DOM 并重新渲染整个列表。幸运的是,事实并非如此。 Vue 实现了一些智能启发式方法来最大化 DOM 元素重用,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。

示例:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title>列表渲染</title>
    </head>

    <body>
        <div id="app1">
            <ul>
                <li v-for="n in items">
                    <h2>{{n}}</h2>
                </li>
            </ul>
            <button @click="items.splice(0,3)">修改数组(变异)</button>
            <button @click="items.slice(0,3)">修改数组(不变异)</button>
        </div>
        <script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var app1 = new Vue({
                el: "#app1",
                data: {
                    items:[1,3,5,7,9,2,4,6,8,0]
                }
            });
        </script>
    </body>

</html>

结果:

前端MVC Vue2学习总结(四)——条件渲染、列表渲染、事件处理器

如果原数组发生了变化则View也会重新渲染,如果原数组未发生变化只是读取后返回了新的数组对象则不会渲染。

2.3.3、触发数组状态更新

由于 JavaScript 的限制, Vue 不能检测以下变动的数组:

  1. 当你直接设置一个项的索引时,例如: vm.items[indexOfItem] = newValue
  2. 当你修改数组的长度时,例如: vm.items.length = newLength

为了避免第一种情况,以下两种方式将达到像 vm.items[indexOfItem] = newValue 的效果, 同时也将触发状态更新:

// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice`
example1.items.splice(indexOfItem, 1, newValue)

避免第二种情况,使用 splice

example1.items.splice(newLength)

splice数组详解:

splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。

注释:该方法会改变原始数组。

语法
arrayObject.splice(index,howmany,item1,.....,itemX)

index //规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany //要删除的项目数量。如果设置为 0,则不会删除项目。
item1, ..., itemX //向数组添加的新项目。

返回值
Array    包含被删除项目的新数组,如果有的话。

说明
//splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。

//如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组。
View Code

相关文章:

  • 2021-08-06
  • 2022-12-23
  • 2022-12-23
  • 2019-11-17
  • 2021-11-19
  • 2022-12-23
  • 2020-11-13
  • 2021-07-29
猜你喜欢
  • 2021-08-23
  • 2022-12-23
  • 2022-01-26
  • 2021-12-16
  • 2021-07-10
  • 2021-09-22
  • 2021-09-02
相关资源
相似解决方案