vue3更新不完全学习总结

580 阅读4分钟

数据双向绑定改动

vue3采用proxy代理的方式实现对象劫持,同时也支持Object.defineproperty方法进行对象劫持(为了兼容IE浏览器)

注意事项

  • 代理返回的新对象!==对源对象
  • 由于使用了proxy代理对象,所以在使用时不可以使用对象展开符直接展开对象获取属性,否则会使对象的响应式失效

Teleport选择插入

新增内置标签Teleport,支持将子组件自由插入到dom文档的任何地方

<teleport to="body">
    <div>我是需要插入到body的子元素</div>
</teleport>

组合式API

与其相对的是vue2的选项式API,组合式API可以将相关代码的距离拉的更近或者进行模块化引入。

新增setup()函数,有propscontext两个参数,props为父级传入的属性,context为包含有attrsslotsemits三个函数的对象。运行于created(包含)之前的周期,所以在setup()中无法获取到其他周期信息

<template>
// dom
</template>
<script>
    export default{
        setup(props,{attrs,slots,emits}){
            // do somethings
            return {}
        }
    }
</script>

在setup函数中getCurrentInstance获取组件实例

import { getCurrentInstance } from 'vue'

const MyComponent = {
  setup() {
    const internalInstance = getCurrentInstance()

    internalInstance.appContext.config.globalProperties // 访问 globalProperties
  }
}

vue3的Vue暴露出一些新的模块以供调用用来辅助组合式API

生命周期:

beforeCreate -> use setup()
created -> use setup()
beforeMount -> onBeforeMount
mounted -> onMounted
boforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeUnmount -> onBeforeUnmount
unmount -> onUnmount
// 捕获来自一个子孙组件的错误
errorCaptured -> onErrorCaptured
// 跟踪虚拟DOM重新渲染时调用,告诉你哪个操作跟踪了组件,对象,键
renderTracked -> onRenderTracked
// 跟踪虚拟DOM重新渲染时调用,告诉你哪个操作触发了重新渲染,对象,键
renderTriggered -> onRenderTriggered

响应性API

  1. reactive 返回对象的响应式副本
const obj = reactive({count:0})
  1. readonly 返回一个只读的proxy对象
const original = reactive({count: 0})
const copy = readonly(original)
  1. isProxy 检查对象是否是由 reactivereadonly 创建的 proxy

  2. isReactive 检查对象是否是reactive创建的proxy

  3. isReadonly 检查对象是否是readonly创建的只读proxy

  4. toRaw 返回 reactivereadonly proxy 的原始对象

  5. markRaw 标记一个对象,使其永远不会转换为 proxy

  6. shallowReactive 创建一个响应式 proxy,跟踪其自身 property 的响应性,但不执行嵌套对象的深度响应式转换 (暴露原始值)

  7. shallowReadonly 创建一个 proxy,使其自身的 property 为只读,但不执行嵌套对象的深度只读转换 (暴露原始值)

  8. ref 接受一个内部值并返回一个响应式且可变的 ref 对象

const count = ref(0)
console.log(count.value) //0

count.value++ 
console.log(count.value) //1
  1. unref 如果参数为 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val

  2. toRef 可以用来为源响应式对象上的 property 新创建一个 ref,然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。

// 相当于是添加一个对state.foo解构,但不影响其响应性
const state = reactive({
    foo: 1,
    bar: 2
})
const fooRef = toRef(state,"foo")
fooRef.value++
console.log(state.foo) //2

satte.foo++
console.log(fooRef.value) //3
  1. toRefs 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的ref。(相当于解构对象)

  2. isRef 检查是否是ref对象

  3. customRef 创建一个带有getset函数的ref对象

  4. shallowRef 创建一个 ref,它跟踪自己的 .value 更改,但不会使其值成为响应式的。(浅转换)

  5. triggerRef 手动执行与 shallowRef 关联的任何效果。

  6. computed 可自动调用的computed函数,返回一个不变的响应式ref对象,或者使用getset函数创建可写的ref对象

  7. watchEffect 在响应式地跟踪其依赖项时立即运行一个函数,并在更改依赖项时重新运行它。

const count = ref(0)

watchEffect(() => console.log(count.value))
// -> logs 0

setTimeout(() => {
  count.value++
  // -> logs 1
}, 100)
  1. watch 与watch完全等效

注意事项

  1. props是响应式对象,不可使用对象展开符

片段

vue2.x不支持在template中有多片段

<!-- Layout.vue -->
<template>
  <div>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  </div>
</template>

vue3.x中支持多片段,但需要设置attribute的分布

<!-- Layout.vue -->
<template>
  <header>...</header>
  <main v-bind="$attrs">...</main>
  <footer>...</footer>
</template>

异步组件更改

  • 新增defineAyncComponent助手方法,用于显式的定义异步组件
  • component选项重命名为loader
  • Loader函数本身不在接收resolvereject参数,必须返回一个Promise
import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'

// 不带选项的异步组件
const asyncPage = defineAsyncComponent(() => import('./NextPage.vue'))

// 带选项的异步组件
const asyncPageWithOptions = defineAsyncComponent({
  loader: () => import('./NextPage.vue'),
  delay: 200,
  timeout: 3000,
  errorComponent: ErrorComponent,
  loadingComponent: LoadingComponent
})

自定义事件

  • 新增emits选项,需要显式声明子组件中定义的自定义事件
  • 现在父级组件可以直接在子组件上使用v-on:click监听子组件的点击事件

自定义渲染器

<script setup>语法糖

当使用组合式API的时候可以直接使用此语法糖,减少不必要的代码

<script setup="props, { emit }">
import { watchEffect } from 'vue'

watchEffect(() => console.log(props.msg))
emit('foo')
</script>

<style vars="{ color }">语法糖

<template>
  <div class="text">hello</div>
</template>

<script>
export default {
  data() {
    return {
      color: 'red'
    }
  }
}
</script>

<style vars="{ color }">
.text {
  color: var(--color);
}
</style>

更加灵活的scoped作用域

>>>/deep/被弃用

<style scoped>
/* 深层选择 */
::v-deep(.foo) {}
/* 缩写 */
:deep(.foo) {}

/* 目标插槽选择 */
::v-slotted(.foo) {}
/* 缩写 */
:slotted(.foo) {}

/* 一次性的全局选择 */
::v-global(.foo) {}
/* 缩写 */
:global(.foo) {}
</style>

API改动

使用tree shaking的方式引入api,减少打包后的代码体积

全局api

为了减少对全局Vue的污染,全局API使用Vue暴露出createApp模块的形式创建实例

  1. createApp 新增
  2. config
    1. config.productionTip移除
    2. config.ignoredElements => config.isCustomElement并支持接受一个函数为参数
    3. Vue.prototype => config.globalProperties
  3. componentdirectiveminxinuse都由createApp生成的app实例调用

组件api

  • 组件级别的API使用Vue模块导出
  • 受影响的API有nextTickobservable=>reactiveversioncompilesetdelete
  • 内部一些api如:v-show等也将会被vue内部使用tree shaking的方式编译

v-model用法修改

  • prop: value -> modelValue
  • event: input -> update:modelValue
  • .sync修饰符和组件的model选项被移除
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />

<!-- 是以下的简写: -->

<ChildComponent
  :title="pageTitle"
  @update:title="pageTitle = $event"
  :content="pageContent"
  @update:content="pageContent = $event"
/>

data更改为必须由函数返回

mixins合并data改为浅合并

key值用法小修改

  • 现在vue可以自动生成key值,v-if/v-else/v-else-if不需要单独设置key
  • <template>支持设置key

v-if/v-for优先级修改

现在同级v-if优先级总是大于v-for

v-bind合并顺序修改

现在总是会按照书写顺序来合并v-bind属性,后书写的覆盖前书写的

移除.native修饰符

watch选项不再支持.分割字符串路径,改用第一个参数为计算函数的形式

生命周期改名

  • destroyed => unmounted
  • beforeDestroy => beforeUnmounted

自定义指令周期改为与组件生命周期一致

过度类名变更

  • .v-enter => v-enter-from
  • .v-leave => v-leave-from

transitionGroup不在默认渲染根节点

仍然可以用 tag prop 创建根元素。

$on$off$once方法废除

vue3中事件车可引入第三方库mitttiny-emitter解决

不再支持过滤器语法

vue3更推荐使用使用计算属性或者全局属性的方式处理数据

移除内联特性inline-template属性

vue3使用内联模板有两种方式

  1. <script>标签
<script type="text/html" id="my-comp-template">
  <div>{{ hello }}</div>
</script>
const MyComp = {
  template: '#my-comp-template'
  // ...
}
  1. 默认slot
<!-- 2.x 语法 -->
<my-comp inline-template :msg="parentMsg">
  {{ msg }} {{ childState }}
</my-comp>

<!-- 默认 Slot 版本 -->
<my-comp v-slot="{ childState }">
  {{ parentMsg }} {{ childState }}
</my-comp>

移除$children属性

vue3可直接再子组件上添加ref来获取子组件的实例

keycode形式的按键修饰符被移除

watch监听数组

默认只能监听数组被替换的回调,数组元素被修改需要添加deep选项

未完待续...