六-九节
- 条件渲染
- 列表渲染
- 事件处理
- 表单输入绑定
条件渲染
v-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>
# 不止一个元素可以依附于 <template>
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
v-show
按条件显示一个元素
<h1 v-show="ok">Hello!</h1>
v-if 和 v-show 区别
特性 | v-if |
v-show |
---|---|---|
渲染方式 | 根据条件动态添加或移除元素 | 通过 CSS 控制元素的显示与隐藏 |
初始化开销 | 需要初始化开销,条件为 true 时创建元素并插入 DOM |
无初始化开销,元素一直在 DOM 中,通过 CSS 控制显示隐藏 |
性能考虑 | 适合条件变化较少或有大块内容需要动态渲染 | 适合条件频繁变化或内容变化较少,仅需切换显示隐藏 |
适用场景 | 动态内容频繁变化时较为高效 | 静态内容或频繁切换显示隐藏的情况下较为高效 |
列表渲染
v-for
基于一个数组来渲染一个列表
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
<li v-for="item in items">
{{ item.message }}
</li>
# 索引
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
# 解构
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- 有 index 索引时 -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
# 多层嵌套,内部可以访问外层
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
# 可以用 of
<div v-for="item of items"></div>
v-for 和对象
遍历的顺序会基于对该对象调用 Object.keys() 的返回值来决定。
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
# value
<ul>
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
# value\key
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
# value\key\index
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
# template
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-for 里使用范围值
# 从 1 到 10
<span v-for="n in 10">{{ n }}</span>
通过 key 管理状态
添加 key 的主要原因是帮助 Vue 更高效地管理 DOM,并提升列表渲染的性能。
- 识别元素: 通过 key,Vue 可以追踪每个列表中元素的身份。当数据发生变化时,Vue 使用 key 来确定哪些元素是新创建的、被修改的或被移除的,从而减少不必要的 DOM 操作。
- 复用元素: key 允许 Vue 在重新渲染列表时尽可能地复用已有的 DOM 元素。这样可以避免重新创建和销毁 DOM,从而提升性能和优化用户体验。
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
期望
- 为 v-for 提供一个 key attribute
- key 为字符串或 number 基础类型,不要用对象
事件处理
监听事件
使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click=“handler” 或 @click=“handler”。
事件处理器 (handler) 的值可以是:
- 内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与 onclick 类似)。
- 方法事件处理器:一个指向组件上定义的方法的属性名或是路径。
内联事件处理器
通常用于简单场景
const count = ref(0)
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>
方法事件处理器
const name = ref('Vue.js')
function greet(event) {
alert(`Hello ${name.value}!`)
// `event` 是 DOM 原生事件
if (event) {
alert(event.target.tagName)
}
}
<!-- `greet` 是上面定义过的方法名 -->
<button @click="greet">Greet</button>
方法与内联事件判断:模板编译器会通过检查 v-on 的值是否是合法的 JavaScript 标识符或属性访问路径来断定是何种形式的事件处理器。举例来说,foo、foo.bar 和 foo[‘bar’] 会被视为方法事件处理器,而 foo() 和 count++ 会被视为内联事件处理器。
# 在内联处理器中调用方法
function say(message) {
alert(message)
}
<button @click="say('hello')">Say hello</button>
<button @click="say('bye')">Say bye</button>
# 在内联事件处理器中访问事件参数
<!-- 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
<!-- 使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
Submit
</button>
function warn(message, event) {
// 这里可以访问原生事件
if (event) {
event.preventDefault()
}
alert(message)
}
修饰符
- 事件修饰符
<!-- 单击事件将停止传递 --> <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> <!-- 添加事件监听器时,使用 `capture` 捕获模式 --> <!-- 例如:指向内部元素的事件,在被内部元素处理前,先被外部处理 --> <div @click.capture="doThis">...</div> <!-- 点击事件最多被触发一次 --> <a @click.once="doThis"></a> <!-- 滚动事件的默认行为 (scrolling) 将立即发生而非等待 `onScroll` 完成 --> <!-- 以防其中包含 `event.preventDefault()` --> <div @scroll.passive="onScroll">...</div>
- 按键修饰符
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` --> <input @keyup.enter="submit" /> <!-- 仅会在 $event.key 为 'PageDown' 时调用事件处理 --> <input @keyup.page-down="onPageDown" /> Vue 为一些常用的按键提供了别名: .enter .tab .delete (捕获“Delete”和“Backspace”两个按键) .esc .space .up .down .left .right # 系统按键修饰符 .ctrl .alt .shift .meta # 在 Mac 键盘上,meta 是 Command 键 (⌘)。在 Windows 键盘上,meta 键是 Windows 键 (⊞)。 <!-- Alt + Enter --> <input @keyup.alt.enter="clear" /> <!-- Ctrl + 点击 --> <div @click.ctrl="doSomething">Do something</div> # 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符 <!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 --> <button @click.ctrl="onClick">A</button> <!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 --> <button @click.ctrl.exact="onCtrlClick">A</button> <!-- 仅当没有按下任何系统按键时触发 --> <button @click.exact="onClick">A</button>
- 鼠标按键修饰符
.left .right .middle
表单输入绑定
<input
:value="text"
@input="event => text = event.target.value">
# 简化为
<input v-model="text">
# 基本用法
<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edit me" />
# 多行文本
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
# 复选框
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
<!-- 值绑定 -->
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no" />
<input
type="checkbox"
v-model="toggle"
:true-value="dynamicTrueValue"
:false-value="dynamicFalseValue" />
# 多个复选框
const checkedNames = ref([])
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
# 单选按钮
<div>Picked: {{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
# 选择器
<div>Selected: {{ selected }}</div>
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
# 多选,值绑定到一个数组
<div>Selected: {{ selected }}</div>
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<select v-model="selected">
<!-- 内联对象字面量 -->
<option :value="{ number: 123 }">123</option>
</select>
修饰符
<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />
<!-- 让用户输入自动转换为数字 -->
<input v-model.number="age" />
<!-- 默认自动去除用户输入内容中两端的空格 -->
<input v-model.trim="msg" />