The difference between vue3 and vue2 and how to upgrade (basic for vue2)

Table of contents

1. Noteworthy new features of vue3

1.1、Teleport

1.2, Vue 3 now officially supports components with multiple root nodes

 1.3. Custom event emits

 1.4、v-model 

1.4.1, v-model parameter

 1.4.2, Multiple v-model bindings

1.4.3. Dealing with v-model modifiers 

1.5 Ref array in v-for

 1.6 Asynchronous components

2. Incompatible changes

2.1, Vue 2 does not have the concept of "app",

2.2, attribute mandatory behavior

2.3, attributes, contains, class and style

2.4. Custom commands

2.5. Custom element interaction

2.6, Data option

2.7, Mixin merge behavior change

2.8, Vue.prototype changed to config.globalProperties

2.9 、Global API Treeshaking

2.10. Inline Template Attribute

2.11、key attribute

2.12. Key modifiers

2.13. Access this in the default function of prop

2.14. Rendering function API

2.14.1 Render function parameters

2.14.2. Rendering function signature changes

2.14.3 Formatting VNode Props

2.15. Slot unification

2.16. Transitional class name change

2.17. Priority comparison between v-if and v-for

2.18, v-bind merge behavior

3. Removed attributes

3.1、$children

3.2 , $on, $off and $once instance methods have been removed, and the application instance no longer implements the event trigger interface.

3.3, filters filter delete

3.4, $listeners delete

3.5. The .native modifier of v-on has been deleted.

4. Vue3 + view-ui-plus + js project upgrade


1. Noteworthy new features of vue3

1.1、Teleport

Teleport provides a way to allow us to control under which parent node in the DOM renders HTML without having to resort to global state or split it into two components.

For example, there is a modal box in a subcomponent. Its default parent set is its parent component dom, but the modal box we need is body. This is Teleport, which is a subset component that defines its parent set dom

After joining 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 now officially supports components with multiple root nodes

In 2.x, since multi-root node components are not supported, a warning will be issued when the developer accidentally creates one. To fix this, many components are wrapped in one  <div> .

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

In 3.x, components can contain multiple root nodes! However, this requires the developer to explicitly define where the attribute should be distributed.

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

 1.3. Custom events emits

emits The emitted events can be defined on the component via  options.

When  emits a native event (like  click) is defined in the options, the event from the component will be used instead of the native event listener.

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, v-model parameter

As far as changes go, this section is high-level:

  • Incompatiblev-model :  prop and event default names changed when used in custom components :
    • prop:value -> modelValue
    • event:input -> update:modelValue
  • Incompatible : v-bind The  .sync modifiers and  model options of components have been removed and can be  v-model used instead;
  • Newv-model : Now you can use multiple  two-way bindings on the same component  ;
  • New : Modifiers can now be customized  v-model .

v-model By default, used  on components  modelValue as props and  update:modelValue as events. We can  v-model modify these names by passing parameters to:

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

In this example, the child component will take a  title prop and emit  update:title an event to be synchronized:

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, multiple  v-model bindings

By leveraging the ability to target specific props and events, we can now create multiple v-model bindings on a single component instance.

Each v-model will sync to a different prop without adding extra options to the component:

<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, processing  v-model modifiers 

In 2.x we   had hardcoded support for the etc modifier v-model on  components. .trimHowever, it would be more useful if the component could support custom modifiers. In 3.x,  v-model modifiers added to a component will  modelModifiers be made available to the component via props:

When we learned about form input bindings, we saw that  v-model there are built-in modifiers - .trim, , .number and  .lazy. However, in some cases you may also need to add your own custom modifiers.

For example a custom modifier  capitalizethat  v-model capitalizes the first letter of the string provided by the binding.

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

1.5 Ref array in v-for

In Vue 2,  the attribute v-for used in  ref will fill the corresponding  $refs property with the ref array. v-for This behavior becomes ambiguous and inefficient when there are nested  .

In Vue 3, such usage will no longer  $ref automatically create an array in . To get multiple refs from a single binding, attach  ref the binding to a more flexible function (this is a new feature):

<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 Asynchronous components

Previously, asynchronous components were created by defining the component as a function returning a Promise, for example:

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

Or, for higher order component syntax with options:

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

Vue3. Grammar:

defineAsyncComponent Now, in Vue 3, since functional components are defined as pure functions, the definition of an async component needs to be defined explicitly by wrapping it in a new  helper method:

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

 Another change from 2.x is that component options are now renamed to  loaderin order to accurately convey information that cannot be directly provided by a component definition.

Also, unlike 2.x, the loader function no longer takes  resolve and  reject parameters and must always return a Promise

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

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

2. Incompatible changes

2.1, Vue 2 does not have the concept of "app",

The application we define is just  new Vue() created by the root Vue instance. Every root instance created from the same Vue constructor shares the same global configuration 

new Vue() 改成  createApp()

The application instance exposes a subset of the current global API. The rule of thumb is that any API that globally changes the behavior of Vue will now be moved to the application instance. Here is a table of the current global API and its corresponding instance API:

2.x Global API 3.x instance API ( app)
View.config app.config
Vue.config.productionTip removed  ( see below )
Vue.config.ignoredElements app.config.isCustomElement ( see below )
Vue.component app.component
Directive.view app.directive
Vue.mixin app.mixin
Vue.use app.use ( see below )
Vue.prototype app.config.globalProperties ( see below )

All other global APIs that do not change behavior globally are now named exports

In 3.0, the check of whether an element is a component has been moved to the template compilation stage, so this configuration option is only considered when using the runtime compiler. If you are using the runtime-only version  isCustomElement it must  @vue/compiler-dom be replaced in the build step - for example, via  the compilerOptions option in vue-loader (opens new window) .

  • If  config.isCustomElement when using a runtime-only build, a warning will be issued instructing the user to pass this option in the build settings;
  • This will be a new top-level option in the Vue CLI configuration.

2.2, attribute mandatory behavior

This is a low-level internal API change that won't affect most developers.

  • Remove the internal concept of enumeration attributes and treat these attributes as ordinary non-boolean attributes
  • Breaking change : attribute is no longer removed if the value is boolean  false. Instead, it is set to attr="false". To remove attribute, use  null or  undefined.

The following table describes how Vue 2.0 enforces "enum attributes" with normal non-boolean attributes:

binding expression foo normal draggable enumerate
: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"

As can be seen from the above table, the current implementation  true is mandatory  'true' , but if the attribute is  false, the attribute is removed. This also leads to inconsistencies and requires users to manually coerce boolean values ​​to strings in very common use cases, such as  aria-* attributes like  aria-selected, aria-hidden, etc.

The following table describes how Vue3.0 uses ordinary non-boolean

binding expression foo normal draggable enumerate
: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="" †

†: Change

The coercion of Boolean attributes remains unchanged.

Comparison of 2.x and 3.x behavior

Attributes v-bind value 2.x v-bind value 3.x HTML output
2.x "enum attribute"
ie  contenteditabledraggable and  spellcheck.
undefinedfalse undefinednull removed
true'true'''1'foo' true'true' "true"
null'false' false'false' "false"
Other non-boolean attributes
eg.  aria-checkedtabindexalt, etc.
undefinednullfalse undefinednull removed
'false' false'false' "false"

2.3, attributes, contains, class and style

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>

 So the migration may be in the wrong style

2.4. Custom commands

In Vue 2, custom directives are created by using the hooks listed below, all of which are optional

  • bind  - Occurs after the directive is bound to the element. Happens only once.
  • inserted  - Occurs after the element has been inserted into the parent DOM.
  • 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语法

In 2.x, developers could use this command to access the immediate child components of the current instance. $children:

in 3. x, the $children property has been removed and is no longer supported. Instead, it is recommended to use $refs if you need to access child component instances.

<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 , $on, $off and  $once instance methods have been removed, and the application instance no longer implements the event trigger interface.

3.3, filters filter delete

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

In 3.x, the filter was removed and is no longer supported. Instead, we recommend replacing them with method calls or computed properties.

Using the example above, here's an example of how to do it.

<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 删除

The $listeners object has been removed in Vue 3. Event listeners are now part of $attrs:

view2.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. The .native modifier of v-on has been deleted.

By default, event listeners passed to components with v-on are only triggered by emitting events with this. $emit. To add a native DOM listener to the root element of a child component, you can use the .native modifier:

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

The .native modifier for v-on has been removed. Also, the new emits option allows the child to define which events it does emit.

As a result, Vue now adds all event listeners that were not defined as components emitting events in the child as native event listeners to the child's root element (unless inheritAttrs:false is set in the child's options).

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

MyComponent.vue

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

4. Vue3 + view-ui-plus + js project upgrade

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

Guess you like

Origin blog.csdn.net/xm_w_xm/article/details/125893142