Vue3.0 Learning Suggestions

For those who have learned vue2.0

Vue3.0 new features

Chinese document

  • Composition Api (Core)
  • V – model changes
  • Usage on key node of V-for changed
  • V-if and V-for have higher priority for the same element
  • Ref internal V-for no longer registers reference arrays
  • Functional components can only be created using normal functions
  • Asynchronous components are requireddefineAsyncComponentCreate method
  • All slots pass$slots
  • indestroyedThe lifecycle option has been renamed tounmounted
  • inbeforeDestroyThe lifecycle option has been renamed tobeforeUnmount
  • .

Advantages and disadvantages Vue3.0

Advantages:

  1. The vast majority of Vue internal API external exposure, so that Vue has the ability to develop large projects, such as compile compile API
  2. Treeshaking for Webpack (Tree Shaking is DCE’s way of ignoring unused code when packaging.) Support friendly
  3. Using Proxy for reactive variable definition improves performance by 1.2~2 times
  4. SSR is two to three times faster
  5. You can use the composition-API plug-in in Vue2.0 alone, or you can develop plug-ins with it directly
  6. More friendly to typescript support
  7. For the future: For Yu Creek’s recently innovated Vite development server (a high-performance development server that abandons Webpack and uses the UNDERLYING Koa framework), directly use the Vue3.0 syntax

Disadvantages:

  1. Only Internet Explorer 11 or later is supported
  2. For developers who are used to the Vue2.0 development mode, it will increase the mental burden and experience the developer’s code organization ability

It’s also an opportunity to develop your capabilities. I particularly like the Vue author’s design philosophy: let developers grow with the framework

Experience the four poses of Vue3.0

For now, there are four postural portals to experience Vue3.0

  • Through the CDN: < script SRC = “https://unpkg.com/vue@next” > < / script >

  • Playground via Codepen’s browser

  • Scaffolding Vite:

    npm init vite-app hello-vue3 # OR yarn create vite-app hello-vue3
    Copy the code

A new tool developed by UHP, intended to replace WebPack in the future, was originally developed to take advantage of browsers that now support ES6 import; When an import is encountered, it sends an HTTP request to load the corresponding file. Vite intercepts these requests and precompiles them, eliminating webPack’s lengthy packaging events and improving the development experience.

  • Scaffolding vue – cli

    npm install -g @vue/cli # OR yarn global add @vue/cli
    vue create hello-vue3
    # select vue 3 preset
    Copy the code

Global API

New global API: createApp

Calling createApp returns an application instance, which is a new concept in Vue3.0:

Open the SRC/main. Js

import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.mount('#app')
Copy the code

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

2. X global API 3.x instance API (app)
Vue.config app.config
Vue.config.productionTip removedHas been removed
Vue.config.ignoredElements app.config.isCustomElement
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use

Composition API learning

The official website

setup


The setup function is a new component option. Act as an entry point for using the Composition API within a component

Create the component instance, initialize props, and then call the setup function. It is called before the beforeCreate hook.

Setup returns an object. All properties of the object, which are reactive data, can be used directly in the template. Equivalent to the object returned by the data function in Vue2.0.

App.vue

<script>
export default {
  setup () {
    return{}}}</script>
Copy the code

Responsive data

  • Ref: Can pass in any type of value and return a responsive and mutable REF object. The REF object has a single attribute that points to an internal value.valueThe value attribute must be used when changing a value
  • Reactive: A reactive proxy that accepts a common object and returns that common object. Equivalent to 2.xVue.obserable()

In short: Reactive is responsible for complex data structures, and REF can wrap basic data structures into responsive form

reactive


<template>
  <div>
    <h2>{{state.count}}</h2>
    <button @click="add">To calculate</button>
  </div>
</template>

<script>
import { reactive } from "vue";
export default {
  setup(){
    Reactive is responsible for complex data structures,
    const state = reactive({
      count: 1
    });
    function add() {
      state.count++;
    }
    return{ state, add}; }};</script>
Copy the code

ref


<template>
  <div>
    <h2>{{state.count}}</h2>
    <h3>{{num}}</h3>
    <button @click="add">To calculate</button>
  </div>
</template>
<script>
import { reactive, ref } from "vue";
export default {

  setup(){
    const state = reactive({
      count: 1
    });
    const num = ref(0);
    function add() {
      state.count++;
      num.value+=2
    }
    return{ state, add, num }; }};</script>
Copy the code

Num can be used directly in the template, but the.value attribute can be used when changing js.

toRefs


Converts a reactive object to a normal object, where each property of the resulting object points to the corresponding property of the original object

ToRefs is useful when returning a reactive object from a synthesized function so that the consuming component can decompose/diffuse the returned object without losing the reactive:

useFeatureX.js

import {reactive} from 'vue';
export function userFeatureX(){
  const state = reactive({
    foo: 1.bar: 2
  })

  // Logical running status

  // Convert to ref on return
  return state;
}
Copy the code

App.vue

import {toRefs} from 'vue'
export default {
  setup(){
    const state = useFeatureX();
    return {
      ...toRefs(state)
    }
  }
}
Copy the code

computed

Pass in a getter function that returns a ref object that cannot be manually modified by default.

import { reactive, ref, computed } from "vue";
export default {

  setup() {
    Reactive is responsible for complex data structures.
    const state = reactive({
      count: 1
    });
    // 2.ref can wrap basic data structures in response form
    const num = ref(0);
    // 3. Create a read-only compute property
    const computedEven1 = computed(() = > state.count % 2);
    // 4. Create readable and writable computed properties
    const computedEven2 = computed({
      get:() = >{
        return state.count % 2;
      },
      set: newVal= >{ state.count = newVal; }})// Declaration of the event
    function add() {
      state.count++;
      num.value += 2;
    }

    function handleClick() {
      computedEven2.value = 10;
    }



    return{ state, add, num, computedEven1,computedEven2,handleClick }; }};Copy the code

watchEffect

Execute a function passed in immediately, trace its dependencies responsively, and re-run the function when its dependencies change.

const num = ref(0)

watchEffect(() = > console.log(count.value))
// -> print out 0

setTimeout(() = > {
  count.value++
  // -> print 1
}, 100)
Copy the code
  1. Stop listening

    Implicit stop

    When watchEffect is called on a component’s setup() function or lifecycle hook, the listener is linked to the component’s lifecycle and stops automatically when the component is uninstalled

    According to stop

    In some cases, you can also display the return value of the call to stop listening

    const stop = watchEffect(() = >{
      / *... * /
    })
    // Stop listening
    stop()
    Copy the code
  2. Clearance side effect

    Sometimes side effects functions perform asynchronous side effects, and these responses need to be cleared when they fail (that is, the state has changed before completion). You can take an onInvalidate function as an argument in the function that listens for side effects incoming to register a callback in case of a cleanup failure. This invalidation callback is triggered when:

    • When the side effect is about to be re-executed
    • The listener is stopped (if insetup()Or the lifecycle hook functionwatchEffect, when uninstalling components)

    Examples from the official website:

    watchEffect((onInvalidate) = > {
      const token = performAsyncOperation(id.value)
      onInvalidate(() = > {
        // When the id changes or the listening stops
        // Cancel the asynchronous operation
        token.cancel()
      })
    })
    Copy the code

Case: To achieve the effect of user input “anti-shake”

<template>
  <div>
    <input type="text"
           v-model="keyword">
  </div>
</template>

<script>
  import { ref, watchEffect } from 'vue'

  export default {
    setup() {
      const keyword = ref(' ')
      const asyncPrint = val= > {
        return setTimeout(() = > {
          console.log('user input: ', val)
        }, 1000)
      }
      watchEffect(
        onInvalidate= > {
          // If the interval entered by the user is less than one second, the timing will be cleared immediately and no result will be entered. Because of this, the user has realized the function of shaking, only when the user input time interval is greater than 1 second, do the printing
          const timer = asyncPrint(keyword.value)
          onInvalidate(() = > clearTimeout(timer))
          console.log('keyword change: ', keyword.value)
        },
        // Flush: 'pre' watch() and watchEffect() run side effects before the DOM is mounted or updated, so the template reference has not yet been updated when the listener runs.
        // Flush: defined with the 'post' option, which runs side effects after DOM updates, ensuring that template references are in sync with the DOM and refer to the correct elements.
        {
          flush: 'post' // Default 'pre', sync' sync', 'pre' component before update})return {
        keyword
      }
    }
  }
  // Enable the user to enter "anti-shake" effect
</script>
Copy the code

watch


The Watch API is exactly equivalent to 2.x this.$watch (and the corresponding option in Watch). Watch needs to listen for specific data sources and perform side effects in callback functions. The default is lazy, meaning that callbacks are executed only when the source changes are being listened for.

The first argument received by watch() is called a “data source “, which can be:

  • A getter function that returns any value
  • A wrapper object (can be a REF or a Reactive wrapper object)
  • An array containing both data sources

The second argument is the callback function. The callback function is triggered only when the data source changes:

  1. Listening to a single data source

    const state = reactive({count: 1});
    
    // Listen to data defined by reactive. Changing count triggers a watch callback
    watch(() = >state.count,(newCount,oldCount) = >{
      console.log('newCount:',newCount);  
      console.log('oldCount:',oldCount);
    })
    // listen for a ref
    const num = ref(0);
    watch(num,(newNum,oldNum) = >{
      console.log('newNum:',newNum);  
      console.log('oldNum:',oldNum);
    })
    Copy the code
  2. Listening for multiple data sources (arrays)

    const state = reactive({count: 1});
    const num = ref(0);
    // Listen on an array
    watch([() = >state.count,num],([newCount,newNum],[oldCount,oldNum]) = >{
      console.log('new:',newCount,newNum);
      console.log('old:',oldCount,oldNum);
    })
    Copy the code
  3. Listen for complex nested objects

    In our actual development, we see complex data everywhere, such as:

    const state = reactive({
      person: {
        name: 'Joe'.fav: ['handsome boy'.'beauty'.'music']}}); watch(() = > state.person,
      (newType, oldType) = > {
        console.log("The new value.", newType, "The old values.", oldType);
      },
      { deep: true }, // Listen immediately
    );
    Copy the code

You cannot listen for data changes without using the third parameter deep:true. As we mentioned earlier, watch is lazy by default, so when is it not lazy and the callback can be executed immediately? Set the third parameter to immediate: true

At the same time, Watch and watchEffect behave the same in stopping listening, clearing side effects (onInvalidate is passed in accordingly as the third argument to the callback), and so on.

<template>
  <div>
    <input type="text"
      v-model="keyword">
  </div>
</template>

<script>
import { ref, watch } from 'vue'

export default {
  setup() {
    const keyword = ref(' ')
    const asyncPrint = val= > {
      return setTimeout(() = > {
        console.log('user input: ', val)
      })
    }

    watch(
      keyword,
      (newVal, oldVal, onCleanUp) = > {
        const timer = asyncPrint(keyword)
        onCleanUp(() = > clearTimeout(timer))
      },
      {
        lazy: true // The default is false, that is, the initial listening callback is executed})return {
      keyword
    }
  }
}
</script>
Copy the code

Lifecycle hook


A composite API corresponding to the 2.x release lifecycle

Create a new Test component/Components/test.vue

<template>
  <div id="test">
    <h3>{{a}}</h3>
    <button @click="handleClick">To change the</button>
  </div>
</template>

<script>
import {
  ref,
  onMounted,
  onBeforeMount,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
} from "vue";
export default {
  // The lifecycle of the initialization data phase, between beforeCreate and Created
  setup() {
    const a = ref(0);
    console.log("👌");
    function handleClick() {
      a.value += 1;
    }
    onBeforeMount(() = > {
      console.log("Components before mounting");
    });
    onMounted(() = > {
      console.log("DOM mount complete");
    });
    onBeforeUpdate(() = > {
      console.log("Before DOM update".document.getElementById("test").innerHTML);
    });
    onUpdated(() = > {
      console.log("DOM update completed".document.getElementById("test").innerHTML);
    });
    onBeforeUnmount(() = > {
      console.log("Before instance uninstallation");
    });
    onUnmounted(() = > {
      console.log("After instance uninstallation");
    });
    return{ a, handleClick }; }};</script>
Copy the code

Officially, you don’t have to understand everything right away, but it will become more valuable as you learn and use it.

Dependency injection


Provide and inject Provide dependency injection, which is similar to provide/inject of 2.x. Both can only be called from setup() of the current component

App. Vueprovide data sources

<template>
  <div>
    <Article></Article>
  </div>
</template>

<script>
import {
  ref,
  provide
} from "vue";
import Article from "./components/Article";
export default {
  setup() {
    const articleList = ref([
      { id: 1.title: "Vue3.0 learning".author: "Little Marco" },
      { id: 2.title: "componsition api".author: "Yoda" },
      { id: 3.title: "Vue - the router's latest".author: "Vue official"}]);/* provide allows you to define properties with two arguments: the name of the property (type 
       
        ) the value of the property */
       
    provide("list",articleList);
    return {
      articleList
    };
  },
  components: {
    Article
  }
};
</script>
Copy the code

Article. Vue injects data

<template>
  <div>
    {{articleList[0].title}}
  </div>
</template>

<script>
import { inject } from "vue";
export default {
  setup() {
    const articleList = inject('list'[]);return{articleList}; }};</script>
Copy the code

The template references refs


When using composite apis, the concepts of Reactive refs and Template Refs are unified. To get a reference to an element or component instance within a template, declare a ref directly in setup() and return it

<template>
  <div>
    <div ref='wrap'>Hello vue3.0</div>
    <Article ref='articleComp'></Article>
  </div>
</template>

<script>
import {
  ref,
  onMounted,
  provide
} from "vue";
import Article from "./components/Article";
export default {
  setup() {
    const isShow = ref(true);
    const wrap = ref(null);
    const articleComp = ref(null);

    const articleList = ref([
      { id: 1.title: "Vue3.0 learning".author: "Little Marco" },
      { id: 2.title: "componsition api".author: "Yoda" },
      { id: 3.title: "Vue - the router's latest".author: "Vue official"}]);/* provide allows you to define properties with two arguments: the name of the property (type 
       
        ) the value of the property */
       
    provide("list", articleList);

    onMounted(() = > {
      console.log(wrap.value); // Get the div element
      console.log(articleComp.value); // Get the article component instance object
      
    });
    return {
      articleList,
      wrap,
      articleComp
    };
  },
  components: {

    Article
  }
};
</script>

<style scoped>
</style>
Copy the code

Effect:

Component communication

  • props
  • $emit
  • expose /ref
  • attrs
  • v-model
  • provide/inject
  • vuex
  • mitt

props

/ / Parent. Vue
<child :msg1="msg1" :msg2="msg2"></child>
<script>
import child from "./child.vue"
import { ref, reactive } from "vue"
export default {
    setup(){
        // Create a responsive data
        const msg1 = ref("This is the message of the cascade subcomponent 1")
        const msg2 = reactive(["This is the message of the cascade subcomponent 2"])
        return {
            msg1
            msg2
        }
    }
}
</script>

. / / the Child received vue
<script>
export default {
  props: ["msg1"."msg2"].// If this line is not written, the following is not received
  setup(props) {
    console.log(props) // {msg1:" This is the message to child component 1", msg2:" This is the message to child component 2"}}},</script>
Copy the code

$emit

/ / Child. The vue
<template>
  / / write one
  <button @click="$emit('myClick',123)">button</buttom>
</template>
<script> 
 export default {
	emits: ['myClick']
	//emits:{
  //myClick:null
  / /}
}

</script>

/ / Parent. Vue response
<template>
    <child @myClick="onMyClick"></child>
</template>
<script setup>
  import child from "./child.vue"
const onMyClick = (msg) = > {
  console.log(msg) // This is the message received by the parent component 123
}
</script>
Copy the code

Major change

Teleport

Teleport is like the “any door” in Doraemon. The function of any door is to Teleport people to another place in an instant. With this in mind, let’s see why we need to use the Teleport feature. Here’s a small example: Using a Dialog component in the Header child component makes it difficult to handle the positioning, z-index, and styling of nested components in similar situations that we often use in real development. Dialog should be an independent component from the user perception level, and the DOM structure should be completely stripped of the DOM mounted by the Vue top-level component. You can also use the value of the state (data or props) within the Vue component. Simply put, you want to continue to use dialogs inside the component, but you want to render DOM structures that are not nested inside the component’s DOM. This is where Teleport comes in. We can wrap the Dialog with

, which creates a portal that sends the contents of Dialog’s rendering to any specified location. Here’s a quick example of how Teleport can be used.

We want the DOM rendered by the Dialog to be sibling to the top-level component, defining a mount element in the index.html file:

<body>
  <div id="app"></div>
  <div id="dialog"></div>
</body>
Copy the code

Define a Dialog component dialog. vue, note that the to attribute is the same as the id selector above:

<template>
  <teleport to="#dialog">
    <! You want to continue using dialogs inside the component, but you also want to render DOM structures that are not nested inside the component's DOM. This is where Teleport comes in. We can wrap the Dialog with <Teleport>, which creates a portal to send the contents of the Dialog rendering to any specified location -->
    <div class="dialog">
      <div class="dialog_wrapper">
        <div class="dialog_header">
          <h3>I'm popbox {{count}}</h3>
        </div>
      </div>
    </div>
  </teleport>
</template>

<script>
import { reactive, toRefs } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,})return {
      ...toRefs(state),
    }
  },
}
</script>

<style lang="less" scoped></style>

Copy the code

Suspense

experimental

Suspense is an experimental new feature with an API that can change at any time. This announcement is made so that the community can provide feedback on the current implementation.

Do not use it in production environment

The suspense> component provides an alternative that allows the waiting process to be promoted into a component tree rather than in a single component.

The default slots are default and fallback. As the name implies, when a component to load does not meet its state,Suspense will fallback to fallback state until the component to load meets its condition.

Suspense.vue

Xx64 < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > < xx64 > </template> <template #fallback> <div class="loading"></div> </template> </Suspense> </template> <script> import { ref, defineAsyncComponent } from 'vue' export default { components: { MAsynComp: defineAsyncComponent(() => import('./AsynComp.vue')), }, setup() { const loadAsync = ref(false) const loadAsyncComponent = () => { loadAsync.value = true } return { loadAsync, loadAsyncComponent, } }, } </script> <style lang="less" scoped> button { padding: 12px 12px; background-color: #1890ff; outline: none; border: none; border-radius: 4px; color: #fff; cursor: pointer; } .loading { position: absolute; width: 36px; height: 36px; top: 50%; left: 50%; margin: -18px 0 0 -18px; background-image: url('.. /assets/loading.png'); background-size: 100%; Animation: Rotate 1.4s Linear infinite; } @keyframes rotate { from { transform: rotate(0); } to { transform: rotate(360deg); } } </style>Copy the code

AsynComp.vue

<template> <h1>this is async component</h1> </template> <script> import { setup } from 'vue' export default { name: 'AsyncComponent', async setup() { const sleep = (time) => { return new Promise((reslove, Reject) => {setTimeout(() => {reslove()}, time)})} await sleep(3000),} </script>Copy the code

Fragments

Multiple root components are allowed in Vue3.0 components, eliminating unnecessary div renderings

<template>
  <div>The head</div>
  <div>content</div>
</template>
Copy the code

The benefits of this:

  • A lot fewer div’s that don’t make sense
  • Horizontal recursion can be achieved, which is of great help in implementing the Tree component

emits

  • emits can be an array or an object
  • Triggers a custom event
  • If emits is an array, this allows us to configure and validate events. The validation function should return a Boolean value indicating whether the event parameter is valid.

Emits.vue

$emit('submit',{username:'xiaomage',password:'123'})"> </button> </div> </template> <script> export default {// emits:['submit'],// can be array emits: {submit: payload => { if(payload.username && payload.password){ return true; }else{console.warn(' Invalid payload, please check submit event '); return false } } }, setup() { return {}; }}; </script> <style scoped> </style>Copy the code

App.vue

<Emits @submit="submitHandle"></Emits> <script> import Emits from "./components/Emits"; Export default{components:{Emits}, setup(){function submitHandle(payload) {console.warn(" custom event trigger ",payload); } return { } } } </script>Copy the code

Effect display:

The global Vue API is changed to the application instance

The above has been said, not to repeat one by one.

API can do Tree shakable optimization

In Vue2.0 there are many global apis that hang directly on the Vue constructor as static functions. You should have manually manipulated the DOM and encountered the following pattern. If we don’t use them in code, we form what we call “dead code”. This kind of global API creates “dead code” that cannot be “dead code removed” using Webapck’s tree-shaking.

import Vue from 'vue'
Vue.nextTick(() = >{
  // Something DOM related
})
Copy the code

As a result, Vue3.0 has made a change to separate them into separate functions so that tree shaker optimization of the packaging tool can eliminate these “dead code”. The global API can now only be accessed as named exports of ES module builds. For example, our previous fragment should now look like this

import {nextTick} from 'vue'
nextTick(() = >{
  // Something DOM related
})
Copy the code

Affected apis


These global apis in Vue2. X are affected by this change:

  • Vue.nextTick
  • Ue. Observable (replaced by ue. Reactive)
  • Vue.version
  • Vue.compile(fully built only)
  • Vue.set(Compatible version only)
  • Vue.delete(Compatible version only)

TreeShaking.vue

<template>
<div >
  <hr />Tree shaking optimizes unnecessary code that has not been introduced<div id='name'>Mr Ma</div>
  <h3 ref='myMsg'>{{msg}}</h3>
  <button @click="changeMsg('hai! ')">change</button>
  </div>
</template>

<script>
  import { ref, nextTick } from "vue";
  export default {
    setup() {
      const msg = ref("hello!");
      const myMsg = ref(null);
      async function changeMsg(newV) {
        msg.value = newV;
        // console.log(myMsg.value.innerText); // Get the DOM directly as before
        NextTick returns a Promise object
        await nextTick();
        console.log(myMsg.value.innerText);
      }
      return{ msg, myMsg, changeMsg }; }};</script>
Copy the code

Slot Name Slot syntax

In Vue2. X, the named slot is written:

<! -- Subcomponent: -->
<slot name="title"></slot>
Copy the code

Used in the parent component:

<template slot="title">
    <h1>Song: "The Lonely One"</h1>
<template>
Copy the code

If we want to bind data to a slot, we can use a scoped slot as follows:

// subcomponent <slot name="content" :data="data"></slot> export default {data(){return{data:[" Go through people come and go "," don't like to enjoy "," company is the most love "] }}}Copy the code
<! -- used in parent component -->
<template slot="content" slot-scope="scoped">
    <div v-for="item in scoped.data">{{item}}</div>
<template>
Copy the code

In vue2. x, named slot and scoped slot are implemented using slot and slot-scope respectively. In Vue3.0, slot and slot-scope are combined and approved. The v – slot Vue3.0:

<! -- used in parent component -->
 <template v-slot:content="scoped">
   <div v-for="item in scoped.data">{{item}}</div>
</template>

<! -->
<template #content="{data}">
    <div v-for="item in data">{{item}}</div>
</template>
Copy the code

V-model usage on components


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" />

<! -->

<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 example, v-model is abbreviated as follows:

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

usev-bind.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" />

<! -->

<ChildComponent
  :modelValue="pageTitle"
  @update:modelValue="pageTitle = $event"
/>
Copy the code

Render function API changed

  • hIt is now imported globally instead of being passed as a parameter to the render function
  • Render function parameters are more consistent between stateful components and function components
  • Vnode is now a flat prop structure

The Render function will automatically accept the h function (alias for createElement) as an argument

//vue2.x
export default{
  render(h){
    return h('div')}}/ / vue3 rendering
import { h } from 'vue'

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

Here’s an example:

<template>
  <div>
    <RenderComp v-model='title'>
      <template v-slot:default>
        <! -- Default slot -->The head</template>
      <template v-slot:content>
        <! -- named slot -->content</template>
  </RenderComp>
  </div>
</template>
<script>
  import {
    ref,
    h
  } from "vue";
  export default {
    components: {
      RenderComp: {
        props: {
          modelValue: {
            type: String.default: ' '}},setup(props,{attrs,slots,emit}) {
          $scopedSlots was used to get the corresponding slot
          console.log(slots.default()); // Get the default slot
          console.log(slots.content()); // Get the slot with the name content
          function changeTitle(newV) {
            emit('update:modelValue'.'Hahaha');
          }
          return () = > h("div", {}, [h("div", {
            onClick:changeTitle,
          },[
            'Render function API:${props.modelValue}`, slots.default(), slots.content() ])]); }}},setup(props) {
      const title = ref("Two-way data binding");
      return{ title }; }};</script>

Copy the code

Also, we demonstrate that the $scopedSlotsproperty has been removed and all slots are exposed as a function of $slots

Create functional components using normal functions

  • In 3.x, the performance gain for functional component 2.x is negligible, so we recommend using only stateful components
  • Functional components can only use receiveprops å’Œ contextNormal function creation (that is:slots.attrs.emit).
  • Major changes:functionalAttribute in single file Component (SFC)<template> Have been removed
  • Major changes:{ functional: true }The option to create a component by function has beenHas been removed

In VUe2.0, functional components serve two main purposes:

  • Performance optimization improves because they initialize faster than stateful components
  • Multiple root nodes can be returned

However, in Vue 3, the performance of stateful components has improved to a negligible level. In addition, stateful components now include the ability to return multiple root nodes.

Thus, the only use cases left for functional components are simple components, such as those that create dynamic titles. Otherwise, it is recommended that you use stateful components as usual.

Bottom line: Except for special cases, the website still recommends using stateful components

Functional.vue

import { h } from 'vue'

const DynamicHeading = (props, context) = > {
  return h(`h${props.level}`, context.attrs, context.slots)
}

DynamicHeading.props = ['level']

export default DynamicHeading
Copy the code
<Functional level='3'>Dynamic title</Functional>
Copy the code

You can pass in different levels to customize different H series titles.

Changes to asynchronous components

  • newdefineAsyncComponentHelper method, which displays the definition of asynchronous components
  • componnetI’ll call itloader
  • The loader function is not accepted by itselfresolveandrejectParameter, must return a Promise

2.x


Previously, asynchronous components were created by defining the component as a function that returns a promise, for example:

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

For higher-level component syntax with options:

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

3.x


In VUE3, since functional components are defined as pure functions, components need to be explicitly defined by wrapping asynchronous component definitions in the new defineAsyncComponent helper

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

// Asynchronous components with no options
const asyncPage = defineAsyncComponent(() = > import('./NextPage.vue'))

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

Custom instruction

The API has been renamed to better align with the component lifecycle

  • The bind – beforeMount
  • He inserted – mounted
  • BeforeUpdate: new!!! This is called before the element itself is updated, much like a component lifecycle hook
  • Update → Remove! There are too many similarities to update, so this is redundant, please use it insteadupdated
  • ComponentUpdated – updated
  • **beforeUnmount ** The newSimilar to a component lifecycle hook, it is called before an element is unloaded.
  • unbind -> unmounted

Here’s an example:

main.js

const app = createApp(App);
// Create a custom directive
app.directive('highlight', {Directives also have a set of lifecycle hooks
  // 1. Called before the parent component of the bound element is mounted
  beforeMount(el,binding,vnode){ el.style.background = binding.value; }})Copy the code

App.vue

<p v-highlight="'red'">Custom instruction</p>
Copy the code

Animation Transion changes

  • v-enter->v-enter-from
  • v-leave->v-leave-from

Vue2. X version

Remove the API

  • keyCodeSupport asv-onThe modifier

  • o n . On,
    Off and $once instance methods
  • filter

2.x, which supports keyCodes 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

vue3.x

It is recommended to use the kebab-cased (dash) case name for any key to be used as a modifier.

<! -- Vue 3 uses 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.

The $ON, $OFF, and $once instance methods have been removed, and the application instance no longer implements the event-triggering interface.

Filters have been removed from Vue 3.0 and are no longer supported. Instead, we recommend replacing them with method calls or computed properties.