La diferencia entre vue3 y vue2 y cómo actualizar (básico para vue2)

Tabla de contenido

1. Nuevas características notables de vue3

1.1, Teletransporte

1.2, Vue 3 ahora admite oficialmente componentes con múltiples nodos raíz

 1.3 Emisiones de eventos personalizados

 1.4, modelo v 

1.4.1, parámetros del modelo v

 1.4.2, Múltiples enlaces de modelo v

1.4.3 Tratar con los modificadores del modelo v 

1.5 Matriz de referencia en v-for

 1.6 Componentes asíncronos

2. Cambios incompatibles

2.1, Vue 2 no tiene el concepto de "aplicación",

2.2, atributo comportamiento obligatorio

2.3, atributos, contiene, clase y estilo

2.4 Comandos personalizados

2.5 Interacción de elementos personalizados

2.6, Opción de datos

2.7, cambio de comportamiento de fusión de Mixin

2.8, Vue.prototype cambió a config.globalProperties

2.9, Treeshaking API global

2.10 Atributo de plantilla en línea

2.11, atributo clave

2.12 Modificadores clave

2.13 Acceda a esto en la función predeterminada de prop

2.14 API de función de renderizado

2.14.1 Parámetros de la función de renderizado

2.14.2 Cambios en la firma de la función de representación

2.14.3 Formateo de VNode Props

2.15 Unificación de slots

2.16 Cambio de nombre de clase de transición

2.17 Comparación de prioridad entre v-if y v-for

2.18, comportamiento de fusión v-bind

3. Atributos eliminados

3.1, $ niños

3.2, se eliminaron los métodos de instancia $on, $off y $once, y la instancia de la aplicación ya no implementa la interfaz de activación de eventos.

3.3, eliminar filtro de filtros

3.4, $oyentes eliminar

3.5 Se ha eliminado el modificador .native de v-on.

4. Actualización del proyecto Vue3 + view-ui-plus + js


1. Nuevas características notables de vue3

1.1, Teletransporte

Teleport proporciona una forma de permitirnos controlar bajo qué nodo principal en el DOM representa HTML sin tener que recurrir al estado global o dividirlo en dos componentes.

Por ejemplo, hay un cuadro modal en un subcomponente. Su conjunto principal predeterminado es su componente principal dom, pero el cuadro modal que necesitamos es cuerpo. Este es Teleport, que es un componente de subconjunto que define su conjunto principal dom

Después de unirse a Teleport

app.component('modal-button', {
  template: `
    <button @click="modalOpen = true">
        Open full screen modal! (With teleport!)
    </button>

    <teleport to="body">
      <div v-if="modalOpen" class="modal">
        <div>
          I'm a teleported modal! 
          (My parent is "body")
          <button @click="modalOpen = false">
            Close
          </button>
        </div>
      </div>
    </teleport>
  `,
  data() {
    return { 
      modalOpen: false
    }
  }
})

1.2, Vue 3 ahora admite oficialmente componentes con múltiples nodos raíz

En 2.x, dado que los componentes de nodos multirraíz no son compatibles, se emitirá una advertencia cuando el desarrollador cree uno accidentalmente. Para solucionar esto, muchos componentes están envueltos en uno  <div> .

<template>
  <div>
    <header>...</header>
    <main>...</main>
    <footer>...</footer>
  </div>
</template>

¡En 3.x, los componentes pueden contener múltiples nodos raíz! Sin embargo, esto requiere que el desarrollador defina explícitamente dónde se debe distribuir el atributo.

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

 1.3 Eventos personalizados emits

emits Los eventos emitidos se pueden definir en el componente a través de  opciones.

Cuando  se define emits un evento nativo (como  click) en las opciones, se usará el evento del componente en lugar del detector de eventos nativo.

app.component('custom-form', {
  emits: {
    // 没有验证
    click: null,

    // 验证submit 事件
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('Invalid submit event payload!')
        return false
      }
    }
  },
  methods: {
    submitForm() {
      this.$emit('submit', { email, password })
    }
  }
})

 1.4,v-model 

1.4.1, parámetros del modelo v

En cuanto a los cambios, esta sección es de alto nivel:

  • Incompatiblev-model :  los nombres predeterminados de accesorios y eventos cambiaron cuando se usaron en componentes personalizados :
    • prop:value ->  modelValue
    • evento:input ->  update:modelValue
  • Incompatible : v-bind los  .sync modificadores y  model las opciones de los componentes se han eliminado y se pueden  v-model usar en su lugar;
  • Nuevov-model : ahora puede usar múltiples  enlaces bidireccionales en el mismo componente  ;
  • Nuevo : los modificadores ahora se pueden personalizar  v-model .

v-model De forma predeterminada, se utiliza  en componentes  modelValue como accesorios y  update:modelValue como eventos. Podemos  v-model modificar estos nombres pasando parámetros a:

<my-component v-model:title="bookTitle"></my-component>

En este ejemplo, el componente secundario tomará un  title accesorio y emitirá  update:title un evento para sincronizarlo:

app.component('my-component', {
  props: {
    foo: String
  },
  emits: ['update:title'],
  template: `
    <input 
      type="text"
      :value="title"
      @input="$emit('update:title', $event.target.value)">
  `
})

 1.4.2,  v-model enlaces múltiples

Al aprovechar la capacidad de apuntar a accesorios y eventos específicos, ahora podemos crear múltiples enlaces de modelo v en una sola instancia de componente.

Cada modelo v se sincronizará con un accesorio diferente sin agregar opciones adicionales al componente:

<user-name
  v-model:first-name="firstName"
  v-model:last-name="lastName"
></user-name>
app.component('user-name', {
  props: {
    firstName: String,
    lastName: String
  },
  emits: ['update:firstName', 'update:lastName'],
  template: `
    <input 
      type="text"
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)">

    <input
      type="text"
      :value="lastName"
      @input="$emit('update:lastName', $event.target.value)">
  `
})

1.4.3,  v-model modificadores  de procesamiento

En 2.x,   teníamos soporte codificado para el modificador etc. v-model en  los componentes. .trimSin embargo, sería más útil si el componente pudiera admitir modificadores personalizados. En 3.x,  v-model los modificadores agregados a un componente estarán  modelModifiers disponibles para el componente a través de accesorios:

Cuando aprendimos sobre los enlaces de entrada de formulario, vimos que  v-model hay modificadores integrados - .trim, .number y  .lazy. Sin embargo, en algunos casos, es posible que también deba agregar sus propios modificadores personalizados.

Por ejemplo, un modificador personalizado  capitalizeque  v-model pone en mayúscula la primera letra de la cadena proporcionada por el enlace.

<my-component v-model.capitalize="myText"></my-component>

1.5 Matriz de referencia en v-for

En Vue 2,  el atributo v-for utilizado en  ref llenará la  $refs propiedad correspondiente con la matriz de referencia. v-for Este comportamiento se vuelve ambiguo e ineficiente cuando hay anidados  .

En Vue 3, dicho uso ya no  $ref creará automáticamente una matriz en formato . Para obtener múltiples referencias de un solo enlace, adjunte  ref el enlace a una función más flexible (esta es una característica nueva):

<div v-for="item in list" :ref="setItemRef"></div>
export default {
  data() {
    return {
      itemRefs: []
    }
  },
  methods: {
    setItemRef(el) {
      this.itemRefs.push(el)
    }
  },
  beforeUpdate() {
    this.itemRefs = []
  },
  updated() {
    console.log(this.itemRefs)
  }
}

 1.6 Componentes asíncronos

Anteriormente, los componentes asincrónicos se creaban definiendo el componente como una función que devolvía una Promesa, por ejemplo:

const asyncPage = () => import('./NextPage.vue')

O, para una sintaxis de componentes de orden superior con opciones:

const asyncPage = {
  component: () => import('./NextPage.vue'),
  delay: 200,
  timeout: 3000,
  error: ErrorComponent,
  loading: LoadingComponent
}

Vue 3. Gramática:

defineAsyncComponent Ahora, en Vue 3, dado que los componentes funcionales se definen como funciones puras, la definición de un componente asíncrono debe definirse explícitamente envolviéndolo en un nuevo  método auxiliar:

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
})

 Otro cambio de 2.x es que component las opciones ahora se renombran  loaderpara transmitir con precisión información que no puede proporcionarse directamente mediante una definición de componente.

Además, a diferencia de 2.x, la función del cargador ya no toma  resolve parámetros  reject y siempre debe devolver una Promesa.

// 2.x 版本
const oldAsyncComponent = (resolve, reject) => {
  /* ... */
}

// 3.x 版本
const asyncComponent = defineAsyncComponent(
  () =>
    new Promise((resolve, reject) => {
      /* ... */
    })
)

2. Cambios incompatibles

2.1, Vue 2 no tiene el concepto de "aplicación",

La aplicación que definimos la acaba de  new Vue() crear la instancia raíz de Vue. Cada instancia raíz creada a partir del mismo constructor de Vue comparte la misma configuración global 

new Vue() 改成  createApp()

La instancia de la aplicación expone un subconjunto de la API global actual. La regla general es que cualquier API que cambie globalmente el comportamiento de Vue ahora se moverá a la instancia de la aplicación. Aquí hay una tabla de la API global actual y su API de instancia correspondiente :

API global 2.x API de instancia 3.x ( app)
Ver.config aplicación.config
Vue.config.productionTip eliminado  ( ver más abajo )
Vue.config.ignoredElements app.config.isCustomElement ( ver más abajo )
Vue.componente aplicación.componente
Directiva.view directiva de aplicación
Vue.mixin app.mixin
Vue.use app.use ( ver más abajo )
Vue.prototipo app.config.globalProperties ( ver más abajo )

Todas las demás API globales que no cambian el comportamiento globalmente ahora se denominan exportaciones.

En 3.0, la verificación de si un elemento es un componente se ha movido a la etapa de compilación de plantillas, por lo que esta opción de configuración solo se considera cuando se usa el compilador de tiempo de ejecución. Si está utilizando la versión de solo tiempo de ejecución,  isCustomElement debe  @vue/compiler-dom reemplazarse en el paso de compilación, por ejemplo, a través de  la opción compilerOptions en vue-loader (se abre en una ventana nueva) .

  • Si  config.isCustomElement al usar una compilación solo en tiempo de ejecución, se emitirá una advertencia indicándole al usuario que pase esta opción en la configuración de compilación;
  • Esta será una nueva opción de nivel superior en la configuración de la CLI de Vue.

2.2, atributo comportamiento obligatorio

Este es un cambio de API interna de bajo nivel que no afectará a la mayoría de los desarrolladores.

  • Elimine el concepto interno de atributos de enumeración y trate estos atributos como atributos ordinarios no booleanos
  • Cambio importante : el atributo ya no se elimina si el valor es booleano  false. En su lugar, se establece en attr="false". Para eliminar un atributo, utilice  null o  undefined.

La siguiente tabla describe cómo Vue 2.0 impone "atributos de enumeración" con atributos no booleanos normales:

expresión vinculante foo normal draggable enumerar
: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"
attr foo="" draggable="true"

Como se puede ver en la tabla anterior, la implementación actual  true es obligatoria  'true' , pero si el atributo es  false, el atributo se elimina. Esto también genera inconsistencias y requiere que los usuarios coaccionen manualmente los valores booleanos a cadenas en casos de uso muy comunes, como  aria-* atributos como  aria-selected, aria-hidden, etc.

La siguiente tabla describe cómo Vue3.0 usa valores ordinarios no booleanos

expresión vinculante foo normal draggable enumerar
: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" †
attr foo="" draggable="" †

†: Cambiar

La coacción de los atributos booleanos permanece sin cambios.

Comparación del comportamiento de 2.x y 3.x

Atributos v-bind valor 2.x v-bind valor 3.x salida HTML
2.x "atributo de enumeración",
es decir  contenteditabledraggable y  spellcheck.
undefinedfalse undefinednull remoto
true'true'''1'foo' true'true' "true"
null'false' false'false' "false"
Otros atributos no booleanos,
por ejemplo  aria-checked, ,  tabindexalt, etc.
undefinednullfalse undefinednull remoto
'false' false'false' "false"

2.3, atributos, contiene, clase y estilo

vue2 

<my-component id="my-id" class="my-class"></my-component>
<label class="my-class">
  <input type="text" id="my-id" />
</label>

 vue3

<label>
  <input type="text" id="my-id" class="my-class" />
</label>

 Entonces la migración puede estar en el estilo incorrecto

2.4 Comandos personalizados

En Vue 2, las directivas personalizadas se crean utilizando los ganchos que se enumeran a continuación, todos los cuales son opcionales

  • bind  : ocurre después de que la directiva se vincula al elemento. Ocurre solo una vez.
  • insertado  : ocurre después de que el elemento se haya insertado en el DOM principal.
  • update - 当元素更新,但子元素尚未更新时,将调用此钩子。
  • componentUpdated - 一旦组件和子级被更新,就会调用这个钩子。
  • unbind - 一旦指令被移除,就会调用这个钩子。也只调用一次。

下面是一个例子:

<p v-highlight="'yellow'">高亮显示此文本亮黄色</p>
Vue.directive('highlight', {
  bind(el, binding, vnode) {
    el.style.background = binding.value
  }
})

在这里,在这个元素的初始设置中,指令通过传递一个值来绑定样式,该值可以通过应用程序更新为不同的值。

在 Vue 3 中,我们为自定义指令创建了一个更具凝聚力的 API。正如你所看到的,它们与我们的组件生命周期方法有很大的不同,即使我们正与类似的事件钩子,我们现在把它们统一起来了:

  • 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() {}
}

生成的 API 可以这样使用,与前面的示例相同:

<p v-highlight="'yellow'">高亮显示此文本亮黄色</p>
const app = Vue.createApp({})

app.directive('highlight', {
  beforeMount(el, binding, vnode) {
    el.style.background = binding.value
  }
})

2.5、自定义元素交互

  • 非兼容:自定义元素白名单现在在模板编译期间执行,应该通过编译器选项而不是运行时配置来配置。
  • 非兼容:特定 is prop 用法仅限于保留的 <component> 标记。
  • 新增:有了新的 v-is 指令来支持 2.x 用例,其中在原生元素上使用了 v-is 来处理原生 HTML 解析限制。

v-is 函数像一个动态的 2.x :is 绑定——因此,要按注册名称渲染组件,其值应为 JavaScript 字符串文本:

<!-- 不正确,不会渲染任何内容 -->
<tr v-is="blog-post-row"></tr>

<!-- 正确 -->
<tr v-is="'blog-post-row'"></tr>

2.6、Data 选项

  • 非兼容data 组件选项声明不再接收纯 JavaScript object,而需要 function 声明。

当合并来自 mixin 或 extend 的多个 data 返回值时,现在是浅层次合并的而不是深层次合并的(只合并根级属性)

在 2.x 中,开发者可以定义 data 选项是 object 或者是 function

例如:

<!-- Object 声明 -->
<script>
  const app = new Vue({
    data: {
      apiKey: 'a1b2c3'
    }
  })
</script>

<!-- Function 声明 -->
<script>
  const app = new Vue({
    data() {
      return {
        apiKey: 'a1b2c3'
      }
    }
  })
</script>

虽然这对于具有共享状态的根实例提供了一些便利,但是由于只有在根实例上才有可能,这导致了混乱。

在 3.x,data 选项已标准化为只接受返回 object 的 function

使用上面的示例,代码只有一个可能的实现:

<script>
  import { createApp } from 'vue'

  createApp({
    data() {
      return {
        apiKey: 'a1b2c3'
      }
    }
  }).mount('#app')
</script>

2.7、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中,生成的 $data 是:

{
  user: {
    id: 2,
    name: 'Jack'
  }
}

在 3.0 中,其结果将会是:

{
  user: {
    id: 2
  }
}

2.8、Vue.prototype 改成 config.globalProperties

在Vue 2中,Vue。prototype通常用于添加在所有组件中都可以访问的属性。

Vue 3中的等效项是config.globalproperty。这些属性将作为实例化应用程序内组件的一部分进行复制:

// before - Vue 2
Vue.prototype.$http = () => {}
// after - Vue 3
const app = Vue.createApp({})
app.config.globalProperties.$http = () => {}

2.9 、全局 API Treeshaking

如果你曾经在 Vue 中手动操作过 DOM,你可能会遇到以下模式:

import Vue from 'vue'

Vue.nextTick(() => {
  // 一些和DOM有关的东西
})

在 Vue 3 中,全局和内部 API 都经过了重构,并考虑到了 tree-shaking 的支持。因此,全局 API 现在只能作为 ES 模块构建的命名导出进行访问。例如,我们之前的片段现在应该如下所示:

import { nextTick } from 'vue'

nextTick(() => {
  // 一些和DOM有关的东西
})

直接调用 Vue.nextTick() 将导致臭名昭著的 undefined is not a function 错误。

通过这一更改,如果模块绑定器支持 tree-shaking,则 Vue 应用程序中未使用的全局 api 将从最终捆绑包中消除,从而获得最佳的文件大小

Vue 2.x 中的这些全局 API 受此更改的影响:

  • Vue.nextTick
  • Vue.observable (用 Vue.reactive 替换)
  • Vue.version
  • Vue.compile (仅全构建)
  • Vue.set (仅兼容构建)
  • Vue.delete (仅兼容构建)

插件中的用法

如果你的插件依赖受影响的 Vue 2.x 全局 API,例如:

const plugin = {
  install: Vue => {
    Vue.nextTick(() => {
      // ...
    })
  }
}

在 Vue 3 中,必须显式导入:

import { nextTick } from 'vue'

const plugin = {
  install: app => {
    nextTick(() => {
      // ...
    })
  }
}

如果使用 webpack 这样的模块捆绑包,这可能会导致 Vue 的源代码绑定到插件中,而且通常情况下,这并不是你所期望的。防止这种情况发生的一种常见做法是配置模块绑定器以将 Vue 从最终捆绑中排除。对于 webpack,你可以使用 externals (opens new window)配置选项:

// webpack.config.js
module.exports = {
  /*...*/
  externals: {
    vue: 'Vue'
  }
}

这将告诉 webpack 将 Vue 模块视为一个外部库,而不是捆绑它。

如果你选择的模块绑定器恰好是 Rollup (opens new window),你基本上可以免费获得相同的效果,因为默认情况下,Rollup 会将绝对模块 id (在我们的例子中为 'vue') 作为外部依赖项,而不会将它们包含在最终的 bundle 中。但是在绑定期间,它可能会发出一个“将 vue 作为外部依赖” (opens new window)警告,可使用 external 选项抑制该警告:

// rollup.config.js
export default {
  /*...*/
  external: ['vue']
}

2.10、内联模板 Attribute

在 2.x 中,Vue 为子组件提供了 inline-template attribute,以便将其内部内容用作模板,而不是将其作为分发内容。 3.x将不再支持此功能。

<my-component inline-template>
  <div>
    <p>它们被编译为组件自己的模板</p>
    <p>不是父级所包含的内容。</p>
  </div>
</my-component>

2.11、key attribute

  • 新增:对于 v-if/v-else/v-else-if 的各分支项 key 将不再是必须的,因为现在 Vue 会自动生成唯一的 key
    • 非兼容:如果你手动提供 key,那么每个分支必须使用唯一的 key。你不能通过故意使用相同的 key 来强制重用分支。
  • 非兼容<template v-for> 的 key 应该设置在 <template> 标签上 (而不是设置在它的子节点上)。

Vue 2.x 建议在 v-if/v-else/v-else-if 的分支中使用 key

<!-- Vue 2.x -->
<div v-if="condition" key="yes">Yes</div>
<div v-else key="no">No</div>

这个示例在 Vue 3.x 中仍能正常工作。但是我们不再建议在 v-if/v-else/v-else-if 的分支中继续使用 key attribute,因为没有为条件分支提供 key 时,也会自动生成唯一的 key

<!-- Vue 3.x -->
<div v-if="condition">Yes</div>
<div v-else>No</div>

2.12、按键修饰符

  • 非兼容:不再支持使用数字 (即键码) 作为 v-on 修饰符
  • 非兼容:不再支持 config.keyCodes

在 Vue 2 中,支持 keyCodes 作为修改 v-on 方法的方法。

<!-- 键码版本 -->
<input v-on:keyup.13="submit" />

<!-- 别名版本 -->
<input v-on:keyup.enter="submit" />

此外,你可以通过全局 config.keyCodes 选项。

Vue.config.keyCodes = {
  f1: 112
}
<!-- 键码版本 -->
<input v-on:keyup.112="showHelpText" />

<!-- 自定别名版本 -->
<input v-on:keyup.f1="showHelpText" />

KeyboardEvent.keyCode has been deprecated (opens new window)开始,Vue 3 继续支持这一点就不再有意义了。因此,现在建议对任何要用作修饰符的键使用 kebab-cased (短横线) 大小写名称。

<!-- Vue 3 在 v-on 上使用 按键修饰符 -->
<input v-on:keyup.delete="confirmDelete" />

因此,这意味着 config.keyCodes 现在也已弃用,不再受支持。

2.13、在 prop 的默认函数中访问this

替代方案:

  • 把组件接收到的原始 prop 作为参数传递给默认函数;

  • 注入 API 可以在默认函数中使用。

import { inject } from 'vue'

export default {
  props: {
    theme: {
      default (props) {
        // `props` 是传递给组件的原始值。
        // 在任何类型/默认强制转换之前
        // 也可以使用 `inject` 来访问注入的 property
        return inject('theme', 'default-theme')
      }
    }
  }
}

2.14、渲染函数 API

2.14.1 Render 函数参数

在 2.x 中,e render 函数将自动接收 h 函数 (它是 createElement 的常规别名) 作为参数:

// Vue 2 渲染函数示例
export default {
  render(h) {
    return h('div')
  }
}

 在 3.x 中,h 现在是全局导入的,而不是作为参数自动传递。

// Vue 3 渲染函数示例
import { h } from 'vue'

export default {
  render() {
    return h('div')
  }
}

2.14.2、渲染函数签名更改

在 2.x 中,render 函数自动接收诸如 h 之类的参数。

// Vue 2 渲染函数示例
export default {
  render(h) {
    return h('div')
  }
}

在 3.x 中,由于 render 函数不再接收任何参数,它将主要用于 setup() 函数内部。这还有一个好处:可以访问作用域中声明的响应式状态和函数,以及传递给 setup() 的参数。

import { h, reactive } from 'vue'

export default {
  setup(props, { slots, attrs, emit }) {
    const state = reactive({
      count: 0
    })

    function increment() {
      state.count++
    }

    // 返回render函数
    return () =>
      h(
        'div',
        {
          onClick: increment
        },
        state.count
      )
  }
}

2.14.3 VNode Props 格式化

在 2.x 中,domProps 包含 VNode props 中的嵌套列表:

// 2.x
{
  class: ['button', 'is-outlined'],
  style: { color: '#34495E' },
  attrs: { id: 'submit' },
  domProps: { innerHTML: '' },
  on: { click: submitForm },
  key: 'submit-button'
}

在 3.x 中,整个 VNode props 结构是扁平的,使用上面的例子,下面是它现在的样子

// 3.x 语法
{
  class: ['button', 'is-outlined'],
  style: { color: '#34495E' },
  id: 'submit',
  innerHTML: '',
  onClick: submitForm,
  key: 'submit-button'
}

2.15、Slot 统一

  • this.$slots 现在将 slots 作为函数公开
  • 非兼容:移除 this.$scopedSlots

2.x 当使用渲染函数时,即 h,2.x 用于在内容节点上定义 slot data property。

// 2.x 语法
h(LayoutComponent, [
  h('div', { slot: 'header' }, this.header),
  h('div', { slot: 'content' }, this.content)
])

此外,在引用作用域 slot 时,可以使用以下方法引用它们:

// 2.x 语法
this.$scopedSlots.header

在 3.x 中,插槽被定义为当前节点的子对象:

// 3.x Syntax
h(LayoutComponent, {}, {
  header: () => h('div', this.header),
  content: () => h('div', this.content)
})

当你需要以编程方式引用作用域 slot 时,它们现在被统一到 $slots 选项中。

// 2.x 语法
this.$scopedSlots.header

// 3.x 语法
this.$slots.header

2.16、过渡的 class 名更改

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

在v2.1.8版本之前, 为过渡指令提供了两个过渡类名对应初始和激活状态。

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

.v-enter,
.v-leave-to {
  opacity: 0;
}

.v-leave,
.v-enter-to {
  opacity: 1;
}

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

为了更加明确易读,我们现在将这些初始状态重命名为:

.v-enter-from,
.v-leave-to {
  opacity: 0;
}

.v-leave-from,
.v-enter-to {
  opacity: 1;
}

现在,这些状态之间的区别就清晰多了。

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

  • leave-class 已经被重命名为 leave-from-class (在渲染函数或 JSX 中可以写为:leaveFromClass)
  • enter-class 已经被重命名为 enter-from-class (在渲染函数或 JSX 中可以写为:enterFromClass)

2.17、v-if 与 v-for 的优先级对比

  • 非兼容:两者作用于同一个元素上时,v-if 会拥有比 v-for 更高的优先级。

2.x 版本中在一个元素上同时使用 v-if 和 v-for 时,v-for 会优先作用。

3.x 版本中 v-if 总是优先于 v-for 生效

2.18、v-bind 合并行为

  • 不兼容:v-bind 的绑定顺序会影响渲染结果。

在 2.x,如果一个元素同时定义了 v-bind="object" 和一个相同的单独的 property,那么这个单独的 property 总是会覆盖 object 中的绑定。

<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="red"></div>

在 3.x,如果一个元素同时定义了 v-bind="object" 和一个相同的单独的 property,那么声明绑定的顺序决定了它们如何合并。换句话说,相对于假设开发者总是希望单独的 property 覆盖 object 中定义的内容,现在开发者对自己所希望的合并行为有了更好的控制。

<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>

<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>

三、移除的属性

3.1、$children

$children实例属性已从Vue 3.0中删除,不再受支持。

#2.x语法

En 2.x, los desarrolladores podían usar este comando para acceder a los componentes secundarios inmediatos de la instancia actual. $niños:

en 3. x, la propiedad $child se eliminó y ya no se admite. En su lugar, se recomienda usar $refs si necesita acceder a instancias de componentes secundarios.

<template>
  <div>
    <img alt="Vue logo" src="/vue3js/logo.png">
    <my-button>Change logo</my-button>
  </div>
</template>

<script>
import MyButton from './MyButton'

export default {
  components: {
    MyButton
  },
  mounted() {
    console.log(this.$children) // [VueComponent]
  }
}
</script>

3.2 , $ony $off los  $once métodos de instancia se han eliminado y la instancia de la aplicación ya no implementa la interfaz de activación de eventos.

3.3, eliminar filtro de filtros

filters: {
      currencyUSD(value) {
        return '$' + value
      }
    }

En 3.x, el filtro se eliminó y ya no se admite. En su lugar, recomendamos reemplazarlos con llamadas a métodos o propiedades calculadas.

Usando el ejemplo anterior, aquí hay un ejemplo de cómo hacerlo.

<template>
  <h1>Bank Account Balance</h1>
  <p>{
   
   { accountInUSD }}</p>
</template>

<script>
  export default {
    props: {
      accountBalance: {
        type: Number,
        required: true
      }
    },
    computed: {
      accountInUSD() {
        return '$' + this.accountBalance
      }
    }
  }
</script>

3.4,$listeners 删除

El objeto $listeners se eliminó en Vue 3. Los detectores de eventos ahora son parte de $attrs:

vista2.x

<template>
  <label>
    <input type="text" v-bind="$attrs" v-on="$listeners" />
  </label>
</template>
<script>
  export default {
    inheritAttrs: false
  }
</script>

vue.3.x

<template>
  <label>
    <input type="text" v-bind="$attrs" />
  </label>
</template>
<script>
export default {
  inheritAttrs: false
}
</script>

3.5 Se ha eliminado el modificador .native de v-on.

De forma predeterminada, los detectores de eventos que se pasan a los componentes con v-on solo se activan al emitir eventos con this. $emitir. Para agregar un oyente DOM nativo al elemento raíz de un componente secundario, puede usar el modificador .native:

<my-component
  v-on:close="handleComponentEvent"
  v-on:click.native="handleNativeClickEvent"
/>

Se eliminó el modificador .native para v-on. Además, la nueva opción emite le permite al niño definir qué eventos emite.

Como resultado, Vue ahora agrega todos los detectores de eventos que no se definieron como componentes que emiten eventos en el elemento secundario como detectores de eventos nativos al elemento raíz del elemento secundario (a menos que heredarAttrs:false esté configurado en las opciones del elemento secundario).

<my-component
  v-on:close="handleComponentEvent"
  v-on:click="handleNativeClickEvent"
/>

MyComponent.vue

<script>
  export default {
    emits: ['close']
  }
</script>

4. Actualización del proyecto Vue3 + view-ui-plus + js

https://blog.csdn.net/xm_w_xm/article/details/126013210

Supongo que te gusta

Origin blog.csdn.net/xm_w_xm/article/details/125893142
Recomendado
Clasificación