This paper mainly includes the following contents:

  1. Changes in V-Model usage
  2. Render function API changes
  3. Functional component usage changes
  4. Asynchronous component usage changes

The model option and the V-bind. sync modifier are removed to unify as a V-model parameter

V – model change
  • In vue2.0, using v-models on components is equivalent to binding value prop and input events:

    <ChildComponent v-model="pageTitle" />
    
    <! -- equivalent to: -->
    
    <ChildComponent :value="pageTitle" @input="pageTitle = $event" />
    Copy the code
  • In Vue2.2, add the Model component option. If you change the property or event name to something else, add the Model option to the ChildComponent component:

    <! -- ParentComponent.vue -->
    
    <ChildComponent v-model="pageTitle" />
    <! -- equivalent to: -->
    <ChildComponent :title="pageTitle" @change="pageTitle = $event" />
    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

    Another option is to use v-bind.sync

    Bidirectional data binding for a prop, the child component can pass the new value to the parent using the Update :myPropName emit event:

    this.$emit('update:title', newValue)
    Copy the code
    <ChildComponent :title.sync="pageTitle" />
    <! -- equivalent to: -->
    <ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
    Copy the code
  • In VUe2, sync and v-model functions overlap, but vue3 is unified: The model option and the v-bind. Sync modifier are removed, and the v-model parameter is unified

    A V-Model on a custom component is equivalent to passing a modelValue prop and receiving an Update :modelValue event thrown

    <comp v-model="data"></comp>
    <! -- equivalent to: -->
    <comp :modelValue="data" @update:modelValue="data=$event"></comp>
    Copy the code
    app.component('comp', {
    	template: `
    		<div @click="$emit('update:modelValue', 'new value')">
    			{{modelValue}}
    		</div>
    	`,
    	props: ['modelValue'],
    })
    Copy the code

    If you want to bind a prop of another name, you can pass an argument to the model:

    <comp v-model:title="data"></comp>
    <! -- equivalent to: -->
    <comp :title="data" @update:title="data=$event"></comp>
    Copy the code

Render function API changes

It mainly includes the following contents:

  1. What is theh()
  2. 3.x In contrast to2.x What are the changes to the render function?
hfunction

The h() function is a utility used to create a VNode. It is more accurately named createVNode(), but is shortened to H () due to its frequent use and brevity. The function takes three arguments:

// @returns {VNode}
h(
  // {String | Object | Function | null} tag
  // An HTML tag name, a component, an asynchronous component, or null.
  // Using null will render a comment.
  //
  // Necessary.
  'div'.// {Object} props
  // Objects corresponding to attributes, prop, and events.
  // We will use it in the template.
  //
  // Optional.
  {},

  // {String | Array | Object} children
  // Subvnodes, built using 'h()',
  // Get "text Vnode" with string or
  // Objects with slots.
  //
  // Optional.
  [
    'Some text comes first.',
    h('h1'.'A headline'),
    h(MyComponent, {
      someProp: 'foobar'})])Copy the code
Rendering functions have become simpler and easier to use. The main changes are as follows:
  • The Render function no longer takes the H argument, but imports it manually

    In 2.x, the render function automatically takes an h function as an argument:

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

    In 3.x, h requires manual import rather than automatic parameter passing, and the render function is often used inside the setup function, which makes it easier to access reactive states defined in scope, functions, and parameters passed in setup()

    import { h, reactive } from 'vue'
      export default {
        props: {
          counter: {
            type: Number.default: 0}},setup(props, {emit}) {
          const state = reactive({
            count: props.counter
          })
    
          function increment() {
            state.count++;
            emit('update:counter', state.count);
          }
    	 // Render function
          return () = >
            h(
              'div',
              {
                onClick: increment
              },
              state.count
            )
        }
      }
    Copy the code
  • Flattened props parameter structure

    In 2.x, domProps contains a nested list of VNode attributes:

            {
                class: ['color-tips'].style: { color: '#34495E' },
                attrs: {
                    title: 'text'.target: '_blank'.href: `www.baid.com`,},domProps: {
                	innerText: 'content',},on: {
                    click: () = > {
                    	console.log('Click event')}},key: 'xx'
            }
    Copy the code

    3. In x, the overall VNode attribute structure is flattened. The above example is rewritten as follows:

    {class: ['color: #34495E'], style: {color: '#34495E'}, href: 'www.baid.com ', innerText: 'content' onClick: () = > {the console. The log (' click event ')}, key: 'xx'}Copy the code
  • ScopedSlots has been deleted. It’s consolidated into slots

    2. X uses scopedSlots to obtain the slot content

    render() {
      // `<div><slot></slot></div>`
      return h('div', {}, this.$scopedSlots.default())
    }
    Copy the code

    3. X uses slots to access static slots, each of which is a VNode:

    render() {
      // `<div><slot></slot></div>`
      return h('div', {}, this.$slots.default())
    }
    Copy the code

Vue3 Disruptive Changes — Changes to functional components

Functional components vary greatly, mainly in the following aspects:
  • Performance improvement invue3Can be ignored, so using the state component is officially recommended
  • Functional components can only be declared and received in purely functional formpropscontext(Object containsslots , attrs ,emit) two parameters
  • Incompatible change: in the SFC<template> cannot be addedThe functional ‘feature declares functional components
  • Incompatible change : {functional: true}Component option Removal
2. Functional components in x

In 2.x, functional components have the following main advantages:

1. As a performance optimization, functional components initialize much faster than stateful components. Return multiple root nodes. 3. Create simple componentsCopy the code

Example: Creating a dynamic title component

// Function component Fuctional. Js
export default {
  functional: true.props: ['level'].render(h, ctx) {
    console.log('ctx', ctx);
    return h(`h${ctx.props.level}`, ctx.data, ctx.children); }};// The functional component example uses 
      
<template functional>
  <component :is="`h${props.level}`" v-bind="attrs" v-on="listeners">
    <div v-if="slots()">
      <slot></slot>
    </div>
  </component>
</template>

<script>
export default { props: ['level']};</script>

/ / the parent component
<template>
  <div>
    <Functional :level="1">This is a dynamic title element</Functional>
  </div>
</template>
<script>
import Functional from '@/components/Functional';
export default { components: { Functional } };
</script>

Copy the code

The console sees CTX as a FunctionalRenderContext object in the child component

3. functional components in x

In VUe3, the performance of stateful components is negligible, and stateful components can return multiple root nodes, so the advantages of functional components mentioned in VUE2 are eliminated, leaving scenarios created by simple components.

All functional components in VUe3 are created using normal functions, so there is no need to define {functional: true} component options. This function takes two arguments, props and context.

Additionally, H is not supplied implicitly in the render function, but is imported manually.

For migrations using functional on SFCs, simply remove the fucntional attribute and change propos to props, ‘attrs’ to props,’ attrs’ to props, ‘attrs’ to attrs, Listeners transmitted as part of attr may be deleted

The above example is written in VUe3:

// Function component Fuctional. Js
import {h} from 'vue';
const Heading = (props, context) = > {
    return h(`h${props.level}`, context.attrs, context.slots)
}
Heading.props = ['level'];

export default Heading;

// Single file component
<template>
  <component
    v-bind:is="`h${$props.level}`"
    v-bind="$attrs"
  />
</template>

<script>
export default {
  props: ['level']}</script>
Copy the code

Print the context on the console for a clearer structure, including attrs Emit slots

The original functional component was born for performance improvement, but the performance of VUe3 state component has been improved, the significance of functional component is not much, VUe3 destructive changes to functional components, subsequent development, it is suggested to write with state component

Asynchronous components are requireddefineAsyncComponentMethod to create

Since functional components in VUe3 must be defined as pure functions, asynchronous components are defined with the following changes:

  • Must be explicitly useddefineAsyncComponentWrap, distinguished from functional components
  • componentLet’s rename the choicesloader
  • loaderFunction not acceptedresolvereject, and must return a Promise
2.xIn writing:
// No configuration
const asyncPage = () = > import('./NextPage.vue')

/ / configuration
const asyncPage = {
  component: () = > import('./NextPage.vue'),
  delay: 200.timeout: 3000.error: ErrorComponent,
  loading: LoadingComponent
}
Copy the code
3.xAsynchronous component writing:

Define an asynchronous component: the defineAsyncComponent package

import { definedAsyncCompnent} from 'vue';
// No configuration
const asyncPage = definedAsyncCompnent(() = > import('./NextPage.vue'))
Copy the code

Asynchronous component with configuration. Loader option is the previous Component option

import { defineAsyncComponent } from 'vue'
import ErrorComponent from './components/ErrorComponent.vue'
import LoadingComponent from './components/LoadingComponent.vue'

const asyncPageWithOptions = defineAsyncComponent({
  loader: () = > import('./NextPage.vue'),
  delay: 200.timeout: 3000.errorComponent: ErrorComponent,
  loadingComponent: LoadingComponent
})
Copy the code

The loader function no longer accepts resolve and reject, and must always return a Promise

/ / 2. X version
const oldAsyncComponent = (resolve, reject) = > {
  / *... * /
}

/ / 3. X version
const asyncComponent = defineAsyncComponent(
  () = >
    new Promise((resolve, reject) = > {
      / *... * /}))Copy the code