vue3中一些不兼容的小改变

Posted 月岛蘑菇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了vue3中一些不兼容的小改变相关的知识,希望对你有一定的参考价值。

vue3中一些不兼容的小改变

生命周期选项名称的变化

destroyed被重命名为unmounted
beforeDestroy被重命名为beforeUnmount

在prop的默认函数中访问this

生成prop默认值的工厂函数不能再访问this

// vue3
// 把组件接收到的原始prop作为参数传递给默认函数
// inject API 可以在默认函数中使用
import { inject } from \'vue\'
export default {
  props: {
    theme: {
      default(props) {
        // props是传递给组件的原始值
        // 在任何类型/默认强制转换之前
        // 也可以使用inject来访问注入的property
        return inject(\'theme\', \'default-theme\')
      }
    }
  }
}

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

指令的钩子函数被重命名

在2.x中,自定义指令是通过使用鞋面列出的狗子来创建的,这些钩子是可选的

  • bind - 指令绑定到元素后发生,只发生一次
  • inserted - 元素插入父DOM后发生
  • update - 单元数更新,但子元素尚未更新时,将调用此钩子
  • componentUpdated - 一旦组件和子级被更新,就会调用此钩子
  • unbind - 指令被移除时调用,只调用一次
<p v-highlignt="\'yellow\'">高亮文本,黄色</p>
Vue.directive(\'highlight\', {
  bind(el, binding, vnode) {
    el.style.background = binding.value
  }
})
// 在这个元素的初始设置中,指令通过传递一个值来绑定样式,该值可以通过应用程序更新为不同的值

在3.x中,自定义指令有了新的API,现在将组件生命周期和自定义指令的生命周期统一了起来

  • created - 新的!在元素的 attribute 或事件侦听器应用之前调用。
  • bind → beforeMount
  • inserted → mounted
  • beforeUpdate:新的!这是在元素本身更新之前调用的,很像组件生命周期钩子。
  • update → 移除!有太多的相似之处要更新,所以这是多余的,请改用 updated
  • componentUpdated → updated
  • beforeUnmount:新的!与组件生命周期钩子类似,它将在卸载元素之前调用。
  • unbind -> unmounted
// 最终API
const MyDirective = {
  beforeMount(el, binding, vnode, prevVnode) {},
  mounted() {},
  beforeUpdate() {},
  updated() {},
  beforeUnmount() {},
  unmounted() {}
}
// 使用方法
const app = Vue.createApp({})
app.directive(\'highlight\', {
  beforeMount(el, binding, vnode) {
    el.style.background = binding.value
  }
})

访问组件实例的变化

// vue2  通过vnode访问组件实例
bind(el, binding, vnode) {
  const vm = vnode.context
}
// vue3  通过binding访问
mounted(el, binding, vnode) {
  const vm = binding.instance
}
// 借助片段支持,组件可能具有多个根节点。当应用于多根组件时,指令将被忽略,并且将记录警告。

Data选项始终都是function,mixin合并data的变化

data选项只支持function

// 2.x
data: {
  apiKey: \'value\'
}
// 或
data() {
  return {
    apiKey: \'value\'
  }
}
// 3.x 现在只支持函数形式的data
data() {
  return {
    apiKey: \'value\'
  }
}

Mixin合并行为变更
当来自组件的data()及其mixin或extends基类被合并时,现在将会浅层次合并

const Mixin = {
  data() {
    return {
      user: {
        name: \'Jack\',
        id: 1
      }
    }
  }
}
const CompA = {
  mixins: [Mixin]
  data() {
    return {
      user: {
        id: 2
      }
    }
  }
}

以上代码在不同版本vue中结果不同

// 2.x
{
  user: {
    id: 2,
    name: \'Jack\'
  }
}
// 3.x
{
  user: {
    id: 2
  }
}

过渡的class名更改

过渡类名 v-enter 修改为 v-enter-from
过渡类名 v-leave 修改为 v-leave-form

v2.1.8 版本中, 引入 v-enter-to 来定义 enter 或 leave 变换之间的过渡动画插帧, 为了向下兼容, 并没有变动 v-enter 类名

这样做会带来很多困惑, 类似 enter 和 leave 含义过于宽泛并且没有遵循类名钩子的命名约定。

在vue3中为了更加明确易读,现在将这些初始状态重命名
/* 2.x */
.v-enter,
.v-leave-to{
  opcity: 0;
}
.v-leave,
.v-enter-to {
  opcity: 1;
}
/* 3.x */
.v-enter-from,
.v-leave-to{
  opcity: 0;
}
.v-leave-from,
.v-enter-to{
  opcity: 0;
}

<transition>组件相关属性名也发生了变化:

  • leave-class 重命名为 leave-from-class (JSX中:leaveFromClass)
  • enter-class 重命名为 enter-from-class(JSX中: enterFromClass)

<transition-group>组件变化

<transition-group>不再默认渲染恩元素,但仍可以用tag属性创建根元素

<!-- 2.x中 如果不指定tag属性,则会默认创建一个span元素包裹 -->
<transition-group tag="ul">
<li v-for="item in items" :key="item">
  {{ item }}
</li>
</transition-group>
<!-- 3.x中 组件不再需要一个根节点,所以transition-group不再渲染根节点 -->
<transition-group tag="span">
  <!-- -->
</transition-group>
<!-- 等同以上代码 -->

watch监听数组的变化

只有数组被替换的时候才会触发watch的回调,如果要在数组改变时触发,需要指定deep选项

watch: {
  bookList: {
    handler(val, oldVal) {
      console.log(\'changed!\')
    },
    deep: true
  }
}

没有特殊指令标记的<template>

没有特殊指令的标记 (v-if/else-if/else、v-for 或 v-slot),将会生成原生<template>元素,而不是渲染内部内容

vue3中,容器本身不再是模板的一部分

在 Vue 2.x 中,应用根容器的 outerhtml 将替换为根组件模板 (如果根组件没有模板/渲染选项,则最终编译为模板)。Vue 3.x 现在使用应用容器的 innerHTML,这意味着容器本身不再被视为模板的一部分。


attribute的强制行为

这是一个低级的内部 API 更改,不会影响大多数开发人员。

  • 删除枚举 attribute 的内部概念,并将这些 attribute 视为普通的非布尔 attribute
  • 重大改变:如果值为布尔值,则不再删除 attribute false。相反,它被设置为 attr=“false”。移除 attribute,使用 null 或者 undefined。

在 2.x,我们有以下策略来强制 v-bind 的值:

  • 对于某些 attribute/元素对,Vue 始终使用相应的 IDL attribute(property):比如 value 的 <input><select><progress>,等等
  • 对于“枚举 attribute” (目前 contenteditable,draggable 和 spellcheck),Vue 会尝试强制将它们串起来 (目前对 contenteditable 做了特殊处理,修复 vuejs/vue#9397)
  • 对于其他 attribute,我们移除了 falsy 值 (undefined,null,or false) 并按原样设置其他值 (见这里)。
绑定表达式foo 正常draggable 枚举
:attr="null"/draggable="false"
:attr="undefined"//
:attr="true"foo="true"draggable="true"
:attr="false"/draggable="false"
:attr="0"foo="0"draggable="true"
attr=""foo=""draggable="true"
attr="foo"foo="foo"draggable="true"
attrfoo=""draggable="true"

从上表可以看出,当前实现 true 强制为 \'true\' 但如果 attribute 为 false,则移除该 attribute。这也导致了不一致性,并要求用户在非常常见的用例中手动强制布尔值为字符串,例如 aria-* attribute 像 aria-selected,aria-hidden,等等。

在vue3中,放弃“枚举 attribute”的内部概念,并将它们视为普通的非布尔 HTML attribute。

  • 这解决了普通非布尔 attribute 和“枚举 attribute”之间的不一致性
  • 它还可以使用 \'true\' 和 \'false\' 以外的值,甚至可以使用 contenteditable 等 attribute 的关键字`
  • 对于非布尔 attribute,如果 attribute 为 false,Vue 将停止删除它们,相反强制它们为 \'false\'。
  • 这解决了 true 和 false 之间的不一致性,并使输出 aria-* attributes 更容易
绑定表达式foo 正常draggable 枚举
:attr="null"// †
:attr="undefined"//
:attr="true"foo="true"draggable="true"
:attr="false"foo="false" †draggable="false"
:attr="0"foo="0"draggable="0" †
attr=""foo=""draggable="" †
attr="foo"foo="foo"draggable="foo" †
attrfoo=""draggable=""

†: 变更
布尔 attributes 的强制保持不变。

以上是关于vue3中一些不兼容的小改变的主要内容,如果未能解决你的问题,请参考以下文章

记录--Vue3+TS(uniapp)手撸一个聊天页面

Vue3官网-高级指南(十七)响应式计算`computed`和侦听`watchEffect`(onTrackonTriggeronInvalidate副作用的刷新时机`watch` pre)(代码片段

vue3的小知识

片段中的LayoutInflator错误“不兼容的类型”[重复]

好用的小技巧win8兼容网页不让复制

vue3中的fragment(片段)组件