Vue 3
Vue 3 引入了一个全新的响应式系统,它是基于 ES6 的Proxy 特性构建的。这个系统使得 Vue 能够更高效地追踪数据的变化,并在数据发生变化时自动更新 DOM。响应式系统的核心是让数据变得“可观察”,当数据改变时,视图会响应这些变化并重新渲染。
vue3优点:
1、使用 <template>
标签和 Vue 3 的 Fragment 特性可以帮助你避免在模板中添加不必要的包装器元素,从而保持 DOM 结构的简洁性和性能。
一、 使用响应式助手声明基本类型
1.使用reactive 代替Object,Array,Map,Set
reactive 用于定义一个响应式的对象。它接受一个普通对象并返回该对象的响应式代理。这使得整个对象的属性都是响应式的。
reactive的使用场景
- 当你需要创建一个响应式的对象或数组时。
- 当你需要管理一个对象的多个属性,并且希望这些属性都是响应式的时。
- 当你需要在多个组件之间共享和操作一个响应式状态时。
2.使用ref 代替String,Number,Boolean
ref 用于定义一个响应式的引用类型。它接受一个参数值,并返回一个响应式且可变的 ref 对象。这个对象有一个 `.value属性,指向传入的参数值。
ref的使用场景
- 当你需要包装一个基本类型值(如字符串、数字、布尔值)使其成为响应式时。
- 当你需要一个响应式的单一值时(例如,一个标志位或计数器)。
-
ref
也可以包装对象和数组,但通常情况下,我们会使用reactive
来处理这些复杂类型。
对于原始值使用响应式会导致警告,并且该值不会被设置为响应式。
对于原始值使用响应式会导致警告,并且该值不会被设置为响应式。
<script setup>
import { reactive } from’vue’;
const count = reactive(0)
</script>
[Vue warn]:value cannot be made reactive;
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
3、 结构失去响应式值
return 返回响应式对象的属性时不能用解构;
在 Vue 3 中,如果你使用解构(destructuring)来访问一个由 reactive
创建的响应式对象的属性,这些属性会失去其响应式特性。这是因为解构操作实际上是在创建对象属性的本地副本,而这些副本不再是响应式的。
例如:
import { reactive } from 'vue';
const state = reactive({
count: 0,
message: 'Hello'
});
// 解构 state 对象
const { count, message } = state;
// count 和 message 在这里是非响应式的
console.log(count); // 输出 0
console.log(message); // 输出 'Hello'
// 如果 state 对象的 count 或 message 属性改变了,
// 解构出来的 count 和 message 不会更新
为了保持响应式,你应该直接使用原始的响应式对象,或者使用 Vue 提供的 toRefs
函数将 reactive
对象的每个属性都转换为一个 ref
对象,这样每个属性都保持响应式。
使用 toRefs
的例子:
import { reactive, toRefs } from 'vue';
const state = reactive({
count: 0,
message: 'Hello'
});
// 使用 toRefs 保持响应式
const { count, message } = toRefs(state);
// 现在 count 和 message 仍然是响应式的
count.value++; // state.count 也会更新
console.log(state.count); // 输出 1
在这个例子中,toRefs
创建了一个包含与原始对象相同属性的普通对象,但是每个属性都是一个 ref
,这样即使在解构后,每个属性仍然保持响应式。这在需要将响应式对象的属性传递给子组件或者在组合式函数中使用时非常有用。
总结一下,要避免解构导致的响应式丢失问题,你可以:
- 直接使用原始的响应式对象,不进行解构。
- 使用
toRefs
将reactive
对象的属性转换为ref
,然后再进行解构。
二、模板语法和基本指令
在 Vue 3 中,模板语法和基本指令是构建动态用户界面的核心。
1.模板语法
Vue.js 使用基于 HTML 的模板语法,允许你声明式地将 DOM 绑定到底层组件实例的数据。所有 Vue.js 模板都是有效的 HTML,可以被遵循规范的浏览器和 HTML 解析器解析。
在模板中,你可以使用双大括号 {{ }}
进行文本插值:
<span>{{ message }}</span>
2.v-bind
v-bind
指令用于动态地绑定一个或多个属性,或一个组件 prop 到表达式。在渲染的 DOM 上,你会看到属性值被设置为指令的表达式计算的结果。
<!-- 绑定一个属性 -->
<img v-bind:src="imageSrc">
<!-- 缩写 -->
<img :src="imageSrc">
3.v-model
v-model
指令在表单 <input>
、<textarea>
及 <select>
元素上创建双向数据绑定。根据控件类型自动选择正确的方法来更新元素。
<!-- 在文本输入框中使用 v-model -->
<input v-model="message">
<!-- 在单选按钮中使用 v-model -->
<input type="radio" v-model="picked" value="One">
<!-- 在选择框中使用 v-model -->
<select v-model="selected">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
4.v-for
v-for
指令基于一个数组来渲染一个列表。该指令需要使用 item in items
形式的特殊语法,其中 items
是源数据数组,而 item
是数组元素迭代的别名。
<ul>
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</ul>
使用 :key
是为了给 Vue 一个提示,以便它可以跟踪每个节点的身份,从而重用和重新排序现有元素。
5.v-if, v-else-if, v-else
v-if
指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
<!-- 使用 v-if -->
<h1 v-if="awesome">Vue is awesome!</h1>
<!-- 使用 v-else-if -->
<h1 v-else-if="ok">Vue is ok!</h1>
<!-- 使用 v-else -->
<h1 v-else>Vue is not great.</h1>
这些指令可以用来进行条件渲染,v-else-if
和 v-else
必须紧跟在 v-if
或 v-else-if
元素之后。
6.对‘value’属性感到困惑
-
在 Vue 3 中,当你使用
ref
函数来创建响应式引用时,需要通过.value
属性来访问或修改该变量的值。这是因为ref
返回的是一个包含value
属性的响应式引用对象。例如:
import { ref } from 'vue'; const count = ref(0); // 读取 count 的值 console.log(count.value); // 输出 0 // 修改 count 的值 count.value = 1;
这种设计允许 Vue 包装基本类型值(如字符串、数字、布尔值等)并使其成为响应式的。
-
对于对象和数组,通常会使用
reactive
函数,它不需要.value
属性来访问或修改数据,因为reactive
返回的是一个响应式代理,直接操作对象的属性即可。import { reactive } from 'vue'; const state = reactive({ count: 0, message: 'Hello' }); // 直接读取和修改 state 对象的属性 console.log(state.count); // 输出 0 state.count = 1;
-
在模板中使用
ref
创建的响应式引用时,不需要使用.value
来访问它们。Vue 的模板编译器会自动处理这些引用,使其在模板中直接可用。<template> <div>{{ count }}</div> </template> <script> import { ref } from 'vue'; export default { setup() { const count = ref(0); // 在模板中,直接使用 count 而不是 count.value return { count }; } }; </script>
在 JavaScript 中使用
ref
创建的响应式引用时,记得总是通过.value
属性来访问或修改它的值。而在模板中,你可以直接使用引用的名称。 -
注意,解包只能在顶层属性上有效
<template> Counter:{{ count.foo +1 }} //展示 Counter:[object Object]1 Counter: {{ count.foo.value + 1 }} // 正确地显示 `count.foo.value` 的值加 `1` 的结果 <button @click="add">Increase</button> </template> <script setup> import { ref } from "vue"; const count = { foo: ref(0) }; function add() { count.foo.value++; console.log(count.foo.value); } </script>
三、组件基础
在 Vue 3 中,组件是构建应用的基本单元。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面,Vue 组件是预定义选项的一个实例,这些选项是用来定义一个新的自定义元素。以下是 Vue 3 组件基础的关键概念:
1.创建组件
组件可以通过两种方式创建:使用 Vue.extend
(在 Vue 2 中常见,Vue 3 中不推荐)或者使用单文件组件(.vue
文件)。
- 单文件组件(推荐)
<!-- MyComponent.vue -->
<template>
<div class="my-component">
{{ message }}
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, Vue!'
};
}
};
</script>
<style scoped>
.my-component {
/* 组件样式 */
}
</style>
2.组件的数据
组件的数据必须是一个函数,这样每个实例可以维护一份被返回对象的独立的拷贝。
export default {
data() {
return {
count: 0
};
}
};
3.组件的 Props
Props 是组件的自定义属性,用于从父组件接收数据。子组件需要显式地用 props
选项声明它期望获得的数据。
export default {
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // 或者任何其他构造函数
}
};
3.组件的方法
组件的方法应该定义在 methods
对象中,可以在模板中或组件实例中调用这些方法。
export default {
data() {
return {
count: 0
};
},
methods: {
increment() {
this.count++;
}
}
};
4.组件的生命周期钩子
组件实例有其生命周期,你可以通过生命周期钩子在不同阶段执行代码。
export default {
mounted() {
console.log('组件已挂载!');
},
updated() {
console.log('组件已更新!');
},
unmounted() {
console.log('组件已卸载!');
}
};
5.组件的模板和样式
组件的模板定义了组件的 HTML 结构。样式可以是全局的,也可以通过添加 scoped
属性来限制在当前组件内部。
6.组件的注册
组件可以是全局注册的,也可以是局部注册的。局部注册的组件只能在注册它们的组件中使用。
- 全局注册
import Vue from 'vue';
import MyComponent from './MyComponent.vue';
Vue.component('MyComponent', MyComponent);
- 局部注册
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
}
};
7.组件的使用
注册组件后,你可以在父组件的模板中像使用普通 HTML 元素一样使用它。
<my-component></my-component>
8.组件通信
- Props down: 父组件通过 props 向子组件传递数据。
- Events up: 子组件通过事件向父组件发送消息。
9.单文件组件的 <script setup>
Vue 3.2 引入了 <script setup>
,这是在单文件组件中使用 Composition API 的语法糖。
<script setup>
import { ref } from 'vue';
const count = ref(0);
function increment() {
count.value++;
}
</script>
四、defineProps,defineEmits的使用
在 Vue 3 中,<script setup>
是一种新的组件编写方式,它使得使用 Composition API 更加简洁。在 <script setup>
中,defineProps
和 defineEmits
是两个编译时的宏,它们用于在组件中声明 props 和自定义事件。
1.defineProps
defineProps
用于声明组件接收的 props。它可以接受一个类型定义对象或一个 TypeScript 接口。
- #### 使用类型定义对象:
<script setup>
const props = defineProps({
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function
});
</script>
- #### 使用 TypeScript 接口:
<script setup lang="ts">
interface Props {
title: string;
likes: number;
isPublished: boolean;
commentIds: number[];
author: object;
callback: Function;
}
const props = defineProps<Props>();
</script>
在模板中,你可以直接使用 props
中的属性,无需通过 this
访问它们。
2.defineEmits
defineEmits
用于声明组件可以发出的自定义事件。它可以接受一个事件名称数组或一个 TypeScript 类型定义。
- #### 使用事件名称数组:
<script setup>
const emit = defineEmits(['update:title', 'delete:post']);
</script>
- #### 使用 TypeScript 类型定义:
<script setup lang="ts">
const emit = defineEmits<{
(e: 'update:title', title: string): void;
(e: 'delete:post', postId: number): void;
}>();
</script>
在组件内部,你可以使用 emit
函数来发出事件:
function updateTitle(newTitle) {
emit('update:title', newTitle);
}
function deletePost(postId) {
emit('delete:post', postId);
}
在父组件中,你可以监听这些事件并作出相应的处理:
<template>
<ChildComponent
@update:title="handleTitleUpdate"
@delete:post="handlePostDelete"
/>
</template>
defineProps
和 defineEmits
提供了一种类型安全的方式来声明和使用 props 和自定义事件,特别是在使用 TypeScript 时。它们只能在 <script setup>
中使用,并且由于它们是编译时的宏,它们在运行时不会被包含在最终的 JavaScript 代码中。
请注意,defineProps
和 defineEmits
只能在 <script setup>
标签内部使用一次,并且不能与其他 JavaScript 逻辑混合使用。如果你需要执行其他逻辑,应该在它们之外进行。
无论是 defineEmits 还是 defineProps (用于声明props),都不需要导入。当使用 script setup. 时,它们会自动可用。
五、 声明额外选项
有一些Options API 方法的属性在script setup 中不受支持
-
name
-
inheritAttrs
-
插件或库需要的自定义选项
解决方案是在同一组件中定义两个不同的脚本,如脚本设置RFC中所定义的那样
<script>
export default {
name:’CustomName’,
inheritAttrs:false,
customOptions:{}
}
</script>
<script setup>
// script setup logic
</script>
六、 定义异步组件
defineAsyncComponent
是 Vue 3 中用于定义异步组件的函数。异步组件是指那些不会在初始渲染中同步加载的组件,而是在需要时才加载,这有助于减少应用程序的初始包大小,实现更快的加载时间。
以下是一个使用 defineAsyncComponent
的例子:
1.基本用法
// 在你的组件文件中
import { defineAsyncComponent } from 'vue';
// 使用 defineAsyncComponent 定义一个异步组件
const AsyncComponent = defineAsyncComponent(() =>
import('./components/MyAsyncComponent.vue')
);
export default {
components: {
AsyncComponent
}
};
在这个例子中,MyAsyncComponent.vue
是一个异步加载的组件。当 AsyncComponent
被用作模板中的标签时,Vue 会在组件需要渲染时自动加载它。
2.在模板中使用
<template>
<div>
<!-- 使用异步组件 -->
<AsyncComponent />
</div>
</template>
3.高级用法
defineAsyncComponent
还接受一个对象作为参数,允许你指定加载状态时的行为,例如显示加载指示器、错误处理或设置超时时间。
import { defineAsyncComponent } from 'vue';
const AsyncComponent = defineAsyncComponent({
// 加载异步组件的函数
loader: () => import('./components/MyAsyncComponent.vue'),
// 加载异步组件时使用的组件
loadingComponent: LoadingComponent, // LoadingComponent 是一个组件,用于在加载异步组件时显示
// 如果加载失败,使用的组件
errorComponent: ErrorComponent, // ErrorComponent 是一个组件,用于在加载失败时显示
// 在显示错误组件之前的延迟时间(毫秒)
errorDelay: 200,
// 在显示加载组件之前的延迟时间(毫秒)
delay: 200,
// 最长等待时间,在此时间之后如果组件还没有加载成功,则显示错误组件
timeout: 3000
});
export default {
components: {
AsyncComponent
}
};
在这个高级用法中,你可以定义 loader
函数来加载组件,以及 loadingComponent
和 errorComponent
来分别在加载和错误状态下显示。你还可以设置延迟和超时时间来优化用户体验。
异步组件在大型应用程序中非常有用,特别是当你有一些只在特定情况下才需要的重组件时,使用异步组件可以有效地分割代码,按需加载,从而加快应用程序的初始加载速度。
八、vue3生命周期钩子函数
在 Vue 3 中,生命周期钩子函数是一组特殊的函数,它们提供了在组件的不同阶段执行代码的能力。这些生命周期钩子对应于组件的创建、更新、销毁等关键时刻。
在 Vue 3 中,生命周期钩子是一组特殊的函数,它们在组件的不同阶段被调用。这些生命周期钩子允许你在组件创建、更新、销毁等关键时刻执行代码。以下是 Vue 3 中的主要生命周期钩子:
1.挂载阶段(Mounting Phase)
beforeCreate
: 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。created
: 在实例创建完成后被立即调用。在这一步,实例已完成数据观测、属性和方法的运算,watch/event
事件回调已设置,但$el
属性目前尚不可用。beforeMount
: 在挂载开始之前被调用:相关的render
函数首次被调用。mounted
: 在实例被挂载后调用。此时,你可以访问到 DOM 元素和组件实例 (this
指向组件实例)。
2.更新阶段(Updating Phase)
beforeUpdate
: 在数据变化之后,DOM 被更新之前调用,可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。updated
: 在由于数据变化导致的虚拟 DOM 重新渲染和打补丁之后调用。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。
3.卸载阶段(Unmounting Phase)
beforeUnmount
: 在卸载组件实例之前调用。在这一步,实例仍然完全可用。unmounted
: 在组件实例被卸载之后调用。当这个钩子被调用时,组件实例已经被销毁,你不能再访问组件实例。
4.错误处理阶段(Error Handling Phase)
errorCaptured
: 当捕获一个来自子孙组件的错误时被调用。此钩子在捕获错误时会收到三个参数:错误对象、发生错误的组件实例和一个包含错误来源信息的字符串。
5.组合式 API 中的生命周期钩子
Vue 3 引入了组合式 API,它提供了与上述生命周期钩子对应的函数,可以在 setup
函数中使用:
onBeforeMount
onMounted
onBeforeUpdate
onUpdated
onBeforeUnmount
onUnmounted
onErrorCaptured
这些函数接受一个回调函数作为参数,该回调函数将在相应的生命周期钩子被触发时执行。
import { onMounted, onUpdated } from 'vue';
export default {
setup() {
onMounted(() => {
console.log('组件已挂载!');
});
onUpdated(() => {
console.log('组件已更新!');
});
// ...其他逻辑
}
};
使用组合式 API 的生命周期函数可以让你在使用 setup
函数时更灵活地组织代码,同时也使得逻辑复用变得更加容易。
九、Composition API
Vue 3 引入了 Composition API,这是一组基于函数的 API,它们允许你更灵活地组织和重用代码,特别是在构建大型或复杂组件时。Composition API 提供了一种新的方式来组合和管理组件的逻辑。
1.基本概念
Composition API 的核心是 setup
函数。这个函数是组件的入口点,它在组件创建之前执行,允许你定义响应式状态、计算属性、方法和生命周期钩子。
import { ref, onMounted } from 'vue';
export default {
setup() {
// 定义响应式状态
const count = ref(0);
// 生命周期钩子
onMounted(() => {
console.log('组件已挂载');
});
// 返回值将暴露给模板
return {
count
};
}
};
2.响应式引用:ref
ref
用于定义一个响应式的引用类型。它接受一个参数值,并返回一个响应式且可变的 ref 对象。这个对象有一个 .value
属性,指向传入的参数值。
import { ref } from 'vue';
const count = ref(0);
3.响应式状态:reactive
reactive
用于定义一个响应式的对象。它接受一个普通对象并返回该对象的响应式代理。
import { reactive } from 'vue';
const state = reactive({
count: 0,
message: 'Hello'
});
4.计算属性:computed
computed
用于创建一个计算属性,它接受一个 getter 函数,并根据其返回值返回一个不可变的响应式引用。
import { computed } from 'vue';
const count = ref(0);
const doubled = computed(() => count.value * 2);
5.侦听器:watch 和 watchEffect
watch
和 watchEffect
用于侦听响应式引用或响应式状态的变化,并执行副作用。
import { ref, watch, watchEffect } from 'vue';
const count = ref(0);
// watch 侦听器
watch(count, (newValue, oldValue) => {
console.log(`count 变化了:${oldValue} -> ${newValue}`);
});
// watchEffect 会立即执行一次,并在依赖变化时重新执行
watchEffect(() => {
console.log(`count 的当前值是:${count.value}`);
});
6.生命周期钩子
Composition API 提供了一系列的生命周期钩子函数,如 onMounted
、onUpdated
和 onUnmounted
。
import { onMounted } from 'vue';
onMounted(() => {
console.log('组件已挂载');
});
7.<script setup>
Vue 3.2 引入了 <script setup>
,这是一个编译时的语法糖,它使得使用 Composition API 更加简洁。
<script setup>
import { ref } from 'vue';
const count = ref(0);
</script>
8.提取和重用逻辑
Composition API 的一个主要优势是能够更容易地提取和重用组件逻辑。你可以将相关的响应式状态、计算属性和函数封装到一个函数中,然后在多个组件之间共享这个函数。
// useCounter.js
import { ref } from 'vue';
export function useCounter() {
const count = ref(0);
const increment = () => {
count.value++;
};
return { count, increment };
}
然后在组件中使用这个函数:
import { useCounter } from './useCounter';
export default {
setup() {
const { count, increment } = useCounter();
return { count, increment };
}
};
Composition API 提供了更多的灵活性和组织代码的能力,特别是对于那些需要处理复杂逻辑的组件。通过使用 Composition API,你可以更容易地跟踪和管理组件的状态和逻辑,使得代码更加清晰和可维护。
十、在 Vue 3 项目中使用 TypeScript
在 Vue 3 项目中使用 TypeScript 可以为你的代码提供类型检查和更好的编辑器支持,从而提高代码质量和开发效率。以下是在 Vue 3 项目中使用 TypeScript 的基本步骤:
1. 创建一个新的 Vue 3 + TypeScript 项目
如果你正在创建一个新项目,可以使用 Vue CLI 或 Vite 来设置一个带有 TypeScript 支持的项目。
使用 Vue CLI:
vue create my-project
# 选择 "Manually select features"
# 选择 TypeScript
# 完成其他配置并创建项目
使用 Vite:
npm create vite@latest my-vue-app --template vue-ts
# 或者使用 Yarn
yarn create vite my-vue-app --template vue-ts
2. 在现有项目中添加 TypeScript 支持
如果你的项目是用 JavaScript 创建的,你需要添加 TypeScript 依赖并配置项目以支持 TypeScript。
npm install --save-dev typescript
# 或者使用 Yarn
yarn add --dev typescript
然后,初始化 TypeScript 配置文件 tsconfig.json
:
npx tsc --init
# 或者使用 Yarn
yarn tsc --init
在 tsconfig.json
中,你可以根据需要配置 TypeScript 编译器选项。
3. 配置 Vue 项目以使用 TypeScript
确保你的 tsconfig.json
包含 Vue 的类型定义:
{
"compilerOptions": {
"types": ["vue"],
// ...其他配置
}
// ...其他配置
}
如果你使用的是 Vue CLI,它应该已经为你配置好了大部分 TypeScript 支持。如果你使用的是其他构建工具,如 Vite、Webpack 等,你可能需要安装和配置相应的 TypeScript 插件或加载器。
4. 编写 TypeScript 代码
在 .vue
文件中,你可以使用 <script lang="ts">
来编写 TypeScript 代码:
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
data() {
return {
message: 'Hello Vue with TypeScript!'
};
},
methods: {
greet(): void {
console.log(this.message);
}
}
});
</script>
对于 Composition API 和 <script setup>
,你可以直接使用 TypeScript:
<script setup lang="ts">
import { ref } from 'vue';
const count = ref<number>(0);
function increment(): void {
count.value++;
}
</script>
5. 使用类型和接口
你可以定义类型和接口来为组件的 props、状态和事件提供类型检查:
<script setup lang="ts">
import { ref, defineProps } from 'vue';
interface Props {
title: string;
}
const props = defineProps<Props>();
const count = ref<number>(0);
function increment(): void {
count.value++;
}
</script>
6. 类型声明文件
对于全局类型或模块扩展,你可以创建 .d.ts
文件来声明类型:
// shims-vue.d.ts
declare module '*.vue' {
import { DefineComponent } from 'vue';
const component: DefineComponent<{}, {}, any>;
export default component;
}
7. 运行和构建项目
使用 Vue CLI 或你的构建工具来运行和构建项目。TypeScript 代码将被编译为 JavaScript。
npm run serve
# 或者使用 Yarn
yarn serve
确保你的编辑器支持 TypeScript,这样你就可以享受到自动完成、类型检查和其他功能。如果你使用的是 Visual Studio Code,它已经内置了对 TypeScript 的支持。
8.使用 TypeScript 编写 Composition API 代码。
在 Vue 3 中,使用 TypeScript 编写 Composition API 代码可以提供更好的类型推断和代码提示,从而提高代码的可维护性和可读性。
以下是一个使用 TypeScript 编写的 Vue 3 组件示例,它展示了如何在 <script setup>
中使用 Composition API。
首先,确保你的项目配置了 TypeScript 支持。然后,你可以按照以下步骤编写组件:
- 在
<script setup lang="ts">
块中编写 TypeScript 代码。 - 使用
defineProps
和defineEmits
宏来声明 props 和自定义事件。 - 使用 Composition API 的函数,如
ref
,reactive
,computed
,watch
,onMounted
等。
下面是一个使用 TypeScript 的 Vue 3 组件示例:
<template>
<div>
<input v-model="message" placeholder="Edit me" />
<p>Message is: {{ message }}</p>
<button @click="increment">Count is: {{ count }}</button>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
// 使用 defineProps 定义 props 类型
interface Props {
initialCount: number;
step: number;
}
const props = defineProps<Props>();
// 使用 defineEmits 定义自定义事件和它们的类型
const emit = defineEmits<{
(event: 'count-updated', count: number): void;
}>();
// 使用 ref 创建响应式引用
const count = ref(props.initialCount);
// 使用 computed 创建计算属性
const doubledCount = computed(() => count.value * 2);
// 使用 ref 创建另一个响应式引用
const message = ref('');
// 定义一个方法来更新 count
function increment() {
count.value += props.step;
emit('count-updated', count.value);
}
</script>
在这个示例中,我们定义了两个 props:initialCount
和 step
,并为它们提供了类型。我们还定义了一个自定义事件 count-updated
,它会在每次点击按钮时触发,并传递当前的 count
值。
我们使用 ref
创建了两个响应式引用:count
和 message
。count
是一个计数器,而 message
是一个绑定到输入框的文本。我们还使用 computed
创建了一个计算属性 doubledCount
,它会计算 count
的两倍。
最后,我们定义了一个 increment
方法来增加 count
的值,并在每次增加时发出 count-updated
事件。
请注意,当你在 <script setup>
中使用 TypeScript 时,你不需要导出一个默认对象,因为 <script setup>
是一个语法糖,它会自动处理导出。此外,由于 defineProps
和 defineEmits
是编译时宏,它们不会出现在最终的 JavaScript 输出中。