Vue3相关学习

创建应用

模版语法

响应式

ref

在组合式 API 中,更应该使用 ref() 函数来声明响应式状态:

1
2
3
import { ref } from 'vue'

const count = ref(0)

reactive

还有另一种声明响应式状态的方式,即使用reactive()API。与将内部值包装在特殊对象中的ref不同,reactive()将使对象本身具有响应性:

1
2
3
import { reactive } from 'vue'

const state = reactive({ count: 0 })

为什么要使用 ref?​

为什么需要使用带有.valueref,而不是普通的变量?

当在模板中使用了一个ref,然后改变了这个ref的值时,Vue会自动检测到这个变化,并且相应地更新DOM。这是通过一个基于依赖追踪的响应式系统实现的。当一个组件首次渲染时,Vue 会追踪在渲染过程中使用的每一个 ref。然后,当一个ref被修改时,它会触发追踪它的组件的一次重新渲染。

在标准的JavaScript中,检测普通变量的访问或修改是行不通的。然而,可以通过gettersetter方法来拦截对象属性的getset操作。

.value属性给予了Vue一个机会来检测ref何时被访问或修改。在其内部,Vue在它的getter中执行追踪,在它的setter中执行触发。从概念上讲,你可以将ref看作是一个像这样的对象:

1
2
3
4
5
6
7
8
9
10
11
const myRef = {
_value: 0,
get value() {
track()
return this._value
},
set value(newValue) {
this._value = newValue
trigger()
}
}

另一个ref的好处是,与普通变量不同,你可以将ref传递给函数,同时保留对最新值和响应式连接的访问。当将复杂的逻辑重构为可重用的代码时,这将非常有用。

使用场景

优先用 ref 的场景
  • 基本数据类型(字符串、数字、布尔等)。
  • 需要明确控制响应式的简单数据。
  • 可能被解构或重新赋值的变量。
优先用 reactive 的场景:
  • 复杂对象或数组(如用户信息、列表数据)。
  • 希望直接通过属性访问,保持代码简洁时。

计算属性

方法computed() 期望接收一个getter函数,返回值为一个计算属性 ref。和其他一般的ref类似,可以通过publishedBooksMessage.value访问计算结果。计算属性ref也会在模板中自动解包,因此在模板表达式中引用时无需添加.value

计算属性还会自动追踪响应式依赖。它会检测到publishedBooksMessage依赖于author.books,所以当author.books改变时,任何依赖于publishedBooksMessage的绑定都会同时更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script setup>
import { reactive, computed } from 'vue'

const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})

// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
</script>

<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>

类与样式绑定

绑定HTML Class

绑定内联Style

条件渲染

v-if

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

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

v-else

也可以使用v-elsev-if添加一个else区块。

1
2
3
4
<button @click="awesome = !awesome">Toggle</button>

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

v-else-if

其实就是ifelse语法

1
2
3
4
5
6
7
8
9
10
11
12
<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 上的 v-if

因为 v-if 是一个指令,必须依附于某个元素。但如果想要切换的不止一个元素,也可以在一个 <template> 元素上使用 v-if<template>是一个不可见的包装器元素,有点类似React的Fragment标签,最后渲染的结果并不会包含这个 <template> 元素。

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

指令 v-elsev-else-if 也可以在 <template> 上使用。

v-show

另一个可以用来按条件显示一个元素的指令是 v-show。其用法基本一样:

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

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

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

v-if vs v-show

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

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

相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。v-show的隐藏是通过 display: none 实现的)

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

列表渲染

v-for

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

1
2
3
4
5
const items = ref([{ message: 'Foo' }, { message: 'Bar' }]);

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

template 上的 v-for

和模板上的 v-if 类似,也可以在 <template> 标签上使用 v-for 来渲染一个包含多个元素的块。例如:

1
2
3
4
5
6
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>

通过 key 管理状态

React Reconcile 阶段类似,列表渲染时 Vue 也要给虚拟 DOM 一个标识
框架 Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。

默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时 DOM 状态 (例如表单输入值) 的情况。

为了给 Vue 一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,需要为每个元素对应的块提供一个唯一的 key attribute

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

当使用 <template v-for> 时,key 应该被放置在这个 <template> 容器上:

1
2
3
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>

事件处理

我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler"@click="handler"

事件处理器 (handler) 的值可以是:

内联事件处理器(纯纯的糟粕,完全不明白Vue为什么要设计这么复杂的语法)

事件被触发时执行的内联 JavaScript 语句

1
2
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>

方法事件处理器

一个指向组件上定义的方法的属性名或是路径。

1
2
3
4
5
6
7
8
9
10
11
12
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-text:会把内容解析成纯文本(会覆盖原标签内容)
  • v-html:可以解析标签(会覆盖原标签内容)
  • v-if
  • v-else
  • v-else-if
  • v-show
  • v-for: