VUE3 语法
setup
vue3 中用 setup 函数整合了所有的 api;只执行一次,在生命周期函数前执行,所以在 setup 函数中拿不到当前实例 this,不能用 this 来调用 vue2 写法中定义的方法
它将接受两个参数:props、context
1 | // props - 组件接受到的属性 context - 上下文 |
props
setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新
但是,因为 props 是响应式的,不能使用 ES6 解构,因为它会消除 prop 的响应性
如果需要解构 prop,可以通过使用 setup 函数中的 toRefs 来安全地完成此操作
1 | import { toRefs } from 'vue' |
context
context 暴露三个组件的 property:{ attrs, slots, emit }
它是一个普通的 JavaScript 对象,不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构
setup
方法和以下是等效的
1 | <script setup> |
ref、reactive
ref 可以将某个普通值包装成响应式数据,仅限于简单值,内部是将值包装成对象,再通过 defineProperty 来处理的
通过 ref 包装的值,取值和设置值的时候,需用通过 .value来进行设置
可以用 ref 来获取组件的引用,替代 this.$refs 的写法
reactive 对复杂数据进行响应式处理,它的返回值是一个 proxy 对象,在 setup 函数中返回时,可以用 toRefs 对 proxy 对象进行结构,方便在 template 中使用
使用如下:
1 | <template> |
computed
1 | // computed |
注意
computed返回的是一个ref对象。
watch
基本
1 | import { ref, watch } from 'vue' |
深度监听
1 | import { ref, watch } from 'vue' |
路由监听
1 | import { ref, reactive, watch } from 'vue' |
立即执行
我们可以通过传入 immediate: true
选项来强制侦听器的回调立即执行:
1 | watch( |
同时监听多个属性
1 | import { watch } from 'vue'; |
watchEffect
响应式地跟踪函数中引用的响应式数据,当响应式数据改变时,会重新执行函数
1 | const count = ref(0) |
还可以停止监听,watchEffect 返回一个函数,执行后可以停止监听
与 vue2 一样:
1 | const unwatch = this.$watch('say', curVal => {}) |
Props
一个组件需要显式声明它所接受的 props,这样 Vue 才能知道外部传入的哪些是 props。
setup
在使用 <script setup>
的单文件组件中,props 可以使用 defineProps()
宏来声明:
vue
1 | <script setup> |
TS
1 | <script setup lang="ts"> |
注意
props 是 Ref 类型,内部的属性不是。
使用自定义类型
1 | interface TGoods { |
默认值
1 | const props = defineProps({ |
非setup
在没有使用 <script setup>
的组件中,props 可以使用 props
选项来声明:
JS
1 | export default { |
注意传递给 defineProps()
的参数和提供给 props
选项的值是相同的,两种声明方式背后其实使用的都是 props 选项。
props属性监听
1 | <script setup> |
v-model
v-model
可以在组件上使用以实现双向绑定。
组合式
新版本-单个属性
从 Vue 3.4 开始,推荐的实现方式是使用 defineModel()
宏:
自定义组件中
1 | <!-- Child.vue --> |
父组件可以用 v-model
绑定一个值:
1 | <!-- Parent.vue --> |
defineModel()
返回的值是一个 ref。
它可以像其他 ref 一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用:
- 它的
.value
和父组件的v-model
的值同步; - 当它被子组件变更了,会触发父组件绑定的值一起更新。
defineModel
是一个便利宏。
编译器将其展开为以下内容:
- 一个名为
modelValue
的 prop,本地 ref 的值与其同步; - 一个名为
update:modelValue
的事件,当本地 ref 的值发生变更时触发。
TS中设置类型
1 | const model = defineModel<number[]>() |
新版本-多个属性
1 | <script setup> |
父组件可以用 v-model
绑定多个值:
1 | <Child v-model:firstName="firstName" v-model:lastName="lastName" /> |
旧版本-单个属性
在 3.4 版本之前,你一般会按照如下的方式来实现上述相同的子组件:
vue
1 | <!-- Child.vue --> |
父组件可以用 v-model
绑定一个值:
1 | <!-- Parent.vue --> |
内部实际将被编译为:
1 | <!-- Parent.vue --> |
旧版本-多个属性
1 | <script setup> |
选项式
选项式没有新旧版本的区别
单个属性
1 | <!-- CustomInput.vue --> |
或者
1 | export default { |
可能多个类型
1 | export default { |
使用
1 | <CustomInput v-model="searchText" /> |
多个属性
1 | <script> |
使用
1 | <UserName |
事件
1 | <script setup> |
TS中使用
1 | <script setup lang="ts"> |
生命周期
通过在生命周期钩子前面加上on
来访问组件的生命周期钩子
因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们
换句话说,
想在
beforeCreate
和created
中编写的任何代码都应该直接在setup
函数中编写
周期函数
1 | onMounted(() => { |
Vue Router
引用
useRoute、useRouter
1 | import {useRoute, useRouter} from 'vue-router' |
跳转
跳转
1 | // 字符串路径 |
替换
1 | router.push({ path: '/home', replace: true }) |
前进后退
1 | // 向前移动一条记录,与 router.forward() 相同 |
参数
1 | import { useRoute } from 'vue-router' |
vuex
使用 useStore 来获取 store 对象 从 vuex 中取值时,要注意必须使用 computed 进行包装,这样 vuex 中状态修改后才能在页面中响应
1 | import {useStore} from 'vuex' |
复用
在 Vue 3 中,混合(Mixins)依然是可用的,尽管 Vue 3 更加推荐使用 Composition API 来进行代码复用和管理。
使用 Mixins 的方法
定义混合对象:
1 | // myMixin.js |
在组件中使用混合:
1 | // MyComponent.vue |
使用 Composition API
使用 Composition API 替代 Mixins
在 Vue 3 中,推荐使用 Composition API 进行逻辑复用。通过 Composition API,你可以创建组合函数来封装逻辑,然后在多个组件中复用这些函数。以下是使用 Composition API 的一个示例:
定义组合函数:
1 | // useMixin.js |
在组件中使用组合函数:
1 | // MyComponent.vue |
使用依赖注入
要为组件后代提供数据,需要使用到 provide()
函数:
1 | <script setup> |
要注入上层组件提供的数据,需使用 inject()
函数:
1 | <script setup> |
如果提供的值是一个 ref,注入进来的会是该 ref 对象,而不会自动解包为其内部的值。这使得注入方组件能够通过 ref 对象保持了和供给方的响应性链接。
总结
虽然 Vue 3 仍然支持使用 Mixins,但 Vue 团队推荐使用 Composition API,因为它提供了更灵活、更可组合的方式来管理和复用逻辑,并且可以更好地处理复杂的组件逻辑和状态。