Vue3基础
模板语法
插值
- 文本 =>
Mustache
->{{ }}
- 原始HTML =>
v-html=""
- Attribute =>
v-bind
- JavaScript表达式
指令(Directives) => v-
attribute
- 参数 =>
v-bind:参数
,v-on:参数
- 动态参数 =>
v-bind:[attributeName]=""
- 不能含有空格,可使用计算属性解决
- 修饰符 =>
.prevent
<=>event.preventDefault()
缩写
v-bind:
<=> :
v-on:
<=> @
Data Property 和方法
Data Property
$data
方法
methods
=> 绑定this
在定义
methods
时应避免使用箭头函数,因为这会阻止 Vue 绑定恰当的this
指向
防抖和节流
Vue 没有内置支持防抖和节流,但可以使用 Lodash 等库来实现。
计算属性和侦听器
计算属性 => computed
计算属性缓存 vs 方法
计算属性将基于它们的响应依赖关系缓存。计算属性只会在相关响应式依赖发生改变时重新求值。这就意味着只要 计算属性中的方法依赖的值 还没有发生改变,多次访问计算属性中的方法时计算属性会立即返回之前的计算结果,而不必再次执行函数。
这也同样意味着下面的计算属性将永远不会更新,因为Date.now ()
不是响应式依赖。
相比之下,每当触发重新渲染时,调用方法将始终会再次执行函数。-
计算属性的 Setter
computed: { xxx: { // getter get() {}, // setter set(newValue) {} } }
侦听器 => watch
- 计算属性 vs 侦听器
Vue 提供了一种更通用的方式来观察和响应当前活动的实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,watch
很容易被滥用。然而,通常更好的做法是使用计算属性而不是命令式的watch
回调。
Class 与 Style 绑定
绑定 HTML Class
-
对象语法
<div :class="{ active: isActive }"></div>
上面的语法表示
active
这个 class 存在与否将取决于 data propertyisActive
的 truthiness。 -
数组语法
<div :class="[activeClass, errorClass]"></div>
data() { return { activeClass: 'active', errorClass: 'text-danger' } }
绑定内联样式
-
对象语法
CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名。<div :style="{ color: activeColor }"></div>
-
数组语法
<div :style="[styleObject]"></div>
data() { return { styleObject: { color: 'red' } } }
自动添加前缀
在:style
中使用需要一个 vendor prefix (浏览器引擎前缀) 的 CSS property 时,Vue 将自动侦测并添加相应的前缀。Vue 是通过运行时检测来确定哪些样式的 property 是被当前浏览器支持的。如果浏览器不支持某个 property,Vue 会进行多次测试以找到支持它的前缀。-
多重值
可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染
display: flex
。
条件渲染
v-if
v-if
v-else
v-else-if
v-show
不同的是带有 v-show
的元素始终会被渲染并保留在 DOM 中。v-show
只是简单地切换元素的 display
CSS property。
注意,v-show
不支持 <template>
元素,也不支持 v-else
。
v-if
vs v-show
v-if
是“真正”的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。
v-if
也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show
就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
v-if
与 v-for
一起使用
不推荐同时使用
v-if
和v-for
。
当 v-if
与 v-for
一起使用时,v-if
具有比 v-for
更高的优先级。
列表渲染
用 v-for
把一个数组映射为一组元素
<ul>
<li v-for="(item, index) in items">
...
</li>
</ul>
在 v-for
里使用对象
<li v-for="(value, name, index) in myObject">
{{ index }}. {{ name }}: {{ value }}
</li>
维护状态
当 Vue 正在更新使用 v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的 key
attribute:
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
建议尽可能在使用 v-for
时提供 key
attribute,除非遍历输出的 DOM 内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
因为它是 Vue 识别节点的一个通用机制,key
并不仅与 v-for
特别关联。后面我们将在指南中看到,它还具有其它用途。
更多
key
attribute 的细节用法请移步至key
的 API 文档。
数组更新检测
-
变更方法
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:push()
pop()
shift()
unshift()
splice()
sort()
reverse()
替换数组
变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如filter()
、concat()
和slice()
。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组。
显示过滤/排序后的结果
计算属性
<li v-for="n in evenNumbers" :key="n">{{ n }}</li>
data() {
return {
numbers: [ 1, 2, 3, 4, 5 ]
}
},
computed: {
evenNumbers() {
return this.numbers.filter(number => number % 2 === 0)
}
}
在计算属性不适用的情况下 (例如,在嵌套的 v-for
循环中) 你可以使用一个方法:
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)" :key="n">{{ n }}</li>
</ul>
data() {
return {
sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
}
},
methods: {
even(numbers) {
return numbers.filter(number => number % 2 === 0)
}
}
在 v-for
里使用值的范围
v-for
也可以接受整数。在这种情况下,它会把模板重复对应次数。
<div id="range" class="demo">
<span v-for="n in 10" :key="n">{{ n }} </span>
</div>
在 <template>
中使用 v-for
类似于 v-if
,你也可以利用带有 v-for
的 <template>
来循环渲染一段包含多个元素的内容。
v-for
与 v-if
一同使用
当它们处于同一节点,v-if
的优先级比 v-for
更高,这意味着 v-if
将没有权限访问 v-for
里的变量:
<!-- 这将抛出一个错误,因为“todo” property 没有在实例上定义 -->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
可以把 v-for
移动到 <template>
标签中来修正:
<template v-for="todo in todos" :key="todo.name">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
在组件上使用 v-for
事件处理
监听事件 => @
事件处理方法
@event="handle"
-> methods: {handle() { } }
内联处理器中的方法
@event="handle(args)"
@click="handle(args, $event)"
有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event
把它传入方法:
methods: {
handle(args, event) {
// 原生事件 event
}
多事件处理器
事件处理程序中可以有多个方法,这些方法由逗号运算符分隔:
<!-- 这两个 one() 和 two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
Submit
</button>
// ...
methods: {
one(event) {
// 第一个事件处理器逻辑...
},
two(event) {
// 第二个事件处理器逻辑...
}
}
事件修饰符
-
.stop
: 阻止单击事件继续冒泡; -
.prevent
: 提交事件不再重载页面; -
.capture
: 添加事件监听器时使用事件捕获模式,即内部元素触发的事件先在此处理,然后才交由内部元素进行处理; -
.self
: 只当在 event.target 是当前元素自身时触发处理函数,即事件不是从内部元素触发的; -
.once
: 点击事件将只会触发一次; -
.passive
: 对应addEventListener
中的 passive 选项。
修饰符可以串联,使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。
按键修饰符
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input @keyup.enter="submit" />
可以直接将 KeyboardEvent.key
暴露的任意有效按键名转换为 kebab-case 来作为修饰符。
<input @keyup.page-down="onPageDown" />
- 按键别名
Vue 为最常用的键提供了别名:.enter
.tab
-
.delete
(捕获“删除”和“退格”键) .esc
.space
.up
.down
.left
.right
系统修饰键
.ctrl
.alt
.shift
-
.meta
: meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。
请注意修饰键与常规按键不同,在和
keyup
事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住ctrl
的情况下释放其它按键,才能触发keyup.ctrl
。而单单释放ctrl
也不会触发事件。
.exact
修饰符
.exact
修饰符允许你控制由精确的系统修饰符组合触发的事件。-
鼠标按钮修饰符
.left
.right
-
.middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
表单输入绑定 => v-model
v-model
会忽略所有表单元素的value
、checked
、selected
attribute 的初始值。它将始终将当前活动实例的数据作为数据来源。你应该通过 JavaScript 在组件的data
选项中声明初始值。
v-model
在内部为不同的输入元素使用不同的 property 并抛出不同的事件:
- text 和 textarea 元素使用
value
property 和input
事件; - checkbox 和 radio 使用
checked
property 和change
事件; - select 字段将
value
作为 prop 并将change
作为事件。
对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现
v-model
不会在输入法组织文字过程中得到更新。如果你也想响应这些更新,请使用input
事件监听器和value
绑定来替代v-model
。
值绑定
对于单选按钮,复选框及选择框的选项,v-model
绑定的值通常是静态字符串 (对于复选框也可以是布尔值)。
修饰符
-
.lazy
:v-model
在每次input
事件触发后将输入框的值与数据进行同步。你可以添加lazy
修饰符,从而转为在change
事件之后进行同步; -
.number
:自动将用户的输入值转为数值类型; -
.trim
:自动过滤用户输入的首尾空白字符。
组件基础
组件的复用
组件的组织
有两种组件的注册类型:全局注册和局部注册。
通过 Prop 向子组件传递数据 => props
监听子组件事件 => $emit()
使用事件抛出一个值 =>
$emit()
-
在组件上使用
v-model
自定义事件也可以用于创建支持v-model
的自定义输入组件。为了让它正常工作,这个组件内的
<input>
必须:- 将其
value
attribute 绑定到一个名叫modelValue
的 prop 上 - 在其
input
事件被触发时,将新的值通过自定义的update:modelValue
事件抛出
app.component('custom-input', { props: ['modelValue'], emits: ['update:modelValue'], template: ` <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" > ` })
<custom-input v-model="searchText"></custom-input>
在该组件中实现
v-model
的另一种方法是使用computed
property 的功能来定义 getter 和 setter。get
方法应返回modelValue
property,set
方法应该触发相应的事件。app.component('custom-input', { props: ['modelValue'], emits: ['update:modelValue'], template: ` <input v-model="value"> `, computed: { value: { get() { return this.modelValue }, set(value) { this.$emit('update:modelValue', value) } } } })
- 将其
通过插槽分发内容 => <slot></slot>
动态组件 => :is
- 已注册组件的名字,或
- 一个组件选项对象