30 KiB
Vue 3.0 引入了很多新的 API 和功能,同时也保留了 Vue 2.x 的很多特性。以下是一个关于 Vue 3.0 常用功能的编程标准指南纲要:
-
项目和组件结构
- 项目目录和文件命名
- 单文件组件的结构:template, script, style
-
组件数据
- 定义和使用 props
- 定义和使用组件内部数据:
ref和reactive - 使用
computed属性 - 使用
watch和watchEffect监听数据变化
-
模板语法
- 插值:文本,HTML
- 指令:v-model, v-if/v-else-if/v-else, v-show, v-for, v-bind, v-on
- 过滤器和全局混入(虽然 Vue 3.0 推荐尽量避免使用,但在一些场景仍有用)
-
组件通信
- 使用 props 和自定义事件实现父子组件通信
- 使用
provide/inject实现祖先和后代组件通信 - 使用 event bus 进行任意组件间的通信(Vue 3.0 不再内置,但可以自行实现)
- 使用 Vue 3.0 的新功能
teleport进行组件内容的传输
-
Composition API
- 使用
setup函数 - 使用
ref,reactive,computed,watch,watchEffect - 创建和使用 composable 函数
- 使用
-
路由和状态管理
- 使用 Vue Router:定义和使用路由,导航守卫,路由元信息
- 使用 Vuex:状态定义,Getter,Mutation,Action,模块化状态
-
与外部交互
- 使用
axios或者fetch进行 HTTP 请求 - 使用 Vue 3.0 的新功能
Suspense进行异步依赖处理
- 使用
-
测试和部署
- 单元测试:使用 Jest 编写和运行测试
- E2E 测试:使用 Cypress 编写和运行测试
- 部署:编译,打包,发布
-
项目和组件结构
- 项目目录和文件命名 Vue 项目和组件的结构可以因项目需求和开发团队偏好而有所不同,但这里提供一种推荐的目录结构:
/my-app ├── /node_modules ├── /public │ ├── index.html │ └── favicon.ico ├── /src │ ├── /assets // 静态资源如图片、样式等 │ ├── /components // Vue 组件 │ ├── /router // Vue Router 配置 │ ├── /store // Vuex 状态管理配置 │ ├── /views // 页面级 Vue 组件 │ ├── App.vue // 根组件 │ ├── main.ts // 应用入口文件 │ ├── shims-vue.d.ts │ └── ... ├── package.json ├── babel.config.js └── ...- 文件命名:对于组件文件,推荐使用 'PascalCase' 的方式命名。例如:
MyComponent.vue。而对于其它的 .js 或 .ts 文件,推荐使用 'kebab-case' 的方式命名。例如:my-script.ts。
-
单文件组件的结构:template, script, style 对于单文件组件(
.vue文件),其内部结构通常包含三部分:<template>,<script>, 和<style>。<template>中定义了组件的 HTML 结构,<script>中定义了组件的逻辑,而<style>中定义了组件的样式。这三部分的顺序并不是固定的,但一般推荐将<script>放在<template>的下面,以便开发者能更快地看到组件的 HTML 结构。<template> <div> <!-- component HTML --> </div> </template> <script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ // component logic }) </script> <style scoped> /* component styles */ </style>
- 组件数据
在 Vue 3.0 中,组件数据可以通过两种方式进行管理:
-
Props: Props 是父组件向子组件传递数据的一种方式。Props 可以是任何类型的数据,如字符串,数字,对象,数组,布尔值等。在子组件中,我们需要定义接受的 props。
-
组件内部数据: 使用
ref和reactive可以创建组件的响应式数据。ref用于创建响应式的基本类型数据(如字符串、数字等),reactive用于创建响应式的复杂类型数据(如对象和数组)。
以下是 props 和响应式数据的用法示例:
<template>
<div>
<h1>{{ title }}</h1>
<p>{{ message }}</p>
<button @click="increment">Clicks: {{ count }}</button>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
name: 'MyComponent',
props: {
title: String,
},
setup(props) {
const count = ref(0)
const message = ref('Hello, Vue 3 and TypeScript!')
function increment() {
count.value++
}
return {
count,
message,
increment
}
}
})
</script>
在这个示例中,title 是一个从父组件传递过来的 prop,count 和 message 是组件内部的响应式数据。我们在 setup 函数中定义了一个方法 increment,这个方法会使 count 的值增加。
注意:在 Vue 3.0 中,使用 ref 创建的响应式数据在模板中访问时不需要 .value,但在 setup 函数或其他 JavaScript 代码中访问时需要 .value。例如,在上述例子中,我们在模板中使用 {{ count }},但在 increment 函数中使用 count.value++。
- 模板语法
Vue.js 使用基于 HTML 的模板语法,允许你声明式地将 DOM 和 Vue 实例的数据绑定在一起。在 Vue 3.0 中,所有 Vue 2.x 的模板语法都得到了支持,包括插值、指令等。
以下是一些常用的模板语法:
- 插值: 使用双大括号(
{{ }})进行文本插值。
<template>
<p>{{ message }}</p>
</template>
- 指令: Vue 指令是带有
v-前缀的特殊属性。指令属性的值预期是单一 JavaScript 表达式。例如v-model、v-if/v-else-if/v-else、v-show、v-for、v-bind、v-on等。
<template>
<input v-model="message">
<p v-if="visible">Hello Vue!</p>
<button v-on:click="handleClick">Click me</button>
<div v-for="(item, index) in items" :key="index">
{{ item }}
</div>
</template>
- 过滤器: Vue 2.x 支持过滤器,但在 Vue 3.0 中过滤器被移除了。如果你需要使用过滤器功能,你可以使用计算属性或者方法来替代。
注意:在 Vue 3.0 中,你应该尽量使用 setup 函数和 Composition API 来组织你的代码,尽管 data、methods、computed 和 watch 等选项在 Vue 3.0 中仍然可用。
- V3.0中不再支持或者不推荐的方法一览 好的,这是一些在 Vue 3.0 中不再支持或不再建议使用的功能和相应的替代方法:
| Vue 2.x | Vue 3.0 替代方法 |
|---|---|
| Filters | 使用计算属性或者方法 |
Vue.set 和 Vue.delete |
直接使用 delete 或 = 操作符来添加或删除响应式属性 |
Vue.observable |
使用 reactive 或 ref |
Vue.prototype 自定义属性或方法 |
使用 provide/inject 机制来共享全局数据或方法 |
异步组件的 component 工厂函数 |
使用 defineAsyncComponent |
| Inline-template attribute | 使用 JSX 或者 Vue 单文件组件(SFC) |
$on, $off 和 $once 方法 |
使用新的事件处理方法,或者使用第三方库 |
| Functional components | 使用普通的组件或者带有 setup 函数的组件 |
需要注意的是,Vue 3.0 为我们提供了一种新的组件编写格式——Composition API,它提供了更好的 TypeScript 类型推断支持,并允许我们在大型组件中更好地组织我们的代码。虽然 Vue 2.x 的 Options API 在 Vue 3.0 中仍然可用,但建议新的项目尽可能地使用 Composition API。
- 以下是 Vue 2.0 和 Vue 3.0 在不同功能和写法上的对比:
- 声明响应式数据
- Vue 2.0
<script>
export default {
data() {
return {
message: 'Hello Vue 2!',
}
}
}
</script>
- Vue 3.0
<script lang="ts">
import { ref } from 'vue'
export default {
setup() {
const message = ref('Hello Vue 3!')
return {
message
}
}
}
</script>
- 计算属性
- Vue 2.0
<script>
export default {
data() {
return {
count: 0,
}
},
computed: {
doubleCount() {
return this.count * 2
}
}
}
</script>
- Vue 3.0
<script lang="ts">
import { ref, computed } from 'vue'
export default {
setup() {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
return {
count,
doubleCount
}
}
}
</script>
- 侦听属性
- Vue 2.0
<script>
export default {
data() {
return {
count: 0,
}
},
watch: {
count(newVal, oldVal) {
console.log(`count changed from ${oldVal} to ${newVal}`)
}
}
}
</script>
- Vue 3.0
<script lang="ts">
import { ref, watch } from 'vue'
export default {
setup() {
const count = ref(0)
watch(count, (newVal, oldVal) => {
console.log(`count changed from ${oldVal} to ${newVal}`)
})
return {
count
}
}
}
</script>
- 生命周期钩子
- Vue 2.0
<script>
export default {
mounted() {
console.log('Component is mounted')
}
}
</script>
- Vue 3.0
<script lang="ts">
import { onMounted } from 'vue'
export default {
setup() {
onMounted(() => {
console.log('Component is mounted')
})
}
}
</script>
以上例子说明了 Vue 3.0 中 Composition API 的基本使用方法。你会注意到,Vue 3.0 提供的新的 API 允许我们在 setup 方法中更自由、更直观地组织代码,更容易进行类型推断,从而提高代码的可读性和可维护性。
4. 组件和指令
- 组件定义
- Vue 3.0 中的组件定义方式如下:
<template>
<div>
{{ message }}
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const message = ref('Hello Vue 3!')
return {
message
}
}
})
</script>
- 使用组件
在 Vue 3.0 中,组件的使用方式和 Vue 2.x 基本相同。可以在父组件中引入子组件,并通过标签形式进行使用。
- Vue 3.0 中的使用方式如下:
<template>
<ChildComponent />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import ChildComponent from './ChildComponent.vue'
export default defineComponent({
components: {
ChildComponent
}
})
</script>
- 指令
Vue 3.0 中的指令和 Vue 2.x 在使用方式上也是相似的,包括内置指令如 v-model, v-if, v-for, v-on, v-bind 等,以及自定义指令。
以下是 Vue 3.0 中自定义指令的一个例子:
<template>
<p v-focus>Focus me!</p>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue'
export default defineComponent({
directives: {
focus: {
mounted(el) {
el.focus()
}
}
}
})
</script>
在上述例子中,我们创建了一个自定义指令 v-focus,当元素被插入到 DOM 中时,这个指令会使元素自动获取焦点。
使用 props 和自定义事件实现父子组件通信
在 Vue.js 中,props 和自定义事件是实现父子组件通信的主要方式。父组件通过 props 向子组件传递数据,子组件通过发射 (emit) 自定义事件向父组件传递数据或者通知父组件某个事件已经发生。
- 以下是一个使用 props 和自定义事件实现父子组件通信的例子:
- 父组件 (ParentComponent.vue)
<template>
<ChildComponent :propData="parentData" @childEvent="handleChildEvent" />
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
export default defineComponent({
components: {
ChildComponent
},
setup() {
const parentData = ref('Data from parent component')
function handleChildEvent(payload) {
console.log('Received event from child component with payload:', payload)
}
return {
parentData,
handleChildEvent
}
}
})
</script>
在上述父组件中,我们使用了 :propData="parentData" 来向子组件传递 prop,以及使用了 @childEvent="handleChildEvent" 来监听子组件发射的 childEvent 事件。
- 子组件 (ChildComponent.vue)
<template>
<button @click="emitEvent">Emit Event</button>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
export default defineComponent({
props: {
propData: {
type: String as PropType<string>,
required: true
}
},
setup(props, { emit }) {
function emitEvent() {
emit('childEvent', 'Data from child component')
}
return {
emitEvent
}
}
})
</script>
在上述子组件中,我们定义了一个 prop propData 来接收父组件传递的数据,以及一个方法 emitEvent 来发射 childEvent 事件。
注意,在 TypeScript 中,我们需要使用 PropType 来显式地指定 prop 的类型。
使用 provide/inject 实现祖先和后代组件通信
在 Vue.js 中,provide 和 inject 是实现祖先和后代组件之间通信的一种方式,主要用于避免 prop drilling(也就是多层级的组件传递 prop)。祖先组件使用 provide 选项来提供某些数据,后代组件使用 inject 选项来注入这些数据。
以下是一个使用 provide 和 inject 实现祖先和后代组件通信的例子:
- 祖先组件 (AncestorComponent.vue)
<template>
<DescendantComponent />
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import DescendantComponent from './DescendantComponent.vue'
export default defineComponent({
components: {
DescendantComponent
},
setup() {
const ancestorData = ref('Data from ancestor component')
provide('ancestorData', ancestorData)
return {}
}
})
</script>
在上述祖先组件中,我们使用了 provide 函数来提供一个名为 ancestorData 的数据。
- 后代组件 (DescendantComponent.vue)
<template>
<p>{{ injectedData }}</p>
</template>
<script lang="ts">
import { defineComponent, inject, Ref } from 'vue'
export default defineComponent({
setup() {
const injectedData = inject<Ref<string>>('ancestorData')
if (!injectedData) {
throw new Error('ancestorData is not provided')
}
return {
injectedData
}
}
})
</script>
在上述后代组件中,我们使用了 inject 函数来注入名为 ancestorData 的数据。请注意,在 TypeScript 中,我们需要使用类型断言 <Ref<string>> 来指定注入数据的类型。
这种方式特别适用于一些跨级别的状态共享,例如主题颜色、语言偏好等全局性的配置。
使用 event bus 进行任意组件间的通信(Vue 3.0 不再内置,但可以自行实现)
Vue 3.0 不再内置 event bus,但你可以使用一个简单的 EventEmitter 实现自己的 event bus。在这种情况下,任何组件都可以通过 event bus 发送和接收事件,实现跨组件通信。
以下是一个使用 event bus 进行任意组件间通信的例子:
首先,我们需要创建一个 Event Bus:
// EventBus.ts
import { EventEmitter } from 'events'
export const EventBus = new EventEmitter()
然后,组件可以通过 Event Bus 发送和接收事件:
- 发送事件的组件 (EmitterComponent.vue)
<template>
<button @click="emitEvent">Emit Event</button>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
import { EventBus } from './EventBus.ts'
export default defineComponent({
setup() {
function emitEvent() {
EventBus.emit('customEvent', 'Data from EmitterComponent')
}
return {
emitEvent
}
}
})
</script>
在上述组件中,我们定义了一个方法 emitEvent,用于在 customEvent 事件上发送数据。
- 接收事件的组件 (ReceiverComponent.vue)
<template>
<p>{{ receivedData }}</p>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted, onBeforeUnmount } from 'vue'
import { EventBus } from './EventBus.ts'
export default defineComponent({
setup() {
const receivedData = ref('')
function handleCustomEvent(payload: string) {
receivedData.value = payload
}
onMounted(() => {
EventBus.on('customEvent', handleCustomEvent)
})
onBeforeUnmount(() => {
EventBus.off('customEvent', handleCustomEvent)
})
return {
receivedData
}
}
})
</script>
在上述组件中,我们使用了 EventBus.on 来监听 customEvent 事件,并在事件处理器 handleCustomEvent 中更新 receivedData。同时,我们也使用了 EventBus.off 来在组件卸载前移除事件监听器,以避免内存泄漏。
请注意,使用 event bus 进行跨组件通信应该谨慎使用,因为它使得数据流难以追踪,增加了代码的复杂性。在大型项目中,你可能会更倾向于使用专门的状态管理库,如 Vuex。
使用 Vue 3.0 的新功能 teleport 进行组件内容的传输
在 Vue 3.0 中,新增了 teleport 功能,也被称为 "传送门"。teleport 能将子组件渲染到 DOM 中的任意位置,而不仅仅是局限于父组件的范围内。它特别适用于需要“破坏性”的 UI 特性,例如全屏覆盖的模态框、通知、对话框等。
以下是一个使用 teleport 进行组件内容的传输的例子:
- 在 HTML 文件中,添加一个目标元素:
<body>
...
<div id="modal-root"></div>
</body>
- 创建一个使用
teleport的组件 (ModalComponent.vue):
<template>
<teleport to="#modal-root">
<div class="modal">
<h1>This is a modal</h1>
<slot></slot>
<button @click="closeModal">Close Modal</button>
</div>
</teleport>
</template>
<script lang="ts">
import { defineComponent, toRef, ref } from 'vue'
export default defineComponent({
setup(props, { emit }) {
const showModal = ref(false)
function closeModal() {
showModal.value = false
emit('update:modelValue', showModal.value)
}
return {
showModal,
closeModal
}
},
props: {
modelValue: {
type: Boolean,
required: true
}
},
emits: ['update:modelValue']
})
</script>
<style scoped>
.modal {
/* styles for your modal */
}
</style>
在上述组件中,我们定义了一个名为 modal-root 的目标元素,这就是我们要将模态框渲染的地方。注意,teleport 的 to 属性用于指定目标元素。
然后,在其他任何需要使用这个模态框的组件中,只需如下使用:
<template>
<ModalComponent v-model="showModal">
<p>This is some content inside the modal</p>
</ModalComponent>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
import ModalComponent from './ModalComponent.vue'
export default defineComponent({
components: {
ModalComponent
},
setup() {
const showModal = ref(false)
return {
showModal
}
}
})
</script>
在使用 teleport 的过程中,父组件和被 teleport 的子组件之间的通信仍然保持原样。也就是说,你可以像平常一样使用 props、事件、插槽等。
5. Vue 3.0 中的 Composition API
Vue 3.0 引入了一种新的组件编写方式,名为 Composition API。它是一个基于函数的 API,让你能更灵活地组织和重用逻辑代码。对比于 Vue 2 中的 Options API,Composition API 更容易处理复杂的组件和逻辑,使代码组织更加清晰。
以下是一个基本的 Composition API 组件示例:
<template>
<button @click="increment">{{ count }}</button>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue'
export default defineComponent({
setup() {
const count = ref(0)
function increment() {
count.value++
}
return {
count,
increment
}
}
})
</script>
在上述示例中,我们在 setup 函数中定义了 count 数据和 increment 方法。请注意,ref 是一个函数,用于创建响应式的数据。在模板中,我们可以像平常一样使用 count 和 increment。
Composition API 还提供了一系列其它的函数,如 reactive、computed、watch、onMounted、onUnmounted 等,可以帮助我们更好地编写组件逻辑。
值得注意的是,使用 Composition API 不意味着必须放弃 Options API。实际上,两者可以在同一个组件中并用。你可以根据项目的具体需求和团队的编程习惯,选择最适合你的 API 风格。
- 以下是 Vue 3.0 中的 Composition API 函数的基本说明,以及与 Options API 的对比
| Composition API | 说明 | 对应的 Options API |
|---|---|---|
setup |
setup 是一个新引入的组件选项,用于使用 Composition API。它是组件内部使用 Composition API 的入口。 |
无 |
ref |
ref 函数用于创建一个响应式的数据。它接收一个参数,返回一个响应式的 Ref 对象。 |
data |
reactive |
reactive 函数用于创建一个响应式的对象。它接收一个普通对象,返回一个响应式的对象。 |
data |
computed |
computed 函数用于创建一个计算属性。它接收一个 getter 函数或者一个具有 getter 和 setter 的对象,返回一个响应式的 Ref 对象。 |
computed |
watch |
watch 函数用于响应式地跟踪和触发副作用。它接收一个响应式的源和一个执行副作用的回调函数。 |
watch |
watchEffect |
watchEffect 函数用于立即执行传入的一个函数,并响应式地追踪其依赖,并在其依赖变更时重新运行该函数。 |
无 |
onMounted |
onMounted 函数在组件被挂载时调用。它接收一个在组件挂载后执行的回调函数。 |
mounted |
onUnmounted |
onUnmounted 函数在组件被卸载时调用。它接收一个在组件卸载后执行的回调函数。 |
beforeDestroy/unmounted |
onUpdated |
onUpdated 在组件更新后调用。它接收一个在组件更新后执行的回调函数。 |
updated |
provide |
provide 函数用于在组件上定义一个可以被后代组件注入的值。它接收一个提供的键和值。 |
有,与 provide/inject 相似但是属性而不是函数 |
inject |
inject 函数用于在组件中注入一个由祖先组件提供的值。它接收一个注入的键。 |
有,但与 provide/inject 相似但是属性而不是函数 |
值得注意的是,虽然一些 Composition API 函数与 Options API 的某些选项有相似之处,但它们的工作方式和使用方式可能有所不同。在实际使用中,你需要根据具体的使用场景和需求选择合适的 API。
- ** 使用
ref,reactive,computed,watch,watchEffect**
这些函数是 Vue 3.0 Composition API 的一部分,使得我们可以更加灵活和高效地编写组件逻辑。
以下是这些函数的使用示例:
<template>
<div>
<p>{{ count }}</p>
<p>{{ double }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script lang="ts">
import { ref, reactive, computed, watch, watchEffect } from 'vue'
export default {
setup() {
// 使用 ref 创建响应式数据
const count = ref(0)
// 使用 reactive 创建响应式对象
const state = reactive({
message: 'Hello Vue 3!'
})
// 使用 computed 创建计算属性
const double = computed(() => count.value * 2)
// 定义方法
const increment = () => {
count.value++
state.message = `Count is ${count.value}`
}
const decrement = () => {
count.value--
state.message = `Count is ${count.value}`
}
// 使用 watch 监听 count 的变化
watch(count, (newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue}`)
})
// 使用 watchEffect 监听响应式依赖项的变化
watchEffect(() => {
console.log(`State message is "${state.message}"`)
})
return {
count,
state,
double,
increment,
decrement
}
}
}
</script>
在上述示例中,我们使用 ref 和 reactive 创建了响应式数据,使用 computed 创建了计算属性,使用 watch 和 watchEffect 监听了数据的变化。并且在数据变化时更新了相关数据,并打印了日志信息。
- ** 创建和使用 composable 函数**
在 Vue 3.0 的 Composition API 中,我们可以将复用的逻辑提取出来,创建一个 composable 函数。composable 函数就是一个普通的 JavaScript 函数,这个函数内部使用了 Composition API 的功能,并返回一些响应式数据或函数。
以下是一个创建和使用 composable 函数的示例:
首先,我们创建一个名为 useCounter 的 composable 函数,这个函数提供了计数器的功能:
import { ref } from 'vue'
export function useCounter() {
const count = ref(0)
const increment = () => {
count.value++
}
const decrement = () => {
count.value--
}
return {
count,
increment,
decrement
}
}
然后,在组件中使用 useCounter 函数:
<template>
<div>
<p>{{ count }}</p>
<button @click="increment">Increment</button>
<button @click="decrement">Decrement</button>
</div>
</template>
<script lang="ts">
import { useCounter } from './composables/useCounter'
export default {
setup() {
const { count, increment, decrement } = useCounter()
return {
count,
increment,
decrement
}
}
}
</script>
在上述示例中,我们首先创建了一个 useCounter composable 函数,这个函数提供了计数器的功能。然后,在组件中使用了 useCounter 函数,从而复用了计数器的功能。通过这种方式,我们可以将复杂的逻辑提取出来,创建 composable 函数,然后在多个组件中复用这些函数。
- 与外部交互
与外部系统(如服务器端 API、本地存储或其他 JavaScript 库)交互是常见的需求。下面介绍一些 Vue 3 和 TypeScript 中的常用方法。
使用 Axios 进行 HTTP 请求 在处理与外部交互时,我们通常会遇到异步操作。以下是使用 Vue 3 和 TypeScript 进行异步处理的例子。
使用 Axios 进行 HTTP 请求
首先,我们可以使用 async/await 语法改写 Axios 的 HTTP 请求:
import axios from 'axios'
import { ref, onMounted } from 'vue'
export default {
setup() {
const data = ref(null)
onMounted(async () => {
const response = await axios.get('https://api.example.com/data')
data.value = response.data
})
return {
data
}
}
}
在这个例子中,我们使用 async/await 语法来处理异步的 HTTP 请求。注意,因为 await 只能在 async 函数中使用,所以我们需要在 onMounted 钩子中使用 async。
使用 LocalStorage 进行本地存储
虽然 LocalStorage 的操作是同步的,但如果你需要模拟异步操作,可以使用 Promise:
import { ref, onMounted } from 'vue'
export default {
setup() {
const count = ref(0)
onMounted(async () => {
const savedCount = await new Promise(resolve => {
setTimeout(() => {
resolve(localStorage.getItem('count'))
}, 1000)
})
count.value = savedCount || 0
})
return {
count
}
}
}
在这个例子中,我们使用 setTimeout 模拟异步操作,并使用 Promise 来处理这个异步操作。在异步操作完成后,我们更新 count 的值。
使用 LocalStorage 进行本地存储
在浏览器中,我们可以使用 LocalStorage 对象进行本地存储。以下是一个简单的例子:
import { ref, watch } from 'vue'
export default {
setup() {
const count = ref(localStorage.getItem('count') || 0)
watch(count, newValue => {
localStorage.setItem('count', newValue)
})
return {
count
}
}
}
在这个例子中,我们首先从 LocalStorage 中获取 count 的值。然后,我们使用 watch() 函数监听 count 的变化,并在 count 变化时更新 LocalStorage 中的值。
使用 Vue 3 提供的生命周期钩子
Vue 3 提供了一些生命周期钩子,如 onMounted()、onUpdated() 和 onUnmounted(),可以在组件的生命周期的不同阶段进行特定的操作。以下是一个简单的例子:
import { onMounted, ref } from 'vue'
export default {
setup() {
const data = ref(null)
onMounted(() => {
data.value = 'Hello, Vue 3'
})
return {
data
}
}
}
在这个例子中,我们在组件挂载后更新 data 的值。
7. 使用 Vue 3.0 的新功能 Suspense 进行异步依赖处理
Vue 3.0 引入了一个新的内置组件 Suspense,它可以帮助我们处理组件中的异步依赖。
当一个组件的 setup 函数返回一个 Promise 时(这通常意味着该组件有异步操作),我们可以用 Suspense 组件包裹这个组件。Suspense 组件有两个插槽:default 插槽和 fallback 插槽。当异步组件处于等待状态时,fallback 插槽的内容会被渲染;当异步组件的 Promise 解析完成时,default 插槽的内容会被渲染。
下面是一个使用 Suspense 处理异步组件的例子:
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>Loading...</div>
</template>
</Suspense>
</template>
<script lang="ts">
import { defineComponent, ref, onMounted } from 'vue'
import axios from 'axios'
const AsyncComponent = defineComponent({
async setup() {
const data = ref(null)
// 这里模拟一个异步操作
await new Promise(resolve => setTimeout(resolve, 2000))
const response = await axios.get('https://api.example.com/data')
data.value = response.data
return {
data
}
},
template: `
<div>
<p>Data: {{ data }}</p>
</div>
`,
})
export default {
components: {
AsyncComponent
}
}
</script>
在这个例子中,我们创建了一个异步组件 AsyncComponent,它的 setup 函数返回一个 Promise。我们使用 Suspense 组件包裹 AsyncComponent,并提供了 fallback 插槽,当 AsyncComponent 的数据正在加载时,fallback 插槽的内容会被渲染。