Previous Article:Time to migrate from VUe2 to VUe3 (Series 1)

16. Inline template AttributeNot compatible with

Change overview:

  • Support for inline features has been removed.

2. X syntax

In 2.x, Vue provides inline-template attributes for child components to use their internal content as a template rather than as distribution content.

<my-component inline-template>
  <div>
    <p>They are compiled into the component's own template</p>
    <p>It's not what the parent contains.</p>
  </div>
</my-component>
Copy the code

3. X syntax

This feature is no longer supported.

Migration strategy

Most use cases for inline-template assume that there are no build tool Settings and that all templates are written directly to the HTML page.

Option 1: Use the <script> tag

In this case, the simplest solution is to

<script type="text/html" id="my-comp-template">
  <div>{{ hello }}</div>
</script>
Copy the code

In the component, use a selector to point to the target template:

const MyComp = {
  template: '#my-comp-template'
  // ...
}
Copy the code

It doesn’t require any build Settings, works in all browsers, isn’t constrained by any internal DOM HTML parsing warnings (you can use camelCase Prop names, for example), and provides proper syntax highlighting in most ides. In a traditional server-side framework, you can split these templates into server template parts (included in the main HTML template) for better maintainability.

Option 2: Default slot

Components that previously used inline-template can also use the default slot — for refactoring, which makes the data range more explicit while preserving the convenience of inlining subcontent:

<! --2.X syntax - ><my-comp inline-template :msg="parentMsg">
  {{ msg }} {{ childState }}
</my-comp><! -- Default Slot version --><my-comp v-slot="{ childState }">
  {{ parentMsg }} {{ childState }}
</my-comp>
Copy the code

The child should now render the default slot* instead of the supplied empty template:

<! In the child template, render the default slot in the necessary private state on pass. --><template>
  <slot :childState="childState" />
</template>
Copy the code

17.key attribute Not compatible with

Change overview:

  • New: Branch keys for V-if/V-else/V-else -if are no longer required, as Vue now automatically generates unique keys.
    • Incompatibility: If you supply keys manually, each branch must use a unique key. You cannot force reuse of branches by deliberately using the same key.
  • Incompatible: The key of

background

Special key attributes are used to prompt Vue’s virtual DOM algorithm to keep track of node identity. This allows Vue to know when existing nodes can be reused and patched, and when they need to be reordered or recreated.

In the condition branch

Vue 2.x recommends using keys in branches of V-if/V-else/V-else -if.

<! -- Vue2.x -->
<div v-if="condition" key="yes">Yes</div>
<div v-else key="no">No</div>
Copy the code

This example still works in Vue 3.x. However, we no longer recommend continuing to use key attributes in v-if/ V-else/V-else if branches, because a unique key is automatically generated when no key is provided for the conditional branch.

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

Incompatible changes occur when each branch must use a unique key if you manually provide a key. Therefore, in most cases, you don’t need to set these keys.

<! -- Vue2.x -->
<div v-if="condition" key="a">Yes</div>
<div v-else key="a">No</div><! -- Vue3.x (recommended solution: remove keys) -->
<div v-if="condition">Yes</div>
<div v-else>No</div><! -- Vue3.x (alternate solution: make sure the keys are always unique) -->
<div v-if="condition" key="a">Yes</div>
<div v-else key="b">No</div>
Copy the code

Combining with the < the template for > with a v –

In Vue 2.x, the <template> tag cannot have a key. However, you can set a key for each of its children.

<! -- Vue 2.x --> <template v-for="item in list"> <div :key="item.id">... </div> <span :key="item.id">... </span> </template>Copy the code

In Vue 3.x, the key should be set on the <template> tag.

<! -- Vue3.x -->
<template v-for="item in list" :key="item.id">
  <div>.</div>
  <span>.</span>
</template>
Copy the code

Similarly, when using <template v-for> there are children that use V-if, the key should be set on the <template> tag instead.

<! -- Vue2.x -->
<template v-for="item in list">
  <div v-if="item.isVisible" :key="item.id">.</div>
  <span v-else :key="item.id">.</span>
</template><! -- Vue3.x -->
<template v-for="item in list" :key="item.id">
  <div v-if="item.isVisible">.</div>
  <span v-else>.</span>
</template>
Copy the code

18. Key modifierNot compatible with

Change overview:

  • Incompatible: The use of numbers (i.e. key codes) as V-ON modifiers is no longer supported
  • Incompatible: Config.keycodes are no longer supported

2. X syntax

In Vue 2, keyCodes are supported as a way to modify V-on methods.

<! -- Keycode version --><input v-on:keyup.13="submit" /><! -- Alias version --><input v-on:keyup.enter="submit" />
Copy the code

In addition, you can also use the global config.keyCodes option.

Vue.config.keyCodes = {
  f1: 112
}
Copy the code
<! -- Keycode version --><input v-on:keyup.112="showHelpText" /><! -- Custom alias version --><input v-on:keyup.f1="showHelpText" />
Copy the code

3. X syntax

Since KeyboardEvent. KeyCode has been deprecated, it no longer makes sense for Vue 3 to continue to support this. Therefore, it is now recommended to use the kebab-cased (dash) case name for any key to be used as a modifier.

<! -- Vue3Use keystroke modifier on V-ON --><input v-on:keyup.delete="confirmDelete" />
Copy the code

Therefore, this means that config.keycodes are now deprecated and no longer supported.

19. Remove $listenersNot compatible with

Change overview:

  • The $Listeners object has been removed from Vue 3. Now the event listener is part of $attrs:
{
  text: 'this is an attribute'.onClose: () = > console.log('close Event triggered')}Copy the code

2. X syntax

In Vue 2, you can use this.$attrs and this.$Listeners to access the attributes and event listeners passed to the component, respectively. With inheritAttrs: false, developers can apply these attributes and listeners to other elements other than the root element:

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

3. X syntax

In the virtual DOM of Vue 3, event listeners are now just attributes prefixed with on, which makes them part of the $attrs object, so $Listeners have been removed.

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

If this component received an ID attribute and a V-ON :close listener, the $attrs object would now look like this:

{
  id: 'my-input'.onClose: () = > console.log('close Event triggered')}Copy the code

20. Access this in prop’s default functionNot compatible with

Factory functions that generate prop defaults can no longer access this.

Alternatives:

  • Pass the original prop received by the component as an argument to the default function;

  • Inject API is available in default functions.

import { inject } from 'vue'

export default {
  props: {
    theme: {
      default (props) {
        // 'props' is the raw value passed to the component.
        // Before any type/default cast
        // The injected property can also be accessed using 'inject'
        return inject('theme'.'default-theme')}}}}Copy the code

21. Render function APINot compatible with

Change overview:

  • This change does not affect <template> users.

  • Here is a brief summary of the changes:

    • H is now imported globally instead of being passed as an argument to the render function
    • Render function parameters changed to be more consistent between stateful components and function components
    • VNode now has a flat prop structure

Render function parameters

2. X syntax

In 2.x, the render function automatically accepts h (the traditional alias for createElement) as an argument:

// Vue 2 render function example
export default {
  render(h) {
    return h('div')}}Copy the code

3. X syntax

In 3.x, h is now imported globally instead of being passed automatically as a parameter.

// Vue 3 render function example
import { h } from 'vue'

export default {
  render() {
    return h('div')}}Copy the code

Render function signature changed

2. X syntax

In 2.x, the render function automatically accepts arguments such as h.

// Vue 2 render function example
export default {
  render(h) {
    return h('div')}}Copy the code

3. X syntax

In 3.x, since the render function no longer takes any arguments, it will be used primarily inside the setup() function. This has another benefit: you can access reactive states and functions declared in scope, as well as parameters passed to setup().

import { h, reactive } from 'vue'

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

    function increment() {
      state.count++
    }

    // returns the render function
    return () = >
      h(
        'div',
        {
          onClick: increment
        },
        state.count
      )
  }
}
Copy the code

Format VNode Prop

2. X syntax

In 2.x, domProps contains a nested list in VNode Prop:

// 2.x
{
  staticClass: 'button'.class: { 'is-outlined': isOutlined },
  staticStyle: { color: '#34495E' },
  style: { backgroundColor: buttonColor },
  attrs: { id: 'submit' },
  domProps: { innerHTML: ' ' },
  on: { click: submitForm },
  key: 'submit-button'
}
Copy the code

3. X syntax

In 3.x, the entire VNode prop structure is flat. Use the example above to see what it looks like today.

/ / 3. X syntax
{
  class: ['button', { 'is-outlined': isOutlined }],
  style: [{ color: '#34495E' }, { backgroundColor: buttonColor }],
  id: 'submit'.innerHTML: ' '.onClick: submitForm,
  key: 'submit-button'
}
Copy the code

Certified components

2. X syntax

In 2.x, after registering a component and passing the component name as the first argument to the render function as a string, the render function works fine:

// 2.x
Vue.component('button-counter', {
  data() {
    return {
      count: 0}}template: `  `
})

export default {
  render(h) {
    return h('button-counter')}}Copy the code

3. X syntax

In 3.x, because VNode is context-free, you can no longer use string IDS to implicitly look up registered components. Instead, you need to use an imported resolveComponent method:

// 3.x
import { h, resolveComponent } from 'vue'

export default {
  setup() {
    const ButtonCounter = resolveComponent('button-counter')
    return () = > h(ButtonCounter)
  }
}
Copy the code

22. Unify slotsNot compatible with

Change overview:

  • This change unifies normal and scoped slots in 3.x.
    • This.$slots now exposes slots as functions
    • Incompatible: Remove this.$scopedSlots

2. X syntax

When using render functions, h, 2.x is used to define slot data properties on content nodes.

/ / 2 x syntax
h(LayoutComponent, [
  h('div', { slot: 'header' }, this.header),
  h('div', { slot: 'content' }, this.content)
])
Copy the code

In addition, when referencing scoped slots, you can refer to them using the following method:

/ / 2 x syntax
this.$scopedSlots.header
Copy the code

3. X syntax

In 3.x, the slot is defined as a child object of the current node:

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

When you need to programmatically refer to scoped slots, they are now consolidated into the $slots option.

/ / 2 x syntax
this.$scopedSlots.header

/ / 3. X syntax
this.$slots.header()
Copy the code

Migration strategy

Most of the changes have been released in 2.6. Therefore, migration can be done in one step:

  • In 3.x, replace all this.$scopedSlots with this.$slots.
  • Replace all this.$slots.myslot with this.$slots.myslot ().

23. Transition class name changeNot compatible with

Changes in the overview

  • The name of the transition class v-enter was changed to v-enter-from, and the name of the transition class v-leave was changed to v-leave-from.

2. X syntax

Prior to v2.1.8, two transition class names were provided for transition directives corresponding to the initial and active states.

In v2.1.8, v-enter was introduced to define the transition animation frame between the Enter or leave transform. For downward compatibility, the v-Enter class name was not changed:

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

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

3. X syntax

For clarity and legibility, we now rename these initial states to:

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

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

Now, the distinction between these states is much clearer.

<transition> Component property names have also changed:

  • Leave-class has been renamed leave-from-class (in rendering functions or JSX you can write leaveFromClass)
  • Enter-class has been renamed to enter-from-class (in render functions or JSX it could be: enterFromClass)

24.Transition Group root elementNot compatible with

Change overview:

  • no longer renders the root element by default, but it can still be created with tag Prop.

2. X syntax

In Vue 2, <transition-group>, like other custom components, requires a root element. The default root element is a <span>, but can be customized with Tag Prop.

<transition-group tag="ul">
  <li v-for="item in items" :key="item">
    {{ item }}
  </li>
</transition-group>
Copy the code

3. X syntax

In Vue 3, we have fragment support, so components no longer need a root node. So, <transition-group> does not render the root node by default.

  • If, as in the example above, tag Prop has been defined in Vue 2 code, everything will be just as before
  • If no tag prop is defined, and the style or other behavior depends on the presence of the root element to work properly, then simply add tag=”span” to
    :
<transition-group tag="span"> <! -- --> </transition-group>Copy the code

25. Remove the V-on. native modifierNot compatible with

Change overview:

  • The.native modifier for v-ON has been removed.

2. X syntax

By default, event listeners passed to components with V-ON can only be emitted via this.$emit. To add a native DOM listener to the root element of a child component, use the.native modifier:

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

3. X syntax

The.native modifier for v-ON has been removed. Also, the new emits option allows child components to define events that will actually be fired.

As a result, Vue will now add all event listeners in the child component that are not defined to be triggered by the component as native event listeners to the root element of the child component (unless inheritAttrs: False is set in the child component’s options).

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

MyComponent.vue

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

26.v-model Not compatible with

Change overview:

  • Incompatible: V-Model Prop and event default names have been changed when used for custom components:
    • Prop: value -> modelValue;
    • Event: input -> update:modelValue;
  • Incompatible: v-bind’s.sync modifier and component’s model option have been removed and v-model can be used instead;
  • New: Bidirectional binding with multiple V-Models on the same component is now possible;
  • New: V-Model modifiers can now be customized.

introduce

After Vue 2.0 was released, developers using v-model directives had to use prop as Value. If a developer needs to use another prop for a different purpose, they have to use V-bind.sync. In addition, this hard-coded relationship between the V-Model and value raises the question of how to handle native and custom elements.

In Vue 2.2, we introduced the Model component option, which allows components to customize prop and events for v-Models. However, this still allows only one Model to be used on the component.

In Vue 3, the API for two-way data binding has been standardized, reducing developer confusion when using V-Model directives and allowing more flexibility when using V-Model directives.

2. X syntax

In 2.x, using v-Models on components is equivalent to binding value prop and input events:

<ChildComponent v-model="pageTitle"/ > <! -- is short for: --><ChildComponent :value="pageTitle" @input="pageTitle = $event" />

Copy the code

To change the property or event name to something else, add the Model option to the ChildComponent component:

<! -- ParentComponent.vue --><ChildComponent v-model="pageTitle" />
Copy the code
// ChildComponent.vue

export default {
  model: {
    prop: 'title'.event: 'change'
  },
  props: {
    // This will allow the 'value' attribute to be used for other purposes
    value: String.// Use 'title' instead of 'value' as model prop
    title: {
      type: String.default: 'Default title'}}}Copy the code

So, in this case v-model is shorthand for:

<ChildComponent :title="pageTitle" @change="pageTitle = $event" />

Copy the code

Use the v – bind. The sync

In some cases, we may need to “bidirectional bind” a prop (except for the previous v-model binding of the prop). To do this, we recommend throwing events using Update :myPropName. For example, for the ChildComponent with a title prop in the previous example, we could communicate the intent to assign a new value to the parent as follows:

this.$emit('update:title', newValue)
Copy the code

The parent can listen for this event and update the local data property if needed. Such as:

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

Copy the code

For convenience, we can use the.sync modifier to abbreviate, as follows:

<ChildComponent :title.sync="pageTitle" />

Copy the code

3. X syntax

In 3.x, a V-Model on a custom component is equivalent to passing a modelValue prop and receiving an Update :modelValue event thrown:

<ChildComponent v-model="pageTitle"/ > <! -- is short for: --><ChildComponent
  :modelValue="pageTitle"
  @update:modelValue="pageTitle = $event"
/>
Copy the code

V – model parameters

If we need to change the Model name instead of changing the Model option within the component, we can now pass an argument to Model:

<ChildComponent v-model:title="pageTitle"/ > <! -- is short for: --><ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
Copy the code

This can also be used as an alternative to the.sync modifier and allows us to use multiple V-Models on custom components.

<ChildComponent v-model:title="pageTitle" v-model:content="pageContent"/ > <! -- is short for: --><ChildComponent
  :title="pageTitle"
  @update:title="pageTitle = $event"
  :content="pageContent"
  @update:content="pageContent = $event"
/>
Copy the code

V – model modifier

In addition to hard-coded 2.x V-model modifiers like.trim, 3.x now supports custom modifiers:

<ChildComponent v-model.capitalize="pageTitle" />
Copy the code

27. Priority comparison between V-IF and V-forNot compatible with

Changes in the overview

  • Incompatible: V-if has a higher priority than V-for when both work on the same element.

introduce

The two most used directives in vue.js are V-if and V-for, so developers may want to use both. While this is not recommended, it is sometimes necessary, so we want to provide guidance on how it works.

2. X syntax

2. In the x version, when v-if and V-for are used on the same element, v-for takes precedence.

3. X syntax

3. In the X version, V-if always takes effect before V-for.

28. V-bind merge behaviorNot compatible with

Change overview:

  • Incompatible: The binding order of V-bind affects the rendering result

introduce

When attributes are dynamically bound to elements, a common scenario is to use both the V-bind =”object” syntax and a separate property in one element. However, this raises questions about the priority of the merger.

2. X syntax

In 2.x, if an element defines both v-bind=”object” and an identical separate property, that separate property will always override the binding in object.

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

3. X syntax

In 3.x, if an element defines both V-bind =”object” and the same individual property, the order in which the bindings are declared determines how they are combined. In other words, developers now have much better control over what they want to merge, rather than assuming that they always want separate properties to override what is defined in 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>
Copy the code

29.Watch on Arrays Not compatible with

Change overview:

  • Incompatible: When listening on an array, the callback is triggered only when the array is replaced. If you need to trigger a callback when an array changes, you must specify the deep option.

3. X syntax

When you listen on an array with the Watch option, the callback is triggered only if the array is replaced. In other words, the Watch callback will no longer be fired when the array changes. To trigger the Watch callback when the array changes, you must specify the deep option.

watch: {
  bookList: {
    handler(val, oldVal) {
      console.log('book list changed')},deep: true}},Copy the code

Finally:

This note is based on the official document migration policy. If there is any discrepancy, please refer to the official document. You are advised to use the official documents as a supplement. This way you can examine the reading “for yourself” and not be swayed by my opinions

Share the links of some knowledge points and articles arranged by yourself

  • Record front-end development engineer interviews from the end of March to April

  • Interview high frequency handwritten JS code

  • A big factory

  • Webpack explains everything from shallow to deep, so as to achieve the so-called “familiar” on the resume (Series 1)

  • Webpack explains everything from shallow to deep, so as to be truly “familiar” on the resume (Series 2)

  • Webpack explains everything from shallow to deep, so as to be truly “familiar” on the resume (Series 3)

  • Webpack explains everything from shallow to deep, so as to be truly “familiar” on the resume (Series 4)

  • Webpack explains everything from shallow to deep, so as to be truly “familiar” on the resume (Series 5)