# 类与样式绑定

# 绑定HTML class

绑定对象

<div :class="{ active: isActive }"></div>

<div
  class="static"
  :class="{ active: isActive, 'text-danger': hasError }"
></div>

<div :class="classObject"></div>
也可以绑定计算属性

绑定数组

<div :class="[activeClass, errorClass]"></div>

<div :class="[isActive ? activeClass : '', errorClass]"></div>

<div :class="[{ active: isActive }, errorClass]"></div>

# 绑定内联样式

绑定对象

<!-- 支持绑定css属性名的小驼峰式写法 -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

<!-- 支持绑定原始css属性写法 -->
<div :style="{ 'font-size': fontSize + 'px' }"></div>

<!-- 绑定样式对象 -->
<div :style="styleObject"></div>
也可以绑定计算属性

绑定数组

<div :style="[baseStyles, overridingStyles]"></div>

# 自动前缀

当你在 :style 中使用了需要浏览器特殊前缀 (opens new window)的 CSS 属性时,Vue 会自动为他们加上相应的前缀。Vue 是在运行时检查该属性是否支持在当前浏览器中使用。如果浏览器不支持某个属性,那么将尝试加上各个浏览器特殊前缀,以找到哪一个是被支持的。

# 文本插值

# {{}}

最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):

  1. 支持js表达式

仅支持单一表达式(一个简单的判断方法是是否可以合法地写在 return 后面)。

  1. 支持函数调用
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}

{{ formatDate(date) }}

注意:没有显式包含在列表中的全局对象将不能在模板内表达式中访问。(可以自行在 app.config.globalProperties (opens new window) 上显式地添加它们,供所有的 Vue 表达式使用。)

# v-html

# v-text

# 属性绑定

# v-bind

<div v-bind:id="dynamicId"></div>

注意:如果绑定的值是 null 或者 undefined,那么该 attribute 将会从渲染的元素上移除。

简写为::

动态绑定多个值

data() {
  return {
    objectOfAttrs: {
      id: 'container',
      class: 'wrapper'
    }
  }
}
<div v-bind="objectOfAttrs"></div>

动态参数

<a v-bind:[attributeName]="url"> ... </a>

<!-- 简写 -->
<a :[attributeName]="url"> ... </a>

# 条件渲染

# v-if

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

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

# v-else

你也可以使用 v-elsev-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-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-else 类似,一个使用 v-else-if 的元素必须紧跟在一个 v-if 或一个 v-else-if 元素后面。

<template> 上的 v-ifv-else 和 `v-else-if

# v-show

另一个可以用来按条件显示一个元素的指令是 v-show

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

不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。

v-show 不支持在 <template> 元素上使用,也不能和 v-else 搭配使用。

# v-if vs. v-show# (opens new window)

v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。

v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。

相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。

总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

# v-ifv-for

v-ifv-for 同时存在于一个元素上的时候,

v-ifv-for 的优先级更高,v-if 会首先被执行。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:请查看列表渲染指南 (opens new window)获取更多细节。

<!--
 这会抛出一个错误,因为属性 todo 此时
 没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.name }}
</li>

在外新包装一层 <template> 再在其上使用 v-for 可以解决这个问题 (这也更加明显易读):

<template v-for="todo in todos">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

# 列表渲染

# v-for

v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名

<li v-for="item in items">
  {{ item.message }}
</li>

data() {
  return {
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}

你也可以使用 of 作为分隔符来替代 in,这更接近 JavaScript 的迭代器语法:

template

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

# v-for与对象

也可以使用 v-for 来遍历一个对象的所有属性。遍历的顺序会基于对该对象调用 Object.keys() 的返回值来决定。

data() {
  return {
    myObject: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
}


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

属性值、属性名、索引

<template> 标签上使用 v-for 来渲染一个包含多个元素的块。

通过key管理状态

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

# 事件处理

# v-on

它将监听DOM事件,并在事件触发时执行对应的 JavaScript。

<!-- 这里的参数是要监听的事件名称:click -->
<a v-on:click="doSomething"> ... </a>

<!-- 简写 -->
<a @click="doSomething"> ... </a>

简写为:@

事件处理器的值可以是:

  1. 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与 onclick 类似)。

    内联事件处理器通常用于简单场景
    <button @click="count++">Add 1</button>
    
    
  2. 方法事件处理器:一个指向组件上定义的方法的属性名或是路径。

方法内够通过被触发事件的 event.target.tagName 访问到该 DOM 元素。

# 事件修饰符

# .stop

# .prevent

.prevent 修饰符会告知 v-on 指令对触发的事件调用 event.preventDefault()

# .self

# .capture

# .once

# .passive

<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>

<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>

<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>

<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>

<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>

# 按键修饰符

  • .enter
  • .tab
  • .delete (捕获“Delete”和“Backspace”两个按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

# 系统按键修饰符# (opens new window)

你可以使用以下系统按键修饰符来触发鼠标或键盘事件监听器,只有当按键被按下时才会触发。

  • .ctrl
  • .alt
  • .shift
  • .meta
  • 在 Mac 键盘上,meta 是 Command 键 (⌘)。在 Windows 键盘上,meta 键是 Windows 键 (⊞)。在 Sun 微机系统键盘上,meta 是钻石键 (◆)。在某些键盘上,特别是 MIT 和 Lisp 机器的键盘及其后代版本的键盘,如 Knight 键盘,space-cadet 键盘,meta 都被标记为“META”。在 Symbolics 键盘上,meta 也被标识为“META”或“Meta”。

# .exact 修饰符

.exact 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符。

<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>

<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>

# 鼠标按键修饰符# (opens new window)

  • .left
  • .right
  • .middle

这些修饰符将处理程序限定为由特定鼠标按键触发的事件。

指令语法图

# 表单输入绑定

# v-model

# 文本

# 多行文本

# 复选框

<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no" />


true-value 和 false-value 是 Vue 特有的 attributes,仅支持和 v-model 配套使用。这里 toggle 属性的值会在选中时被设为 'yes',取消选择时设为 'no'。你同样可以通过 v-bind 将其绑定为其他动态值:

# 单选按钮

# 选择器

# 修饰符

# .lazy

默认情况下,v-model 会在每次 input 事件后更新数据 (IME 拼字阶段的状态 (opens new window)例外)。你可以添加 lazy 修饰符来改为在每次 change 事件后更新数据

# .number

如果你想让用户输入自动转换为数字,你可以在 v-model 后添加 .number 修饰符来管理输入

# .trim

如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符:

<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />
<input v-model.number="age" />
<input v-model.trim="msg" />