当前位置: 代码迷 >> 综合 >> vue3.0特性 持续更新
  详细解决方案

vue3.0特性 持续更新

热度:102   发布时间:2023-11-21 05:27:07.0

1.创建一个应用实例

  • 每个 Vue 应用都是通过用 createApp 函数创建一个新的应用实例
  • 该应用实例是用来在应用中注册“全局”组件的
const app = Vue.createApp({
    })
app.component('SearchInput', SearchInputComponent)
app.directive('focus', FocusDirective)
app.use(LocalePlugin)
  • 应用实例暴露的大多数方法都会返回该同一实例,允许链式
Vue.createApp({
    }).component('SearchInput', SearchInputComponent).directive('focus', FocusDirective).use(LocalePlugin)

2.setup

为了开始使用组合式 API,我们首先需要一个可以实际使用它的地方。在 Vue 组件中,我们将此位置称为 setup
新的 setup 选项在组件创建之前执行,一旦 props 被解析,就将作为组合式 API 的入口。
setup 选项是一个接收 props 和 context 的函数,我们将在之后进行讨论。此外,我们将 setup 返回的所有内容都暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板
使用 setup 函数时,它将接收两个参数:

  • props
  • context
    props 是响应式的,当传入新的 prop 时,它将被更新。
    但是,因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性。
    如果需要解构 prop,可以在 setup 函数中使用 toRefs 函数来完成此操作:
// MyBook.vueimport {
     toRefs } from 'vue'setup(props) {
    const {
     title } = toRefs(props)console.log(title.value)
}

如果 title 是可选的 prop,则传入的 props 中可能没有 title 。在这种情况下,toRefs 将不会为 title 创建一个 ref 。你需要使用 toRef 替代它:

// MyBook.vue
import {
     toRef } from 'vue'
setup(props) {
    const title = toRef(props, 'title')console.log(title.value)
}

Context

传递给 setup 函数的第二个参数是 context。context 是一个普通的 JavaScript 对象,它暴露组件的三个 property:

// MyBook.vueexport default {
    setup(props, context) {
    // Attribute (非响应式对象)console.log(context.attrs)// 插槽 (非响应式对象)console.log(context.slots)// 触发事件 (方法)console.log(context.emit)}
}

context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构。

// MyBook.vue
export default {
    setup(props, {
      attrs, slots, emit }) {
    ...}
}

attrs 和 slots 是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以 attrs.x 或 slots.x 的方式引用 property。请注意,与 props 不同,attrs 和 slots 是非响应式的。如果你打算根据 attrs 或 slots 更改应用副作用,那么应该在 onUpdated 生命周期钩子中执行此操作

注意,从 setup 返回的 refs 在模板中访问时是被自动浅解包的,因此不应在模板中使用 .value。

setup 还可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态:

// MyBook.vueimport {
     h, ref, reactive } from 'vue'export default {
    setup() {
    const readersNumber = ref(0)const book = reactive({
     title: 'Vue 3 Guide' })// 请注意这里我们需要显式调用 ref 的 valuereturn () => h('div', [readersNumber.value, book.title])}
}

使用 Provide

在 setup() 中使用 provide 时,我们首先从 vue 显式导入 provide 方法。这使我们能够调用 provide 来定义每个 property。

provide 函数允许你通过两个参数定义 property:

name ( 类型)
value
使用 MyMap 组件后,provide 的值可以按如下方式重构:

<!-- src/components/MyMap.vue -->
<template><MyMarker />
</template><script>
import {
     provide } from 'vue'
import MyMarker from './MyMarker.vue'export default {
    components: {
    MyMarker},setup() {
    provide('location', 'North Pole')provide('geolocation', {
    longitude: 90,latitude: 135})}
}
</script>

使用 inject

在 setup() 中使用 inject 时,也需要从 vue 显式导入。导入以后,我们就可以调用它来定义暴露给我们的组件方式。

inject 函数有两个参数:

要 inject 的 property 的 name
默认值 (可选)
使用 MyMarker 组件,可以使用以下代码对其进行重构:

<!-- src/components/MyMarker.vue -->
<script>
import {
     inject } from 'vue'export default {
    setup() {
    const userLocation = inject('location', 'The Universe')const userGeolocation = inject('geolocation')return {
    userLocation,userGeolocation}}
}
</script>

响应性

添加响应性

为了增加 provide 值和 inject 值之间的响应性,我们可以在 provide 值时使用 ref 或 reactive。

使用 MyMap 组件,我们的代码可以更新如下:

<!-- src/components/MyMap.vue -->
<template><MyMarker />
</template><script>
import {
     provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue'export default {
    components: {
    MyMarker},setup() {
    const location = ref('North Pole')const geolocation = reactive({
    longitude: 90,latitude: 135})provide('location', location)provide('geolocation', geolocation)}
}
</script>

现在,如果这两个 property 中有任何更改,MyMarker 组件也将自动更新!

#修改响应式 property
当使用响应式 provide / inject 值时,建议尽可能将对响应式 property 的所有修改限制在定义 provide 的组件内部。

例如,在需要更改用户位置的情况下,我们最好在 MyMap 组件中执行此操作。

<!-- src/components/MyMap.vue -->
<template><MyMarker />
</template><script>
import {
     provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue'export default {
    components: {
    MyMarker},setup() {
    const location = ref('North Pole')const geolocation = reactive({
    longitude: 90,latitude: 135})provide('location', location)provide('geolocation', geolocation)return {
    location}},methods: {
    updateLocation() {
    this.location = 'South Pole'}}
}
</script>

然而,有时我们需要在注入数据的组件内部更新 inject 的数据。在这种情况下,我们建议 provide 一个方法来负责改变响应式 property。

<!-- src/components/MyMap.vue -->
<template><MyMarker />
</template><script>
import {
     provide, reactive, ref } from 'vue'
import MyMarker from './MyMarker.vue'export default {
    components: {
    MyMarker},setup() {
    const location = ref('North Pole')const geolocation = reactive({
    longitude: 90,latitude: 135})const updateLocation = () => {
    location.value = 'South Pole'}provide('location', location)provide('geolocation', geolocation)provide('updateLocation', updateLocation)}
}
</script>
<!-- src/components/MyMarker.vue -->
<script>
import {
     inject } from 'vue'export default {
    setup() {
    const userLocation = inject('location', 'The Universe')const userGeolocation = inject('geolocation')const updateUserLocation = inject('updateLocation')return {
    userLocation,userGeolocation,updateUserLocation}}
}
</script>

最后,如果要确保通过 provide 传递的数据不会被 inject 的组件更改,我们建议对提供者的 property 使用 readonly。

<!-- src/components/MyMap.vue -->
<template><MyMarker />
</template><script>
import {
     provide, reactive, readonly, ref } from 'vue'
import MyMarker from './MyMarker.vue'export default {
    components: {
    MyMarker},setup() {
    const location = ref('North Pole')const geolocation = reactive({
    longitude: 90,latitude: 135})const updateLocation = () => {
    location.value = 'South Pole'}provide('location', readonly(location))provide('geolocation', readonly(geolocation))provide('updateLocation', updateLocation)}
}
</script>

3.带 ref 的响应式变量

这些函数接受一个回调,当钩子被组件调用时,该回调将被执行。
只有访问嵌套的 ref 时需要在模板中添加 .value:

让我们将其添加到 setup 函数中:

// src/components/UserRepositories.vue `setup` function
import {
     fetchUserRepositories } from '@/api/repositories'
import {
     ref, onMounted } from 'vue'// 在我们的组件中
setup (props) {
    const repositories = ref([])const getUserRepositories = async () => {
    repositories.value = await fetchUserRepositories(props.user)}onMounted(getUserRepositories) // 在 `mounted` 时调用 `getUserRepositories`return {
    repositories,getUserRepositories}
}

使用解构的两个 property 的响应性都会丢失。对于这种情况,我们需要将我们的响应式对象转换为一组 ref。这些 ref 将保留与源对象的响应式关联:

import {
     reactive, toRefs } from 'vue'const book = reactive({
    author: 'Vue Team',year: '2020',title: 'Vue 3 Guide',description: 'You are reading this book right now ;)',price: 'free'
})let {
     author, title } = toRefs(book)title.value = 'Vue 3 Detailed Guide' // 我们需要使用 .value 作为标题,现在是 ref
console.log(book.title) // 'Vue 3 Detailed Guide'

4.watch 响应式更改

就像我们在组件中使用 watch 选项并在 user property 上设置侦听器一样,我们也可以使用从 Vue 导入的 watch 函数执行相同的操作。它接受 3 个参数:

  • 一个想要侦听的响应式引用或 getter 函数
  • 一个回调
  • 可选的配置选项
  • 下面让我们快速了解一下它是如何工作的
import {
     ref, watch } from 'vue'const counter = ref(0)
watch(counter, (newValue, oldValue) => {
    console.log('The new counter value is: ' + counter.value)
})

现在我们将其应用到我们的示例中:

// src/components/UserRepositories.vue `setup` function
import {
     fetchUserRepositories } from '@/api/repositories'
import {
     ref, onMounted, watch, toRefs } from 'vue'// 在我们组件中
setup (props) {
    // 使用 `toRefs` 创建对prop的 `user` property 的响应式引用const {
     user } = toRefs(props)const repositories = ref([])const getUserRepositories = async () => {
    // 更新 `prop.user` 到 `user.value` 访问引用值repositories.value = await fetchUserRepositories(user.value)}onMounted(getUserRepositories)// 在 user prop 的响应式引用上设置一个侦听器watch(user, getUserRepositories)return {
    repositories,getUserRepositories}
}

5.独立的 computed 属性

与 ref 和 watch 类似,也可以使用从 Vue 导入的 computed 函数在 Vue 组件外部创建计算属性。让我们回到 counter 的例子:

import {
     ref, computed } from 'vue'const counter = ref(0)
const twiceTheCounter = computed(() => counter.value * 2)counter.value++
console.log(counter.value) // 1
console.log(twiceTheCounter.value) // 2

6.生命周期

选项API setup
beforeMount onBeforeMount
mounted onMounted
updated onUpdated
unmounted onUnmounted

因为 setup 是围绕 beforeCreate 和 created 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 setup 函数中编写。