Vue 中的常用指令(四)

前言

在之前的课程中,我们使用到v-textv-htmlv-bind这三个 Vue 指令,接下来我们继续学习其他的指令,其中条件渲染(v-if)和列表渲染(v-for)是最需要掌握的。

Vue 指令


指令 (Directives) 是带有 v- 前缀的特殊属性。指令属性的值预期是单个 JavaScript 表达式 (v-for 是例外情况)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

v-text

预期接收: String

说明: 更新元素的 textContent。如果要更新部分的 textContent,需要使用 {{ Mustache }} 插值。

示例:

<span v-text="msg"></span> 
<!-- 和下面的一样 --> 
<span>{{msg}}</span>

v-html

预期接收: String

说明: 更新元素的 innerHTML

注意:

  • 内容按普通 HTML 插入,不会作为 Vue 模板进行编译。
  • 在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。
  • 在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 XSS 攻击。只在可信内容上使用 v-html永不用在用户提交的内容上。

示例:

<div v-html="html"></div> 

v-show

预期接收: any

说明: 根据表达式之真假值,切换元素的 display CSS property,当条件变化时该指令触发过渡效果。我们将在条件渲染小节和v-if进行对比演示。

示例:

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

v-once

不需要表达式

说明: 只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

示例:

<!-- 单个元素 --> 
<span v-once>This will never change: {{msg}}</span> 
<!-- 有子元素 --> 
<div v-once> <h1>comment</h1> <p>{{msg}}</p> </div> 
<!-- 组件 --> 
<my-component v-once :comment="msg"></my-component> 
<!-- `v-for` 指令--> 
<ul> <li v-for="i in list" v-once>{{i}}</li> </ul>

v-pre

不需要表达式

说明: 跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。

示例:

<span v-pre>{{ this will not be compiled }}</span> 

v-cloak

不需要表达式

说明: 这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。

示例:

[v-cloak] { 
   display: none; 
}
<div v-cloak> {{ message }} </div> 

v-bind

预期接收: any (带参数) | Object (不带参数)

说明: 动态地绑定一个或多个 attribute 或一个组件 prop,支持进行缩写:。没有参数时,可以绑定到一个包含键值对的对象。关于绑定styleclass比较特殊,我们将在样式绑定章节进行讲解。

示例:

<!-- 绑定一个 attribute --> 
<img v-bind:src="imageSrc">
<!-- 缩写 -->
<img :src="imageSrc">
<!-- 动态 attribute 名 (2.6.0+) --> 
<button v-bind:[key]="value"></button>
<!-- 绑定一个全是 attribute 的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

v-on

预期接收: Function | 内联语句 | Object

说明: 绑定事件监听器,事件类型由参数指定,支持缩写@。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符也可以省略。用在普通元素上时,只能监听原生 DOM 事件。用在自定义元素组件上时,也可以监听子组件触发的自定义事件。在监听原生 DOM 事件时,方法以事件为唯一的参数。如果使用内联语句,语句可以访问一个 $event property:v-on:click="handle('ok', $event)"。具体的使用演示,会在事件处理组件基础章节中进行。

示例:

<!-- 方法处理器 -->
<button v-on:click="doThis"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 动态事件 (2.6.0+) -->
<button v-on:[event]="doThis"></button>
<!-- 内联语句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 对象语法 (2.4.0+) -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>

v-model

预期接收: 随表单控件类型不同而不同。

说明: 在表单控件或者组件上创建双向绑定,我们将在表单输入绑定章节进行详细讲解。

示例:

<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>

v-solt

说明: 我们将在深入了解组件章节进行详细讲解。

条件渲染

v-if

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。

<h1 v-if="awesome">Vue is awesome!</h1>

你可以使用 v-else 指令来表示 v-if 的“else 块”:

<h1 v-if="awesome">Vue is awesome!</h1> 
<h1 v-else>Oh no 😢</h1>

v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。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-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。

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

v-if 搭配 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

20220310_101547.gif

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

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

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

20220310_102244.gif

这里的演示用到了 chrome 浏览器插件Vue.js devtools进行调试,可前往 https://github.com/vuejs/devtools 自行安装或网上查找相关教程。

v-if 和 v-show 的区别

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换:

<div v-if="show">v-if</div>
<div v-show="show">v-show</div>

20220310_105859.gif

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。另外需要注意的是,v-show 不支持 <template> 元素,也不支持 v-else

列表渲染

v-for 使用数组

我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。你也可以用 of 替代 in 作为分隔符,因为它更接近 JavaScript 迭代器的语法。

<li v-for="student in students" :key="student.name">{{ student.name }} {{ student.gender }}</li> 
// <script>块
export default {
  data(){
    return {
      students: [{
        name: '小明',
        gender: '男'
      },{
        name: '小红',
        gender: '女'
      }]
    }    
  }
}

渲染结果:

image.png

v-for 还支持一个可选的第二个参数,即当前项的索引:

<li v-for="(label, index) in labels" :key="label">
  <label>{{ index + 1 }}、{{ label }}:</label>
  <input type="text">
</li>
// <script>块
export default {
  data(){
    return {
      labels: ['姓名', '性别']
    }    
  }
}

渲染结果:

image.png

当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute。下面进行加key和不加key的对比。

以上面的代码为例,指定key的情况下进行删除元素:

20220310_143551.gif

现在我们去掉key attribute,这时编译的时候会出现语法报错,因为之前我们开发依赖装有eslint进行语法检测。
image.png
我们只需在<template>块顶部加上eslint-disable的注释,便可以跳过 eslint 对代码块的检测。

<template>
  <!-- eslint-disable -->
  <div id="app">
    <li v-for="(label, index) in labels">
      <label>{{ index + 1 }}、{{ label }}:</label>
      <input type="text">
    </li>
  </div>
</template>

现在,我们来看一下没有指定key进行删除的情况:

20220310_145043.gif

所以尽可能在使用 v-for 时提供 key attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。

v-for 使用对象

你也可以用 v-for 来遍历一个对象的 property。

<li v-for="value in object">
  {{ value }}
</li>
//  <script>块
export default {
  data(){
    return {
      object: {
        title: 'How to do lists in Vue',
        author: 'Jane Doe',
        publishedAt: '2016-04-10'
      }
    }    
  }
}

渲染结果:
image.png
你也可以提供第二个的参数为 property 名称 (也就是键名):

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

image.png

还可以用第三个参数作为索引:

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

image.png

v-for 使用值范围

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

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

渲染结果:

image.png

v-for 和 v-if 一起使用

注意,我们不推荐在同一元素上使用 v-ifv-for。当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。当你只想为部分项渲染节点时,推荐采用下一章节会学习的计算属性。而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 <template>) 上。如:

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

内容预告

本章我们介绍了 Vue 中的指令,其中v-ifv-for是最常用的指令。下一章节,我们会学习 Vue 中的事件处理、计算属性、监听属性以及实例的生命周期等。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值