New features of vue3 [difference between vue2 and vue3]

Introduction to vue3

Vue3: Brief | Vue.js

Vite: Start {#getting-started} | Vite Chinese Website

Vue-cli: Introduction | Vue CLI

Vscode:Visual Studio Code - Code Editing. Redefined

2. Introduction to other languages

The three major language frameworks parallel to vue on the market are

  • React: It also has a certain degree of advocacy. Its advocacy is mainly the concept of functional programming. For example, you need to know what is a side effect, what is a pure function, and how to isolate side effects. Its invasiveness does not seem to be as strong as Angular, mainly because it is soft intrusive.

  • Angular: Both versions are strongly advocated, if you use it, you must accept the following:

    - must use its module mechanism

    - must use its dependency injection

    - the component must be defined using its special form (this is true for every view framework, it is hard to avoid)

    So Angular is quite exclusive. If your application is not starting from scratch, but you have to constantly consider whether to integrate with other things, these propositions will cause some troubles.

  • Vue: Progressive framework, the proposition is to only be responsible for its own affairs, Vue is designed to be applied layer by layer from bottom to top. Vue's core library only focuses on the view layer, which is not only easy to use, but also easy to integrate with third-party libraries or existing projects. Different concepts can be used at different levels

3. Introduction to vue3

3.1 Understand vue's mvvm architecture

MVVM is the abbreviation of Model-View-ViewModel, which is a very popular architectural pattern at present. The following is a more official description of vue's mvvm relationship diagram.

3.2. Introduction to Vue3

3.3. What Vue3 brings

1. Performance improvement

  • 41% reduction in bundle size

  • 55% faster initial render, 133% faster update render

  • 54% less memory

    ......

2. Source code upgrade

  • Use Proxy instead of defineProperty to achieve responsiveness

  • Rewrite the implementation of virtual DOM and Tree-Shaking

    ......

3. Embrace TypeScript

  • Vue3 can better support TypeScript

4. New Features

  1. Composition API (composition API)

    • setup configuration

    • ref and reactive

    • watch与watchEffect

    • provide and inject

    • ......

  2. new built-ins

    • Fragment

    • Teleport

    • Suspense

  3. other changes

    • new lifecycle hook

    • The data option should always be declared as a function

    • Remove keyCode support as v-on modifier

    • ......

4. Create a Vue3.0 project

1. Use vue-cli to create

Official Documentation: Creating a Project | Vue CLI

## Check @vue/cli version, make sure @vue/cli version is above 4.5.0
vue --version
## Install or upgrade your @vue/cli
npm install -g @vue/cli
## create
view create view_test
## start up
cd view_test
npm run serve

2. Use vite to create

Official Documentation: Quick Start | Vue.js

Vite official website: Vite Chinese website

  • What is vite? — A new generation of front-end build tools.

  • The advantages are as follows:

    • Lightweight and fast Hot Reload (HMR).

    • True on-demand compilation, no longer waiting for the entire application to be compiled.

## Create project
npm init vite-app <project-name>
## Enter the project directory
cd <project-name>
## Install dependencies
npm install
## run
npm run dev

Five, commonly used Composition API (combined API)

Official Documentation: Composition API FAQ | Vue.js

1. Kick off the setup

  1. Understanding: A new configuration item in Vue3.0, the value is a function.

  2. setup is all Composition API (composition API) "performance stage" .

  3. The components used in the components: data, methods, etc., must be configured in the setup.

  4. Two return values ​​of the setup function:

    1. If an object is returned, the properties and methods in the object can be used directly in the template. (Focus!)

    2. If it returns a rendering function: you can customize the rendering content. (Understanding), the requirement is that the rendering function of h returns to

  5. important point:

    1. Try not to mix with Vue2.x configuration

      • Properties and methods in setup can be accessed in Vue2.x configuration (data, methos, computed...) .

      • But Vue2.x configuration (data, methos, computed...) cannot be accessed in setup , without this

      • If there are duplicate names, setup takes precedence.

    2. setup cannot be an async function, because the return value is no longer the return object, but a promise, and the template cannot see the properties in the return object. (You can also return a Promise instance later, but it requires the cooperation of Suspense and asynchronous components)

  <template`
  <!--The component template structure of vue3 can have no root tag -->
  <h1>I am an app component</h1>
  <h1>my name is {
  
  { name }}, {
  
  { age }}岁</h1>
  <button @click="sayHello">hello!!</button>
  <h3>msg: {
  
  { vue2 }}</h3>
  <p>What about data conflicts? {
  
  { a }}</p>
  <button @click="test1">Test to read the configuration of vue3 in vue2</button>
  <button @click="test2">Test to read the configuration of vue2 in the setup of vue3</button>
</template>
<script>
// import { h } from 'vue';
export default {
  name: 'App',
  //here is just to test the setup, don't consider the issue of responsiveness for the time being
  //Test the content using vue2
  data(){
    return {
      vue2: 'still can use vue2 in vue3 code',
      a:1
    }
  },
  methods:{
    //The way of vue2 configuration method
    test1(){
      console.log(this.vue2);
      console.log(this.name);
      console.log(this.sayHello);
      this.sayHello();
    }
  },
  setup(){
    //Stage for performance
    // Prepare data data
    let name = 'py';
    let age = 21;
    let a = 300;
    //method methods
    function sayHello(){
      alert(`My name is ${name}, ${age} ${age === 1  ? 'year' : 'years'} old`);
    }
    //Read the properties of vue2 in the configuration of vue3
    function test2(){
      console.log(name);
      console.log(age);
      console.log(sayHello);
      console.log(this.vue2);
      console.log(this.test1);
    }
    // return an object
    return {
      name,
      age,
      say Hello,
      test2,
      a
    }
    // return a render function
    //This is to directly replace what you render here into the template
    // return () => h('h1', 'hello');
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

2.ref function

<input ref="xxxx"></input>

  • Role: Define a responsive data

  • grammar:const xxx = ref(initValue)

    • Create a reference object (reference object, ref object for short) that contains responsive data .

    • Data manipulation in JS:xxx.value

    • Read data in the template: No need for .value, directly:<div>{ {xxx}}</div>

  • Remark:

    • The received data can be: basic type or object type.

    • Basic types of data: Reactive is still dependable Object.defineProperty()and getcomplete set.

    • Object type data: internally "rescues" a new function in Vue3.0 - reactivefunction. The principle is the new way of es6, proxy

  • Annotation comprehension:

    • The data wrapped by ref is finally an object, which is refimpl. Separately, it is reference (reference), implement (implementation), abbreviation: the object of the implementation referenced by the reference object (RefImpl)

  • Points to note: When vue3 renders, it detects that you are wrapped with ref, and automatically parses out the value

    <template>
      <!--The component template structure of vue3 can have no root tag -->
      <h1>I am an app component</h1>
      <h1>my name is {
        
        { name }}, {
        
        { age }}岁</h1>
      <h3>Position:{
        
        { job.type }}</h3>
      <h3>Salary:{
        
        { job.salary }}</h3>
      <button @click="changeInfo">Modify the person's information</button>
    </template>
    <script>
    import { ref } from 'vue';
    export default {
      name: 'App',
      setup(){
        //Stage for performance (setup)
        // Prepare data data
        //ref implements responsive (basic type) getter and setter implemented by Object.definedProperty()
        let name = ref('py'); //ref refers to the object
        let age = ref(21);
        //ref implements responsiveness (object type) also uses Proxy to implement
        let job = ref({
          type: 'frontend developer',
          salary: '30'
        });
        function changeInfo(){
          name.value = 'Li Si';
          age.value = 42;
          job.value.type = 'UI developer';
          console.log(name, age); //not responsive
        }
        // return an object
        return {
          name,
          age,
          job,
          changeInfo
        }
      }
    }
    </script>
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>

3.reactive function (reactive responsive)

  • Function: Define an object type of responsive data (do not use it for basic types, but use reffunctions)

  • Syntax: const 代理对象= reactive(源对象)Receive an object (or array) and return a proxy object (the instance object of Proxy, referred to as proxy object)

  • The reactive data defined by reactive is "deep".

  • The internal ES6-based Proxy implementation operates on the internal data of the source object through the proxy object.

<template>
  <!--The component template structure of vue3 can have no root tag -->
  <h1>I am an app component</h1>
  <h1>my name is {
  
  { person.name }}, {
   
  { person.age }}years old</h1>
  <h3>Position:{
  
  { person.type }}</h3>
  <h3>Salary:{
  
  { person.salary }}</h3>
  <h3>Hobbies:{
  
  { person.hobbies }}</h3>
  <h4> test data c:{
  
  { person.a.b.c }}</h4>
  <button @click="changeInfo">Modify the person's information</button>
</template>
<script>
import { reactive } from 'vue';
export default {
  name: 'App',
  setup(){
    //Stage for performance (setup)
    // Prepare data data
    //ref implements responsive (basic type) getter and setter implemented by Object.definedProperty()
    // let name = ref('py'); //ref refers to the object (RefImpl) instance
    // let age = ref(21);
    //ref implements responsiveness (object type) and also uses Proxy to implement (proxy) Here, even if ref is used, it also uses reactive
    let person = reactive({
      name: 'py',
      age: 21,
      type: 'frontend developer',
      salary: '30',
      hobbies: ['smoking', 'drinking', 'hot head'],
      a:{
        b:{
          c: 666
        }
      }
    });
    function changeInfo(){
      person.name = 'Li Si';
      person.age = 42;
      // job.value.type = 'xxx'
      person.type = 'UI developer';
      //Test whether reactive can monitor deep changes
      person.a.b.c = 100;
      person.hobbies[0] = 'play tennis';
      // console.log(name, age); //not responsive
    }
    // return an object
    return {
      person,
      changeInfo
    }
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

4. Responsive principle in Vue3.0

Responsiveness of vue2.x

  • Implementation principle:

    • Object type: Object.defineProperty()Intercept (data hijacking) by reading and modifying properties.

    • Array type: interception is achieved by overriding a series of methods for updating the array. (The change method of the array is wrapped).

      Object.defineProperty(data, 'count', {
          get () {}, 
          set () {}
      })
      Object.defineProperty(data, 'name', {
          get () {},
          set () {}
      })
  • There is a problem:

    • When adding or deleting attributes, the interface will not be updated.

    • Modify the array directly through the subscript, and the interface will not be automatically updated.

 <template>
  <div id="app">
    <h1>Name: {
  
  {this.persion.name}}</h1>
    <h1>gender: {
  
  {this.persion.sex}}</h1>
    <h1 v-show="this.persion.age">age: {
  
  {this.persion.age}}</h1>
    <h1>{
  
  {this.persion.hobby}}</h1>
    <button @click="changeAge">Add age</button>
    <button @click="deleobject">Delete age</button>
    <h1></h1>
    <!-- <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </nav>
    <router-view/> -->
  </div>
</template>
<script>
  export default {
    data() {
      return {
        version: {
          name: 'Zhang San',
          sex: "male",
          hobby:['learning','eating']
        },
      }
    },
    methods:{
        changeAge() {
          // console.log( this.persion.age);
          // this.persion.age =12
          // console.log( this.persion.age);
          this.$set(this.persion,'age', 14)
        },
        deleobject() {
          delete this.persion.name
          Vue.delete(this.persion, 'name', '女')
        },
        upDatehobby() {
          this.persion.hobby[0] = "Hobby",
          this.$set(this.persion.hobby, 0, 'shopping')
          this.persion.hobby.splice(0,1,'shopping')
        }
    }
  }
</script>
<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
nav {
  padding: 30px;
  a {
    font-weight: bold;
    color: #2c3e50;
    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>

Add watch writing and monitoring

<template>
  <div id="app">
    <!-- <nav>
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </nav>
    <router-view/> -->
    <h1 v-show="persion.name">Name: {
  
  { persion.name }}</h1>
    <h1 v-if="persion.sex">Sex: {
  
  { persion.sex }}</h1>
    <h1 v-show="persion.age">Age: {
  
  { persion.age }}</h1>
    <h1>Hobbies: {
  
  { persion.hobby }}</h1>
    <button @click="updateObj">Modify name and hobby first</button>
    <button @click="addJobinfo">Add age</button>
    <button @click="deleteJobInfo">Delete name</button>
  </div>
</template>
<script>
import Vue from "vue";
export default {
  data() {
    return {
      version: {
        name: "Zhang San",
        sex: "male",
        hobby: ["smoking", "drinking", "hot head"],
      },
    };
  },
  watch: {
    // By default, our listener will only change the monitored data itself (internal changes cannot be listened to)
    // info(newInfo, oldInfo) {
    //   console.log("newValue:", newInfo, "oldValue:", oldInfo);
    // }
    // Deep listening/immediate execution (must be executed once)
    version: {
      handler: function (newInfo, oldInfo) {
        console.log(
          "newValue:",
          newInfo,
          "oldValue:",
          oldInfo
        );
      },
      deep: true,
      // Deep listening (you can listen to changes in the internal data of the current listening object)
       immediate: true
      // Execute immediately (if immediate execution is enabled, it will be executed once when the page first loads)
    },
    "persion.name": function (newInfo, oldInfo) {
      console.log(newInfo, oldInfo, 'I am listening for name changes');
      //We can also monitor a certain property in the object
    },
  },
  methods: {
    /**
     * I want to change the position and annual salary
     */
    updateObj() {
      this.persion.name = "Pop Doudou";
      this.persion.hobby[1] = "I love playing Hobby";
    },
    /**Add age*/
    addJobinfo() {
      //this.persion.age = 30
      this.$set(this.persion, "age", 20);
    },
    /** delete name */
    deleteJobInfo() {
      //delete this.persion.name
      this.$delete(this.persion, "name");
    },
  },
};
</script>
<style lang="scss">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
nav {
  padding: 30px;
  a {
    font-weight: bold;
    color: #2c3e50;
    &.router-link-exact-active {
      color: #42b983;
    }
  }
}
</style>

Responsiveness of Vue3.0

  • Realization principle:

    • Through Proxy (proxy): Intercept the change of any attribute in the object, including: reading and writing attribute values, adding attributes, deleting attributes, etc.

    • Through Reflect (reflection): operate on the properties of the source object.

    • Proxy and Reflect described in the MDN document:

      • Proxy:Proxy - JavaScript | MDN

      • Reflect:Reflect - JavaScript | MDN

        new Proxy(data, {
            // Intercept reading attribute values
            get (target, prop) {
                return Reflect.get(target, prop)
            },
            // Intercept setting attribute values ​​or adding new attributes
            set (target, prop, value) {
                return Reflect.set(target, prop, value)
            },
            // Intercept delete attribute
            deleteProperty (target, prop) {
                return Reflect.deleteProperty(target, prop)
            }
        })
        
        proxy.name = 'tom'   
        
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>v3 responsive</title>
</head>
<body>
    <script type="text/javascript">
        let person = {
            name: 'Zhang San',
            age: 18
        };

        //Simulate the responsiveness in vue2
        // #region
        // let p = {};
        // Object.defineProperty(p, 'name', {
        //     get(){
        //         //get name
        //         return person.name;
        //     },
        //     set(value){
        //         //set name
        //         console.log('name changed, must change the page');
        //         person.name = value;
        //     }
        // })
        //
        // Object.defineProperty(p, 'age', {
        //     configurable: true,
        //     get(){
        //         //get age
        //         return person.age;
        //     },
        //     set(value){
        //         //set age
        //         console.log('age changed, must change the page');
        //         person.age = value;
        //     }
        // })
        // #endregion

        //Responsive style of vue3
        const p = new Proxy(person,{
            // read
            get(target, propName){
                //person ==> target
                console.log('read');
                return Reflect.get(target,propName);
            },
            set(target, propName, value) {
                // Both modification and addition of properties are called
                console.log('Modify');
                Reflect.set(target, propName, value);
            },
            //delete
            deleteProperty(target, propName) {
                console.log(`Delete`);
                return Reflect.deleteProperty(target, propName);
            }
        });

        // let obj = {
        //     a:1,
        //     b:2
        // }
        //
        // const x1 = Reflect.defineProperty(obj, 'c',{
        //     get(){
        //         return 3;
        //     }
        // });
        // console.log(x1); //true into
        // const x2 = Reflect.defineProperty(obj, 'c',{
        //     get(){
        //         return 4;
        //     }
        // });
        // if(x2){
        // console.log(x2); //false no
        // }
        // Reflect.get(obj,'a');
    </script>
</body>
</html>

5. reactive vs. ref

  • From the perspective of defining data:

    • ref is used to define: basic type data .

    • reactive is used to define: object (or array) type data .

    • Remarks: ref can also be used to define object (or array) type data , which will be automatically converted to reactivea proxy object internally .

  • From the perspective of principle comparison:

    • ref implements responsiveness (data hijacking) Object.defineProperty()through getAND .set

    • reactive implements responsiveness (data hijacking) by using Proxy , and manipulates the data inside the source object through Reflect .

  • From a usage point of view:

    • Data defined by ref: required for.value data manipulation , but not required.value for direct reading in the template when reading data .

    • The data defined by reactive: operation data and read data: neither is required.value .

6. Two points of attention for setup

  • The timing of setup execution

    • Executed once before beforeCreate, this is undefined.

  • parameter of setup

    • props: The value is an object, including: the properties passed from outside the component and received by the internal declaration of the component.

    • context: context object

      • attrs: The value is an object, including: attributes passed from outside the component but not declared in the props configuration, equivalent to this.$attrs.

      • slots: Received slot content, equivalent to this.$slots.

      • emit: A function that dispatches custom events, equivalent to this.$emit.

7. Computed properties and monitoring

1.computed function

  • Consistent with the computed configuration function in Vue2.x

  • wording

    import {computed} from 'vue'
    
    setup(){
        ...
    	//Computed property - shorthand
        let fullName = computed(()=>{
            return person.firstName + '-' + person.lastName
        })
        // computed property - complete
        let fullName = computed({
            get(){
                return person.firstName + '-' + person.lastName
            },
            set(value){
                const nameArr = value.split('-')
                person.firstName = nameArr[0]
                person.lastName = nameArr[1]
            }
        })
    }
    

2. watch function

  • Consistent with the watch configuration function in Vue2.x

  • Two small "pits":

    • When monitoring the responsive data defined by reactive: oldValue cannot be obtained correctly, and deep monitoring is forcibly enabled (the deep configuration is invalid).

    • When monitoring an attribute in the reactive data defined by reactive: the deep configuration is valid.

    //Case 1: Monitor the responsive data defined by ref
    watch(sum,(newValue,oldValue)=>{
    	console.log('sum changed', newValue, oldValue)
    },{immediate:true})
    
    //Case 2: Monitor the responsive data defined by multiple refs
    watch([sum,msg],(newValue,oldValue)=>{
    	console.log('sum or msg has changed', newValue, oldValue)
    }) 
    
    /* Case 3: Monitor the responsive data defined by reactive
    			If the watch monitors the reactive data defined by reactive, the oldValue cannot be obtained correctly! !
    			If the watch monitors the reactive data defined by reactive, the in-depth monitoring is forcibly enabled
    */
    watch(person,(newValue,oldValue)=>{
    	console.log('person changed', newValue, oldValue)
    },{immediate:true,deep:false}) //The deep configuration here no longer works
    
    //Case 4: Monitor an attribute in the responsive data defined by reactive
    watch(()=>person.job,(newValue,oldValue)=>{
    	console.log('person's job has changed', newValue, oldValue)
    },{immediate:true,deep:true}) 
    
    //Situation 5: Monitor some attributes in the responsive data defined by reactive
    watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
    	console.log('person's job has changed', newValue, oldValue)
    },{immediate:true,deep:true})
    
    //Special case
    watch(()=>person.job,(newValue,oldValue)=>{
        console.log('person's job has changed', newValue, oldValue)
    },{deep:true}) //The deep configuration is valid here because it monitors an attribute in the object defined by the reactive element
    

3. watchEffect function

  • The routine of watch is: specify not only the attribute of monitoring, but also the callback of monitoring.

  • The routine of watchEffect is: no need to specify which attribute to monitor, which attribute is used in the monitoring callback, then which attribute to monitor.

  • watchEffect is a bit like computed:

    • But computed pays attention to the calculated value (the return value of the callback function), so the return value must be written.

    • And watchEffect pays more attention to the process (the function body of the callback function), so there is no need to write the return value.

    //As long as the data used in the callback specified by watchEffect changes, the callback will be re-executed directly.
    watchEffect(()=>{
        const x1 = sum.value
        const x2 = person.age
        console.log('The callback configured by watchEffect is executed')
    })
    

8. Life cycle

The life cycle of vue3.0

  • The lifecycle hooks in Vue2.x can continue to be used in Vue3.0, but two of them have been renamed:

    • beforeDestroyrename tobeforeUnmount

    • destroyedrename tounmounted

  • Vue3.0 also provides lifecycle hooks in the form of Composition API, and the corresponding relationship with the hooks in Vue2.x is as follows:

    • beforeCreate===>setup()

    • created=======>setup()

    • beforeMount ===>onBeforeMount

    • mounted=======>onMounted

    • beforeUpdate===>onBeforeUpdate

    • updated =======>onUpdated

    • beforeUnmount ==>onBeforeUnmount

    • unmounted =====>onUnmounted

  • Summarize:

    • The combined life cycle is a little faster than the configuration item

    <template>
      <div>
          <h1>{
        
        {counnt}}</h1>
          <button @click="counnt++">求和</button>
      </div>
    </template>
    <script lang="ts">
    import {ref,onBeforeMount, onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'
    export default {
      name: "DemoWatch",
      setup() {
        let counnt = ref(1)
    
    
        onBeforeMount(() => {
          console.log('onBeforeMount');
        })
    
        onMounted(() => {
           console.log('onMounted');
        })
    
        onBeforeUpdate(() => {
           console.log('onBeforeUpdate');
        })
    
        onUpdated(() => {
           console.log('onUpdated');
        })
    
        onBeforeUnmount(() => {
           console.log('onBeforeUnmount');
        })
    
        onUnmounted(() => {
           console.log('onUnmounted');
        })
    
        return {
          known
        }
      },
    
    //  beforeCreate() {
      //#region 
    //     console.log('beforeCreate');
    //  },
    //  created() {
    //       console.log('created');
    //  },
    //  beforeUpdate () {
    //     console.log('beforeUpdate');
    //  },
    //  updated() {
    //    console.log('updated');
    //  },
    //  beforeMount() {
    //     console.log('beforeMount');
    //  },
    //  mounted() {
    //     console.log('mounted');
    //  },
    //  beforeUnmount() {
    //    console.log('beforeUnmount');
    //  },
    //  unmounted() {
    //     console.log('unmounted');
        //#endregion
    //  },
    };
    
    
    </script>
    <style></style>
    
    

9. Custom hook function

  • What are hooks? —— It is essentially a function that encapsulates the Composition API used in the setup function.

  • Similar to mixin in vue2.x.

  • Advantages of custom hooks: code reuse, making the logic in setup clearer and easier to understand.

call hooks

<template>
   <h2>I am a test component</h2>
   <h3>{
  
  { point }}</h3>
</template>

<script>
import usePoint from "../hooks/usePoint";

export default {
  name: "Test",
  setup(){
    const point = usePoint(); //Reuse hooks (encapsulate data and life cycle hooks to be used) The benefits of combined API
    return {
      point
    }
  }
}
</script>

<style scoped>

</style>

Encapsulated hooks

import {reactive, onMounted, onBeforeUnmount} from 'vue'


export default function usePointer() {
    let point =reactive({
        x: 0,
        y: 0,
    })

    const savePoint = (event) => {
        point.x = event.pageX
        point.y = event.pageY
    }

    onMounted(() => {
        window.addEventListener('click', savePoint)
    })

    onBeforeUnmount(() => {
        widnwo.removeEventLister('click', savePoint)
    })

    return point
}

10.toRef

  • Function: Create a ref object whose value points to an attribute in another object.

  • grammar:const name = toRef(person,'name')

  • Application: When you want to provide a property in the responsive object for external use alone.

  • Extension: Same toRefsas toRefthe function, but multiple ref objects can be created in batches, syntax:toRefs(person)

<template>
  <div>
    <h1>Name: {
  
  { name }}</h1>
    <h1>Age: {
  
  { age }}</h1>
    <h1>School: {
  
  { schoolClass }}</h1>
    <h1>Salary: {
  
  { salary }}K</h1>
    <button @click="schoolClass += '!'">Modify school</button>
    <button @click="age ++">Modify age</button>
  </div>
</template>
<script lang="ts">
import { ref, reactive, toRef, toRefs } from "vue";
export default {
  name: "DemoWatch",
  setup() {
    let sum = ref(0);
    let persion = reactive({
      name: "Little Red",
      age: 19,
      job: {
        type: "Front-end development engineer",
        salary: 30,
      },
    });
    let schoolClass = ref("I am in Beijing");


    return {
      ...toRefs(persion),
       salary:toRef(persion.job,'salary'),
      // name: toRef(persion, 'name'),
      schoolClass,
      sum,
    };
  },
};
</script>
<style></style>

6. Other Composition APIs

1.shallowReactive 与 shallowRef

  • shallowReactive: only handles the response (shallow response) of the outermost properties of the object.

  • shallowRef: only handles the response of basic data types, not the response of objects.

  • When to use it?

    • If there is an object data, the structure is relatively deep, but only the outer attribute changes ===> shallowReactive.

    • If there is an object data, the subsequent function will not modify the properties in the object, but generate a new object to replace ===> shallowRef.

<template>
  <h2>The current y is: {
  
  { x.y }}</h2>
  <button @click="x = {y : 888}">Click me to replace x</button>
  <button @click="x.y++">点我y+1</button>
  <hr/>
  <h4>{
  
  { person }}</h4>
  <h2>Name:{
  
  { name }}</h2>
  <h2>age:{
  
  { age }}</h2>
  <h2>Salary:{
  
  { job.j1.salary }}K</h2>
  <button @click="name = name + '~'">Modify name</button>
  <button @click="age++">Increasing age</button>
  <button @click="job.j1.salary++">Increase salary</button>
</template>

<script>
import {ref,reactive, toRefs, shallowReactive, shallowRef} from 'vue';
export default {
  name: 'Demo',
  setup(){
    //shallowReactive only considers the first layer of data responsiveness of the object type
    // let person = shallowReactive({
    // name: 'Zhang San',
    //   age: 18,
    //   job:{
    // j1:{
    //       salary: 20
    //     }
    //   }
    // });

    let person = reactive({
      name: 'Zhang San',
      age: 18,
      job:{
        j1:{
          salary: 20
        }
      }
    });

    // let x = ref(0);

    //In terms of passing basic types, there is basically no difference between ref and shallowRef
    // let x = shallowRef(0);
    //But note that the object type shallowRef is not processed, and the bottom layer of ref goes back to use reactive to generate proxy objects (getter/setter)
    //But note that whether it is shallowR or non-shallow, the first layer is responsive (not as good as x below is still responsive data)
    let x = shallowRef({ y: 0 });

    console.log(x);

    // let x = ref({ y: 0 })

    return {
      person,
      ...toRefs(person),
      x,
    };

  }
}
</script>

<style>
</style>


2.readonly 与 shallowReadonly

  • readonly: Make a reactive data read-only (deep read-only).

  • shallowReadonly: Make a responsive data read-only (shallow read-only).

  • Application scenario: When you do not want data (especially when this data comes from other components) to be modified.

<template>
  <h2>The current sum is: {
  
  { sum }}</h2>
  <button @click="sum++">sum+1</button>
  <hr/>
  <h2>Name:{
  
  { name }}</h2>
  <h2>age:{
  
  { age }}</h2>
  <h2>Salary:{
  
  { job.j1.salary }}K</h2>
  <button @click="name = name + '~'">Modify name</button>
  <button @click="age++">Increasing age</button>
  <button @click="job.j1.salary++">Increase salary</button>
</template>

<script>
import {ref,reactive, toRefs, readonly, shallowReadonly} from 'vue';
export default {
  name: 'Demo',
  setup(){

    let sum = ref(0);

    let person = reactive({
      name: 'Zhang San',
      age: 18,
      job:{
        j1:{
          salary: 20
        }
      }
    });

    // person = readonly(person); //At this time, the attribute values ​​​​in the person are not allowed to be modified
    //person = shallowReadonly(person); //The first layer cannot be changed (name, age), but j1 and salary can still be changed

    // sum = readonly(sum); //same reason
    // sum = shallowReadonly(sum)

    return {
      sum,
      ...toRefs(person),
    };

  }
}
</script>

<style>
</style>


3. toRaw and markRaw

  • toRaw:

    • Function: Convert a responsive objectreactive generated by a bot into a normal object .

    • Usage scenario: It is used to read the common object corresponding to the responsive object. All operations on this common object will not cause page updates.

  • markRaw:

    • Role: Mark an object so that it will never become a responsive object again.

    • Application scenario:

      1. Some values ​​should not be set responsive, such as complex third-party libraries, etc.

      2. Skipping reactive transformations can improve performance when rendering large lists with immutable data sources.

4.customRef

  • Role: Create a custom ref with explicit control over its dependency tracking and update triggering.

  • To achieve the anti-shake effect:

    <template>
    	<input type="text" v-model="keyword">
    	<h3>{
        
        {keyword}}</h3>
    </template>
    
    <script>
    	import {ref,customRef} from 'vue'
    	export default {
    		name:'Demo',
    		setup(){
    			// let keyword = ref('hello') //use built-in ref prepared by Vue
    			// Customize a myRef
    			function myRef(value,delay){
    				let timer
    				//Through customRef to achieve customization
    				return customRef((track,trigger)=>{
    					return{
    						get(){
    							track() //tell Vue that this value needs to be "tracked"
    							return value
    						},
    						set(newValue){
    							clearTimeout(timer)
    							timer = setTimeout(()=>{
    								value = newValue
    								trigger() //tell Vue to update the interface
    							},delay)
    						}
    					}
    				})
    			}
    			let keyword = myRef('hello',500) //Use the ref defined by the programmer
    			return {
    				keyword
    			}
    		}
    	}
    </script>
    

5.provide and inject

  • Role: Realize communication between ancestor and descendant components

  • Routine: the parent component has an provideoption to provide data, and the descendant components have an injectoption to start using this data

  • Specifically written:

    1. In the parent component:

      setup(){
          ......
          let car = reactive({name:'Benz',price:'400,000'})
          provide('car',car)
          ......
      }
      
    2. In descendant components:

      setup(props,context){
          ......
          const car = inject('car')
          return {car}
          ......
      }
      

6. Judgment of responsive data

  • isRef: checks if a value is a ref object

  • isReactive: checks if an object was reactivecreated a reactive proxy

  • isReadonly: checks if an object was readonlycreated a read-only proxy

  • isProxy: Checks if an object reactiveis readonlya proxy created by the or method

7. Advantages of Composition API

1. Problems with the Options API

In the traditional OptionsAPI, if you add or modify a requirement, you need to modify it in data, methods, and computed respectively.

In vue2, the codes of all functions and modules are integrated together. If one place, you have to modify the entire page of code, it will cause unpredictable bugs, generate a lot of extra work, and spend a lot of time reading and consulting the code

2. Advantages of Composition API

We can organize our code and functions more elegantly. Let the code of related functions be organized together in a more orderly manner.

All codes are stored in modules, and each function is placed inside its own function. If you want to modify a function, just modify a function or a component, which saves cost and reduces coupling.

8. New components

1.Fragment

  • In Vue2: Components must have a root tag

  • In Vue3: Components can have no root tags, and multiple tags will be included in a Fragment virtual element internally

  • Benefits: Reduce label levels, reduce memory usage

2.Teleport

  • What is Teleport? -- Teleportis a technique that can move our component html structure to a specified location.

    <teleport to="move location">
    	<div v-if="isShow" class="mask">
    		<div class="dialog">
    			<h3>I am a popup</h3>
    			<button @click="isShow = false">Close the popup</button>
    		</div>
    	</div>
    </teleport>
    

3.Suspense

  • Render some extra content while waiting for asynchronous components, so that the application has a better user experience

  • Steps for usage:

    • Import components asynchronously

      import {defineAsyncComponent} from 'vue'
      const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
      
    • Use Suspensethe wrapper component, and configure it defaultwithfallback

      <template>
          <div class="app">
              <h3>I am an App component</h3>
              <Suspense>
                  <template v-slot:default>
                      <Child/>
                  </template>
                  <template v-slot:fallback>
                      <h3>Loading...</h3>
                  </template>
              </Suspense>
          </div>
      </template>
      

Nine, other

1. Transfer of global API

  • Vue 2.x has many global APIs and configurations.

    • For example: registering global components, registering global directives, etc.

      //register global component
      Vue.component('MyButton', {
        data: () => ({
          count: 0
        }),
        template: '<button @click="count++">Clicked {
            
            { count }} times.</button>'
      })
      
      //register global directive
      Vue.directive('focus', {
        inserted: el => el.focus()
      }
      
  • These APIs have been adjusted in Vue3.0:

    • Adjust the global API, ie: Vue.xxxto the application instance ( app)

      2.X Global API ( VUE) 3.X instance API ( APP)
      Vue.config.xxxx app.config.xxxx
      Vue.config.productionTip remove
      Vue.component app.component
      Directive.view app.directive
      Vue.mixin app.mixin
      Vue.use app.use
      Vue.prototype app.config.globalProperties

2. Other changes

  • The data option should always be declared as a function.

  • Excessive class name changes:

    • Vue2.x writing method

      .v-enter,
      .v-leave-to {
        opacity: 0;
      }
      .v-leave,
      .v-enter-to {
        opacity: 1;
      }
      
    • Vue3.x writing method

      .v-enter-from,
      .v-leave-to {
        opacity: 0;
      }
      
      .v-leave-from,
      .v-enter-to {
        opacity: 1;
      }
      
  • Remove keyCode as a v-on modifier, and no longer supportconfig.keyCodes

  • removev-on.native modifier

    • Bind event in parent component

      <my-component
        v-on:close="handleComponentEvent"
        v-on:click="handleNativeClickEvent"
      />
      
    • Declare custom events in subcomponents

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

    Filters While this seems convenient, it requires a custom syntax that breaks the assumption that expressions inside curly braces are "just JavaScript", which has not only a learning cost, but an implementation cost as well! It is recommended to replace filters with method calls or computed properties.

  • ......

Guess you like

Origin blog.csdn.net/jiangshen_a/article/details/127671213