Start from 0 and take you to the beginning. Vue3 - the most complete in the whole network (1.1w words)

God's destiny is not afraid, and ancestors are not law—— Wang Anshi

preface

This article is not a title party, but a real hard core article. If you want to learn from Vue3, you can browse this article. Generally speaking, this blog covers most of the contents of Vue3, including common composition APIs (composite APIs), other composition APIs and some new features: Fragment, report, suspend, provide and input.

Project construction

Since you are learning Vue3, the first thing you need is how to initialize the project. Here are two ways for your reference

  • Method 1: Vue cli scaffold initializes Vue3 project

Official documents: https://cli.vuejs.org/zh/guid...

//    Check the version of @ vue/cli and ensure that the version of @ vue/cli is above 4.5.0
vue --version
//    Install or upgrade your @ vue/cli
npm install -g @vue/cli
//     establish
vue create vue_test
// start-up
cd vue_test
npm run serve
  • Method 2: vite initializes Vue3 project

vite official website: https://vitejs.cn/

//     Create project
npm init vite-app <project-name>
//    Enter project directory
cd <project-name>
//     Installation dependency
npm install
//    function
npm run dev

Project directory structure analysis

The analysis of the project directory structure here is mainly main JS file

  • Main in Vue2 js

    new Vue({
    el: '#app',
    components: {},
    template: ''
    });
  • Main in Vue3 js

    import { createApp } from 'vue'
    import App from './App.vue'
    createApp(App).mount('#app')

In Vue2, the application instance object is created through the new Vue({}) constructor, while Vue3 no longer introduces the Vue constructor, but introduces a factory function called createApp to create the application instance object.

Vue3 devtool get

devtool:https://chrome.zzzmh.cn/info?...

Composition API

setup

  • Understanding: vue3 A new configuration item in 0 with the value of a function
  • setup is the entry point for all composition APIs
  • The data and methods used in the component should be configured in setup
  • Two return values of setup function

    • If an object is returned, the properties and methods in the object can be used directly in the template
    • If you return a rendering function, you can customize the rendering content
  • Execution timing of setup

    • Execute once before beforeCreate, and this is undefined
  • Parameters of setup

    props: the value is an object, including the attributes passed from outside the component and declared and received inside 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, which is equivalent to this$ attrs
    • Slots: received slot contents, equivalent to this$ slots
    • Emit: a function that distributes custom events, equivalent to this$ emit

matters needing attention:

  • Try not to use with Vue2x configuration

    • Vue2x configurations (data, methods, computed) can access properties and methods in setup
    • Vue2x configuration (data, methods, computed) cannot be accessed in setup
    • If the attribute in data has the same name as the attribute in setup, setup takes precedence
  • setup cannot be an async function, because the return value is no longer the return object, but Promise. The template cannot see the properties in the return object, but it can also return a Promise instance later, which requires the cooperation of suspend and asynchronous components

Example 1: two return values of the setup function

<template>
    <h2>practice setup Related content</h2>
    <!--<h2>setup Returns an object and uses the properties and methods in the object</h2>-->
    <!--<p>full name:{{student.name}}</p>-->
    <!--<p>Age:{{student.age}}</p>-->
    <!--<button @click="hello">Click to view console information</button>-->
    <hr>
    <h2>setup Returns a function</h2>
</template>

<script>
    import {h} from 'vue'
    export default {
        name: "setupComponent",
        setup(){
            // attribute
             let student={
                name:'Zhang San',
                age:18,
             }
            // method
        function hello() {
               console.log(`Hello, my name is ${student.name},this year ${student.age}`)
             }
             return{    // Returns an object
                 student,
                 hello,
             }
            // Return() = > H ('h1 ',' hello ') / / returns a function
        }
    }
</script>

<style scoped>

</style>

It should be noted that the attributes and methods defined in setup must be return ed, otherwise they cannot be used

Example 2: the parameters and methods in setup are mixed with configuration items

<template>
    <h2>setup Mixed with configuration items</h2>
    <h2>full name:{{name}}</h2>
    <h2>Age:{{age}}</h2>
    <h2>Gender:{{sex}}</h2>
    <button @click="sayHello">sayHello(Vue3 (method inside)</button>
    <button @click="sayWelcome">sayWelcome(Vue2 (method inside)</button>
</template>

<script>
    export default {
        name: "setup01_component",
        data(){
          return{
            sex:'male',
            sum:0,
          }
        },
        methods:{
            sayWelcome(){
                console.log(`sayWelcome`)
            },
        },
        setup(){
            let sum=100;
            let name='Zhang San';
            let age=18;
            function sayHello() {
                console.log(`My name is ${name},this year ${age}`)
            }
            return{
                name,
                age,
                sayHello,
                test02,
                sum
            }
        }
    }
</script>

<style scoped>

</style>

This code first implements the properties and methods in setup and the properties and methods in the configuration items in Vue2. Next, add the corresponding blending method

<template>
    <h2>setup Mixed with configuration items</h2>
    <h2>full name:{{name}}</h2>
    <h2>Age:{{age}}</h2>
    <h2>Gender:{{sex}}</h2>
    <button @click="sayHello">sayHello(Vue3 (method inside)</button>
    <button @click="sayWelcome">sayWelcome(Vue2 (method inside)</button>
    <br>
    <br>
    <button @click="test01">test Vue2 Inside call Vue3 Properties and methods inside</button>
    <br>
    <br>
    <button @click="test02">test Vue3setup Inside call Vue2 Properties and methods inside</button>
    <br>
    <h2>sum The values are:{{sum}}</h2>
</template>

<script>
    export default {
        name: "setup01_component",
        data(){
          return{
            sex:'male',
            sum:0,
          }
        },
        methods:{
            sayWelcome(){
                console.log(`sayWelcome`)
            },
            test01(){
                console.log(this.sex);  // Properties in Vue2 (properties in data)
                // Properties in setup
                console.log(this.name);
                console.log(this.age);
                // Methods in setup
                this.sayHello();
            }
        },
        setup(){
            let sum=100;
            let name='Zhang San';
            let age=18;
            function sayHello() {
                console.log(`My name is ${name},this year ${age}`)
            }
            function test02() {
                // Properties in setup
                console.log(name);
                console.log(age);
                
                // Attributes in data
                console.log(this.sex);
                console.log(this.sayWelcome);
            }
            return{
                name,
                age,
                sayHello,
                test02,
                sum
            }
        }
    }
</script>

<style scoped>

</style>

Test01 and test02 methods are added here. Click them respectively, and the console can see that when you click the test01 method in the configuration item, in addition to the value of its own sex attribute, the attributes defined in setup also have values and methods can be called. When you click the test02 method defined in setup, the console can only output the attributes and methods defined in setup, The attribute and method values defined in the configuration item are undefined.

  • The properties and methods defined in setup can be used in configuration items (methods, computed, watch, etc.), while the properties and methods defined in configuration items cannot be called in setup
  • If the attribute in setup has the same name as the attribute in data, the attribute in setup takes precedence

Example 3: execution timing of setup
setup will be executed once before beforeCreate

<template>
    <h2>setup Implementation mechanism</h2>
</template>

<script>
    export default {
        name: "setup_component03",
        setup(){
            console.log('setup')
        },
        beforeCreate(){
            console.log('beforeCreate')
        }
    }
</script>

<style scoped>

</style>

When viewing the console, the order we see is setup > before create

Use of context and props in setup

Use of props and slot s in Vue2

Before explaining the two parameters in setup, first review the relevant knowledge in Vue2

  • Use of props and custom events
  • attrs
  • Slot

Example 1: use of Vue2props and custom events

Prepare two components, parent Vue components and child Vue component

parent.vue

<template>
    <div class="parent">
      I am the parent component
      <child msg="Transmit information" name="Zhang San" @sendParentMsg="getMsg"/>
    </div>
</template>
<script>
    import Child from "./Child";
    export default {
        name: "Parent",
      components: {Child},
      methods:{
        getMsg(msg){
          console.log(msg)
        }
      }
    }
</script>
<style scoped>
  .parent{
    padding: 10px;
    background-color: red;
  }
</style>

child.vue

<template>
    <div class="child">
      <h2>I am a subcomponent</h2>
      <p>The message passed by the parent component is:{{msg}}</p>
      <p>The message passed by the parent component is:{{name}}</p>
      <button @click="sendMsg">Pass information to parent component</button>
    </div>
</template>
<script>
    export default {
        name: "Child",
        props:{
          msg:{
            type:String,
            default:''
          },
          name:{
            type:String,
            default:''
          }
        },
        mounted(){
          console.log(this);
        },
        methods:{
          sendMsg(){
            this.$emit("sendParentMsg",'Notify parent component updates')
          }
        }
    }
</script>
<style scoped>
  .child{
    padding: 10px;
    background-color: orange;
  }
</style>

The code corresponding to the child component is as follows:

<template>
    <div class="child">
      <h2>I am a subcomponent</h2>
      <!--<p>The message passed by the parent component is:{{msg}}</p>-->
      <!--<p>The message passed by the parent component is:{{name}}</p>-->
      <p>The message passed by the parent component is:{{$attrs.msg}}</p>
      <p>The message passed by the parent component is:{{$attrs.name}}</p>
      <button @click="sendMsg">Pass information to parent component</button>
    </div>
</template>

<script>
    export default {
        name: "Child",
        // props:{
        //   msg:{
        //     type:String,
        //     default:''
        //   },
        //   name:{
        //     type:String,
        //     default:''
        //   }
        // },
        mounted(){
          console.log(this);
        },
        methods:{
          sendMsg(){
            this.$emit("sendParentMsg",'Notify parent component updates')
          }
        }
    }
</script>

<style scoped>
  .child{
    padding: 10px;
    background-color: orange;
  }
</style>


The child component receives the information transmitted by the parent component through props and through this$ The emit () custom event passes information to the parent component. When props is used to receive data, the data in attrs is empty. If props is not used to receive data, there is a value in props.

Example 2: use of slot s in Vue2

Similarly, prepare two components, one index Vue component, and the other is MySlot Vue component

Index.vue

<template>
    <div class="index">
      <h2>I am Index assembly</h2>
      <!--Writing method I-->
      <my-slot>
        <!--Contents in the slot-->
        <h2>Incoming slot parameter</h2>
        <h2>Incoming slot parameter</h2>
        <h2>Incoming slot parameter</h2>
        <h2>Incoming slot parameter</h2>
      </my-slot>
      <!--Writing method 2-->
      <my-slot>
        <template slot="header">
          <h2>I am header assembly</h2>
        </template>
        <template slot="footer">
          <h2>I am footer enclosure</h2>
        </template>
      </my-slot>
    </div>
</template>

<script>
    import MySlot from "./MySlot";
    export default {
        name: "Index",
      components: {MySlot}
    }
</script>

<style scoped>
  .index{
    padding: 10px;
    background: red;
  }
</style>

MySlot.vue

<template>
    <div class="slot">
      <h2>I am MySlot assembly</h2>
      <slot></slot>
      <br>
      <slot name="header"></slot>
      <br>
      <slot name="footer"></slot>
    </div>
</template>

<script>
    export default {
        name: "MySlot",
        mounted(){
          console.log(this);
        }
    }
</script>

<style scoped>
  .slot{
    padding: 10px;
    background: orange;
  }
</style>

ref

  • Function: define a responsive data
  • Syntax: const xxx=ref(initValue)
  • Create a reference object (reference object) containing responsive data;
  • Operation data in JS: XXX value=xxx;
  • Read data from template: not required value, direct: < div > {{XXX}} < / div >

    remarks:

    • The received data can be basic type or object type
    • Basic type of data: the response type still depends on object get and set of defineproperty() are completed
    • Data of object type: Vue3.0 is used internally A new function in 0 - reactive function
      Example

      <template>
      <h1>ref</h1>
      <h2>ref Define basic data types</h2>
      <p>full name:{{name}}</p>
      <p>Age:{{age}}</p>
      <p>Married or not:{{isMarry}}</p>
      <h2>ref Define object type</h2>
      <p>Hobbies:{{hobby}}</p>
      <p>Certificate type:{{user.idCard}}</p>
      <p>Nationality:{{user.nation}}</p>
      <button @click="changeName">Modify information</button>
      </template>
      
      <script>
      import {ref} from 'vue'
      export default {
      name: "refComponent",
      setup(){
          // Use the basic data types number,string,boolean,
          let name=ref('Zhang San');
          let age=ref(18);
          let isMarry=ref(false);
          // Using ref to define an array
          let hobby=ref(['having dinner','sleep','Beat beans']);
          // Using ref to define objects
          let user=ref({
              idCard:'ID',
              nation:['China','U.S.A','britain','Russia']
          })
          function changeName() {
              //  Modify basic data type
              name.value='Li Si';    // ref defined responsive data is required when modifying data value
              age.value=20;
              isMarry.value=true;
              //  Modify object data type
              hobby.value[0]='play a game';
              user.value.idCard='Hong Kong, Macao and Taiwan resident ID card';
              user.value.nation[0]='Norway';
          }
          return{
              name,
              age,
              isMarry,
              changeName,
              user,
              hobby
          }
      }
      }
      </script>
      
      <style scoped>
      
      </style>

      be careful:

  • ref defined responsive data is required when modifying data value
  • ref defines the object data type. Vue3.0 is used internally A new function in 0 - reactive function
  • Not required when using data in a template value

reactive function

  • Function: define the responsive data of an object type (don't use it for basic types, use ref function)
  • Syntax: const Proxy object = reactive (Proxy object) receives an object (or array) and returns a Proxy object (Proxy instance object, Proxy object for short)
  • The responsive data defined by reactive is deep-seated
  • The internal Proxy implementation is based on ES6. Through the operation of the Proxy object, the internal data of the source object is responsive

    <template>
    <h2>reactive Responsive data</h2>
    <p>full name:{{student.name}}</p>
    <p>Age:{{student.age}}</p>
    <p>Hobbies:{{student.hobbies}}</p>
    <button @click="changeStuInfo">Change student information</button>
    </template>
    
    <script>
    import {reactive} from 'vue'
    export default {
        name: "reactiveComponent",
        setup(){
                // data
            let student=reactive({
                name:'Zhang San',
                age:19,
                hobbies:['having dinner','sleep','Beat beans']
            });
            console.log(student)
            // method
            function changeStuInfo() {
                student.name='Li Si';
                student.age=20;
                student.hobbies[0]='do housework'    
            }
            return{
                student,
                changeStuInfo,
            }
        }
    }
    </script>
    
    <style scoped>
    
    </style>

    reactive vs ref

  • Compare from the perspective of defining data

    • ref is used to define basic type data
    • reactive is used to define: object (or array) type data
    • Note: ref can also be used to define the data of object (or array) type. It will be automatically converted into proxy object through reactive
  • Comparison from the perspective of principle

    • ref through object get and set implementation of defineproperty() (responsive) data hijacking
    • reactive implements responsive (data hijacking) by using Proxy, and operates the data inside the source object through Reflect
  • From the perspective of use

    • ref defined data: required for operation data Value, which is not required for direct reading in the template when reading data value
    • reactive defined data: neither operation data nor read data is required value

watch and watchEffect

    //    attr indicates the attribute to be monitored
    //  Scenario 1: monitor the responsive data defined by a single ref
    watch(attr,(newValue,oldValue)=>{
        console.log('attr Changed',newValue,oldValue);
    })

   //  Situation II; Monitor responsive data defined by multiple ref s
    watch([attr1,attr2,....,attrn],(newValue,oldValue)=>{
        console.log('attr1 or attrn Changed',newValue,oldValue);
    })

    // obj indicates the object to listen on
     // Scenario 3: monitor reactive defined responsive data
    //    If the watch monitors reactive defined responsive data, the oldValue cannot be obtained correctly
    //    If the watch monitors reactive defined responsive data, it is forced to turn on the deep monitoring
     watch(obj,(newValue,oldValue)=>{
        console.log('obj Changed',newValue,oldValue)

     },{immediate:true,deep:false}); // The deep configuration is no longer working here

    // Case 4: monitor an attribute in the responsive data defined by reactive
      watch(()=>person.job,(newValue,oldValue)=>{
         console.log('person of job Changed',newValue,oldValue)
      },{immediate:true,deep:true})

     //  Scenario 5: monitor some attributes in the responsive data defined by reactive
    watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
            console.log('person of job Changed',newValue,oldValue)
    })
    // exceptional case
    watch(()=>person.job,(newValue,oldValue)=>{
        console.log('person of job Changed',newValue,oldValue)
    },{deep:false});//  Here, the deep configuration is valid because it monitors a property in the object defined by reactive
  • watch

    • When monitoring reactive defined responsive data: oldValue cannot be obtained correctly and deep monitoring is forced on (deep configuration is invalid)
    • The deep configuration is valid when monitoring an attribute in the reactive defined responsive data
      Example 1: wath listens to the responsive data defined by ref

      <template>
      <h2>watch monitor ref Defined responsive data</h2>
      <h2>full name:{{userName}}</h2>
      <h2>Age:{{age}}</h2>
      <button @click="userName+='!'">Modify name</button>
      <button @click="age++">Modify age</button>
      <hr>
      <h2>full name:{{user.name}}</h2>
      <h2>Age:{{user.age}}</h2>
      <button @click="user.name+='!'">Modify name</button>
      <button @click="user.age++">Modify age</button>
      </template>
      
      <script>
      import {ref,watch} from 'vue';
      export default {
      name: "watch_component01",
      setup(){
         let userName=ref('Zhang San');
         let age=ref(18);
         let user=ref({
             name:'Zhang San',
             age:21,
         })
         // watch listens to single responsive data defined by ref
         watch(userName,(newValue,oldValue)=>{
             console.log(`userName Has changed,The new value is:${newValue},Old value is:${oldValue}`)
         });
         watch(age,(newValue,oldValue)=>{
             console.log(`age Has changed,The new value is:${newValue},Old value is:${oldValue}`);
         });
      
         // If you need to listen to the responsive data defined by multiple ref s, the code is as follows
         /**
          * newValue And oldValue are in the form of an array, where the nth bit of the array represents the nth bit of the listening position
          * For example, in this example, the first bit of the listening property is userName, and so is the first bit corresponding to newValue and oldValue
          * userName. 
          * If there is immediate execution, the initial value is [], not [undefined,undefined]
          */
         watch([userName,age],(newValue,oldValue)=>{
            console.log('userName or age One of them has changed,',newValue,oldValue)
         })
         
         // watch monitors the responsive object data defined by ref
         watch(user.value,(newValue,oldValue)=>{
             console.log('person Has changed',newValue,oldValue)
         })
         watch(user,(newValue,oldValue)=>{
             console.log('person Has changed',newValue,oldValue);
         },{deep:false})
         
         return{
             userName,
             age,
             user
         }
      }
      }
      </script>
      
      <style scoped>
      
      </style>

      Example 2: watch listens to the responsive data defined by reactive

      <template>
      <h1>watch monitor reactive Defined responsive data</h1>
      <p>full name:{{user.name}}</p>
      <p>Age:{{user.age}}</p>
      <p>Salary:{{user.job.salary}}K</p>
      <button @click="user.name+='!'">Change name</button>
      <button @click="user.age++">Change age</button>
      <button @click="user.job.salary++">Change salary</button>
      </template>
      
      <script>
      import {watch,reactive} from 'vue'
      export default {
      name: "watch_component02",
      setup(){
          let user=reactive({
              name:'Zhang San',
              age:18,
              job:{
                 salary:20
              }
          });
          
          // Case 1: listening to the responsive data defined by reactive, the oldValue cannot be obtained correctly
          /**
           * At this time, newValue and oldValue are the latest data
           * By default, the depth monitoring is forced to be turned on. At this time, the depth monitoring is invalid
           */
          watch(user,(newValue,oldValue)=>{
              console.log(newValue,oldValue);
          },{deep:false});
      
          
          //  In case 2, monitor a single attribute of reactive defined responsive data
          // watch(()=>user.name,(newValue,oldValue)=>{
          //     console.log('name changed ', newValue,oldValue);
          // });
          // watch(()=>user.age,(newValue,oldValue)=>{
          //     console.log('age changed ', newValue,oldValue);
          // })
      
          
          // Scenario 3: monitor multiple attributes of reactive defined responsive data
          /**
           * newValue And oldValue are in the form of an array, where the nth bit of the array represents the nth bit of the listening position
           * For example, in this example, the first bit of the listening property is userName, and so is the first bit corresponding to newValue and oldValue
           * userName,
           */
          // Watch ([() = > user. Name, () = > user. Age], (newvalue, oldvalue) = > {/ / method 1
          //     console. Log ('a property in name or age has changed ', newValue,oldValue);
          // })
          // Watch (() = > [user. Name, user. Age], (newvalue, oldvalue) = > {/ / method 2
          //     console. Log ('a property in name or age has changed ', newValue,oldValue)
          // })
      
          //  Scenario 4: monitor a property of the reactive data object defined by reactive, and deep is valid at this time
          /**
           * Note: at this time, it is necessary to distinguish between the reactive defined object and an attribute in the reactive defined object
           * At this time, deep is effective and monitoring is turned off
           */
            // watch(()=>user.job,(newValue,oldValue)=>{
            //     console.log(newValue,oldValue);
            // },{deep:false});
          return{
              user
          }
      }
      }
      </script>
      
      <style scoped>
      
      </style>
  • watchEffect

    • The routine of watch is to specify both the monitored properties and the monitored callbacks
    • The routine of watchEffect is: do not specify the property to be monitored. If the property is used in the monitored callback, monitor the property
    • watchEffect is a bit like computed

      • However, computed focuses on the calculated value (the return value of the callback function), so it is necessary to write the return value
      • watchEffect pays more attention to the process (the function body of the callback function), so there is no need to write the return value
        Example

        <template>
        <h1>watchEffect monitor ref and reactive Defined responsive data</h1>
        <h2>Current summation:{{sum}}</h2>
        <button @click="sum++">Point I add 1</button>
        <hr>
        <h2>Current information:{{msg}}</h2>
        <button @click="msg+='!'">Modify information</button>
        <hr>
        <h2>full name:{{person.name}}</h2>
        <h2>Age:{{person.age}}</h2>
        <h2>salary:{{person.job.j1.salary}}</h2>
        <button @click="person.name+='!'">Modify name</button>
        <button @click="person.age++">Modify age</button>
        <button @click="person.job.j1.salary++">Pay rise</button>
        </template>
        
        <script>
        import {ref,reactive,watchEffect} from 'vue';
        export default {
        name: "watch_effect_component01",
        setup(){
        let sum=ref(0);
        let msg=ref('Hello');
        let person=reactive({
           name:'Zhang San',
           age:18,
           job:{
               j1:{
                   salary:100,
               }
           }
        });
        /**
        * Write the attributes to be monitored in watchEffect, which will be executed once by default
        * If it is a response form for monitoring ref definition, it is required value
        * If you are monitoring reactive defined responsive data, monitor directly
        */
        watchEffect(()=>{
           let x1=sum.value;
           let x2=person.job.j1.salary;
           console.log('watchEffect The specified callback function executed');
        })
        
        return{
           sum,
           msg,
           person
        }
        }
        }
        </script>
        
        <style scoped>
        
        </style>

Vue2 responsive principle vs vue3 responsive principle

In Vue2, the responsive principle is mainly realized through data hijacking, that is, based on object Defineproperty is implemented, while Vue3 is implemented through Proxy and Reflect (for personal understanding at the lowest level, please forgive me).

So let's compare the principle of Vue3's implementation of responsiveness with that of Vue2's implementation of responsiveness?

Vue2 responsive principle

  • Implementation principle

    • Object type: through object Defineproperty() intercepts the reading and modification of properties (data hijacking)
    • Array type: intercept by overriding a series of methods to update the array. (the change method of the array is wrapped)
    Object.defineProperty(data,'count',{
      get(){}
      set(){}
    })
  • Existing problems

    • The interface will not be updated automatically when adding or deleting attributes
    • Modify the array directly through subscript, and the interface will not be updated automatically

    Let's start with a simple example

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Title</title>
    </head>
    <body>
    <div id="app">
      <h1>Student information</h1>
      <h4>full name:{{student.name}}</h4>
      <h4>Age:{{student.age}}</h4>
      <h4 v-if="student.sex">Gender:{{student.sex}}</h4>
      <h4>Hobbies:{{student.hobbies}}</h4>
      <button @click="addSex">New gender</button>
      <button @click="deleteAge">Delete age</button>
      <button @click="updateHobbies">Modify hobbies</button>
    </div>
    <script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
    <script>
      let vm=new Vue({
          el:'#app',
          data(){
              return{
                  student:{
                      name:'Zhang San',
                      age:18,
                      hobbies:['having dinner','sleep','Beat beans']
                  }
              }
          },
          methods:{
              addSex(){   // New gender
                  this.student.sex='male';
                  console.log(this.student);
              },
              deleteAge(){    // Delete age
                  delete this.student.age;
                  console.log(this.student);
              },
              updateHobbies(){   //   Modify hobbies
                  this.student.hobbies[0]='play a game';
                  console.log(this.student);
              }
          }
      })
    </script>
    </body>
    </html>

    Call the methods corresponding to the buttons respectively. The console can see that when adding a gender attribute, the student has the gender attribute, but does not implement the response (the view is not updated). Similarly, the methods corresponding to the other two buttons are the same.

Cause: vue2 0 if you want to implement responsive data, you must first define it in data, and the data added later cannot implement responsive data.
Solution:

  • Add / modify: Vue$ set(target,propName/index,value)

    • {Object | Array} target
    • {string | number} propertyName/index
    • {any} value
  • Delete: Vue$ delete(target,propName/index)

    • {Object | Array} target
    • {string | number} propertyName/index

At this point, we modify the corresponding code as follows

    addSex(){   // New gender
        // this.student.sex='male';
        // vm.$set(this.student,'sex','male');
        this.$set(this.student,'sex',male);
        console.log(this.student);
    },
    deleteAge(){    // Delete age
        // delete this.student.age;
        // this.$delete(this.student,'age');
        vm.$delete(this.student,'age');
        console.log(this.student);
    },  
     updateHobbies(){   //   Modify hobbies
         // this.student.hobbies[0] = 'play games';
         // this.$set(this.student.hobbies,0, 'play games');
         //  vm.$set(this.student.hobbies,0, 'play games');
         /**
                 * Or use array mutation
                 * push()
                 * pop()
                 * shift()
                 * unshift()
                 * splice()
                 * sort()
                 * reverse()
             */
         this.student.hobbies.splice(0,1,'play a game');
         console.log(this.student);
       }

malpractice

  • The data defined in the data must be used to implement the response
  • If the data added later wants to implement a response, you need to call the corresponding API

Object. Simple example of defineproperty

    let student={
        name:'Zhang San',
        age:18,
    }
    let p={}
    Object.defineProperty(p,'name',{
        get(){  // Triggered when name is read
            console.log('Read it name attribute');
            return student.name;
        },
        set(value){ // Triggered when name is modified
            console.log('name Has changed,The view has changed');
            student.name=value;
        }
    });
    console.log(p.name);
    p.name='Li Si';
    p.sex='male';
    delete p.name;

Vue3 responsive principle

The usage of Proxy and Reflect is not introduced here. If you want to know, please refer to MDN or teacher Ruan Yifeng's ES6

Example

    let user={
        name:'Zhang San',
        age:18,
    }
    let p=new Proxy(user,{
        get(target,propName){
            console.log(`Read it p Inside ${propName}attribute`);
            Reflect.get(target,propName);
            // return target[propName];
        },
        set(target,propName,value){
            console.log(`Modified p Inside ${propName}attribute`);
            // target[propName]=value;
            Reflect.set(target,propName,value);
        },
        deleteProperty(target,propName){
            console.log(`Deleted p Inside ${propName}attribute`);
            // delete target[propName];
            Reflect.deleteProperty(target,propName);
        }
    });
    console.log(p.name);
    p.name='Li Si';
    p.sex='male';
    delete p.age;

Check the console, trigger the get() method when reading the name property, trigger the set() method when adding or modifying properties, and trigger the deleteProperty() method when deleting properties. This is vue3 0 improvements to responsiveness.

Lifecycle and hook functions

Vue2.0 lifecycle and hook functions

vue3.0 lifecycle and hook functions

Vue2 and Vue3 life cycle comparison
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted
activatedonActivated
deactivatedonDeactivated

Because setup runs around the beforeCreate and created lifecycle hooks, there is no need to explicitly define them. In other words, any code written in these hooks should be written directly in the setup function.

The lifecycle hooks in Vue2x can continue to be used in Vue3x, but two have been renamed

  • beforeDestory is renamed beforeUnmout
  • destoryed renamed unmounted

    <template>
    <!--Vue3x Lifecycle and hook functions-->
    <h3>Vue3x Lifecycle and hook functions</h3>
    <h3>Number:{{num}}</h3>
    <button @click="num++">Order me to add</button>
    </template>
    
    <script>
    import {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'
    export default {
        name: "lifeCycleComponent",
        setup(){
            let num=ref(0);
            console.log("======setup=========");
            onBeforeUnmount(()=>{
                console.log("======onBeforeUnmount=========");
            });
            onMounted(()=>{
                console.log("======onMounted=========");
            });
            onBeforeUpdate(()=>{
                console.log("======onBeforeUpdate=========");
            });
            onUpdated(()=>{
                console.log("======onUpdated=========");
            });
            onBeforeUnmount(()=>{
                console.log("======onBeforeUnmount=========");
            })
            onUnmounted(()=>{
                console.log("======onUnmounted=========");
            });
            return{
                num,
            }
        }
    }
    </script>
    
    <style scoped>
    
    </style>

Custom hook

  • What is hook: it is essentially a function that encapsulates the composition API used in the setup function
  • Similar to mixin in vue2x
  • Advantages of custom hook: reuse code to make the logic in setup clearer and easier to understand

As a beginner of hook, I don't know much about hook. Here are some examples from my own practice. At this stage, I can't feel the difference and advantages between export export function and hook. The example is to obtain the current coordinates when the mouse clicks

Example

<template>
    <h2>custom hook</h2>
    <h2>current x Coordinates of:{{x}},current y Coordinates of:{{y}}</h2>
</template>

<script>
    import {reactive,toRefs,onMounted,onUnmounted} from 'vue'
    export default {
        name: "hook_component01",
        setup(){
            // data
            let point=reactive({
                x:0,
                y:0,
            })
            // method
            function getPoint(event){
                console.log(event)
                point.x=event.clientX;
                point.y=event.clientY;
            }
            // Lifecycle hook function
            onMounted(()=>{
                window.addEventListener('click',getPoint);
            })
            onUnmounted(()=>{
                window.removeEventListener('click',getPoint);
            })
            return{
                ...toRefs(point)
            }
        }
    }
</script>

<style scoped>

</style>

Separate hook

  • New directory hook
  • Create a new file usepoint. In the hook directory js

usePoint.js

import {reactive,onMounted,onUnmounted} from 'vue'
export let getPoint=()=>{
    // data
    let point=reactive({
        x:0,
        y:0,
    })
    // method
    function getPoint(event){
        console.log(event)
        point.x=event.clientX;
        point.y=event.clientY;
    }
    // Lifecycle hook function
    onMounted(()=>{
        window.addEventListener('click',getPoint);
    })
    onUnmounted(()=>{
        window.removeEventListener('click',getPoint);
    })
    return point
}

hook needs to be introduced vue file

    import {reactive,toRefs,onMounted,onUnmounted} from 'vue'
    import {getPoint} from "./hook/usePoint";
    export default {
        name: "hook_component01",
        setup(){
            let point=getPoint();
            return{
                ...toRefs(point)
            }
        }
    }

This is the simplest use of hook. If you know the difference between export export function and hook, you can leave a message in the comment area below. Thank you!!!

Other composition APIs

toRef and toRefs

toRef

  • Function: create a ref object whose value points to an attribute value in another object
  • Syntax: const name=toRef(obj,'name')
  • Application: when you want to provide a property in a responsive object separately for external use
  • Extension: the function of toRefs is the same as that of toRef, but multiple ref objects can be created in batch. toRefs(obj)

Example 1

<template>
    <h2>toRef And toRefs</h2>
    <h2>full name:{{person.name}}</h2>
    <h2>Age:{{person.age}}</h2>
    <h2>Salary:{{person.job.salary}}k</h2>
    <button @click="person.name+='!'">Modify name</button>
    <button @click="person.age++">Modify age</button>
    <button @click="person.job.salary++">Raise your salary</button>
</template>

<script>
    import {reactive} from 'vue'
    export default {
        name: "toRef_component",
        setup(){
            let person=reactive({
                name:'Erlang Shenyang',
                age:18,
                job:{
                    salary:20
                }
            })
            return{
                person,
            }
        }
    }
</script>

<style scoped>

</style>

In example 1, the person object is directly returned, resulting in the need for person every time the value is taken XXX, this is neither beautiful nor elegant. Modify the code.

Example 2

<template>
    <h2>toRef And toRefs</h2>
    <h2>full name:{{name}}</h2>
    <h2>Age:{{age}}</h2>
    <h2>Salary:{{salary}}k</h2>
    <button @click="name+='!'">Modify name</button>
    <button @click="age++">Modify age</button>
    <button @click="salary++">Raise your salary</button>
</template>

<script>
    import {reactive,toRef} from 'vue'
    export default {
        name: "toRef_component",
        setup(){
            let person=reactive({
                name:'Erlang Shenyang',
                age:18,
                job:{
                    salary:20
                }
            })
            return{
                name:toRef(person,'name'),
                age:toRef(person,'age'),
                salary:toRef(person.job,'salary')
            }
        }
    }
</script>

<style scoped>

</style>

Example 1 of incorrect usage

<template>
    <h2>toRef And toRefs</h2>
    <h2>full name:{{name}}</h2>
    <h2>Age:{{age}}</h2>
    <h2>Salary:{{salary}}k</h2>
    <button @click="name+='!'">Modify name</button>
    <button @click="age++">Modify age</button>
    <button @click="salary++">Raise your salary</button>
</template>

<script>
    import {reactive,toRef,toRefs} from 'vue'
    export default {
        name: "toRef_component",
        setup(){
            let person=reactive({
                name:'Erlang Shenyang',
                age:18,
                job:{
                    salary:20
                }
            })
            return{
                name:person.name,
                age:person.age,
                salary:person.job.salary
            }
        }
    }
</script>

<style scoped>

</style>

Example 2 of incorrect usage

<template>
    <h2>toRef And toRefs</h2>
    <h2>full name:{{name}}</h2>
    <h2>Age:{{age}}</h2>
    <h2>Salary:{{salary}}k</h2>
    <h2>peron object{{person}}</h2>
    <button @click="name+='!'">Modify name</button>
    <button @click="age++">Modify age</button>
    <button @click="salary++">Raise your salary</button>
</template>

<script>
    import {reactive,toRef,toRefs,ref} from 'vue'
    export default {
        name: "toRef_component",
        setup(){
            let person=reactive({
                name:'Erlang Shenyang',
                age:18,
                job:{
                    salary:20
                }
            })
            return{
                person,
                name:ref(person.name),
                age:ref(person.age),
                salary:ref(person.job.salary)
            }
        }
    }
</script>

<style scoped>

</style>

toRefs

Example 1

<template>
    <h2>toRef And toRefs</h2>
    <h2>full name:{{name}}</h2>
    <h2>Age:{{age}}</h2>
    <h2>Salary:{{job.salary}}k</h2>
    <button @click="name+='!'">Modify name</button>
    <button @click="age++">Modify age</button>
    <button @click="job.salary++">Raise your salary</button>
</template>

<script>
    import {reactive,toRef,toRefs} from 'vue'
    export default {
        name: "toRef_component",
        setup(){
            let person=reactive({
                name:'Erlang Shenyang',
                age:18,
                job:{
                    salary:20
                }
            })
            return{
                ...toRefs(person)
            }
        }
    }
</script>

<style scoped>

</style>

shallowRef and shallowReactive

  • shallowReactive: only handle the response of the outermost attribute of the object (shallow response)
  • shallowRef: only the response of basic data type is processed, and the response of object is not processed
  • When

    • If there is an object data with a deep structure, but only the outer attributes change, use shallowReactive
    • If there is an object data, the subsequent function will not modify the attributes in the object, but generate a new object to replace with shallowRef

shallowRef example

<template>
    <h2>shallowRef Example</h2>
    <h2>current sum The values are:{{sum}}</h2>
    <button @click="sum++">Point me sum Plus 1</button>
    <h2>current x.y The values are:{{x.y}}</h2>
    <button @click="x.y++">Point me x.y Plus 1</button>
    <button @click="x={y:100}">Click me to replace y Value of</button>
</template>

<script>
    import {shallowRef,ref} from 'vue'
    export default {
        name: "shallowRef_component",
        setup(){
            let sum=ref(0);
            let x=shallowRef({
                y:0,
            })
            return{
                sum,
                x,
            }
        }
    }
</script>

<style scoped>

</style>

Here, we compare ref and shallowRef. When you click the x.y + 1 button, the view will not trigger the update, because the value object of Y is deep-seated, and when you directly click the sum + 1 button, the update can be triggered. Sum is shallow directly. When you replace the value of Y, you replace the value of the whole x (i.e. the whole object), rather than the value in X.

shallowReactive example

<template>
    <h2>shallowReactive Example</h2>
    <h2>full name:{{name}}</h2>
    <h2>Age:{{age}}</h2>
    <h2>Salary:{{job.salary}}k</h2>
    <button @click="name+='!'">Modify name</button>
    <button @click="age++">Modify age</button>
    <button @click="job.salary++">Raise your salary</button>
</template>

<script>
    import {shallowReactive,toRefs} from 'vue'
    export default {
        name: "shallowReactive01_component",
        setup(){
            let person=shallowReactive({
                name:'Zhang San',
                age:18,
                job:{
                    salary:20,
                }
            })
            return{
                ...toRefs(person)
            }
        }
    }
</script>

<style scoped>

</style>

When you click the modify name and modify age buttons, you can see that the view changes. When you click salary increase, the view will not change, but the data changes. You can use the console to test this.

readonly and shallowReadonly

  • readonly: make a responsive data read-only (deep read-only)
  • shallowReadonly: make a response read-only (shallow read-only)
    Example 1

    <template>
    <h2>readonly And shallowReadonly</h2>
    <h2>full name:{{name}}</h2>
    <h2>Age:{{age}}</h2>
    <h2>Salary:{{job.salary}}</h2>
    <h2>current sum The values are:{{sum}}</h2>
    <button @click="name+='!'">Modify name</button>
    <button @click="age++">Modify age</button>
    <button @click="job.salary++">Pay rise(readonly)</button>
    <button @click="job.salary++">Pay rise(shallowReadonly)</button>
    <button @click="sum++">Point I add 1</button>
    </template>
    
    <script>
    import {ref,reactive,readonly,shallowReadonly,toRefs} from 'vue'
    export default {
        name: "shallowReadonly_component",
        setup(){
            let sum=ref(0);
            let person=reactive({
                name:'Er Lang Shen Yang Jian',
                age:21,
                job:{
                    salary:200
                }
            });
            person=readonly(person);
            sum=readonly(sum);
            // person=shallowReadonly(person);
            // sum=readonly(sum);
            return{
                sum,
                ...toRefs(person)
            }
        }
    }
    </script>
    
    <style scoped>
    
    </style>


When using readonly, all the buttons are invalid. Let's see the effect of shallowReadonly


When using shallowReadonly, changing the name and age will not change, only the salary increase will change

toRaw and markRaw

  • toRaw

    • Function: convert a reactive object into a normal object
    • Usage scenario: used to read the ordinary object corresponding to the responsive object. All operations on this ordinary object will not cause page updates
  • markRow

    • Purpose: mark an object so that it will never become a responsive object again

      Application scenario:

    • Some values should not be set to be responsive, such as complex third-party class libraries,
    • Skipping responsive transformations can improve performance when rendering large lists with immutable data sources
      Example 1
<template>
    <div style="width: 800px;margin: 0 auto">
        <h2>toRaw And markRow</h2>
        <h2>full name:{{name}}</h2>
        <h2>Age:{{age}}</h2>
        <h2>Salary:{{job.salary}}k</h2>
        <button @click="name+='!'">Modify name</button>
        <button @click="age++">Modify age</button>
        <button @click="job.salary++">Raise your salary</button>
        <button @click="showRawPerson">Output the original person object</button>
    </div>
</template>

<script>
    import {ref,reactive,toRaw,markRaw,toRefs} from 'vue'
    export default {
        name: "toRaw01_component",
        setup(){
            let sum=ref(0);
            let person=reactive({
                name:'Er Lang Shen Yang Jian',
                age:18,
                job:{
                    salary:20
                }
            })
            function showRawPerson() {
                let p=toRaw(person)
                console.log(p);
                let sum=toRaw(sum);
                console.log(sum);   // Invalid responsive data for ref definition
            }
            return{
                sum,
                ...toRefs(person),
                showRawPerson
            }
        }
    }
</script>

<style scoped>

</style>

When calling the showRawPerson method, the console can see that the output of the original person,sum, undefined and toRaw is invalid for the response data defined by ref. next, let's see the effect of markRow

Example 2

<template>
    <div style="width: 800px;margin: 0 auto">
        <h2>toRaw And markRow</h2>
        <h2>full name:{{name}}</h2>
        <h2>Age:{{age}}</h2>
        <h2>Salary:{{job.salary}}k</h2>
        <button @click="name+='!'">Modify name</button>
        <button @click="age++">Modify age</button>
        <button @click="job.salary++">Raise your salary</button>
        <button @click="showRawPerson">Output the original person object</button>
        <h2>The vehicle information is:{{person.car}}</h2>
        <button @click="addCar">Add a car to someone</button>
        <template v-if="person.car">
            <button @click="person.car.name+='!'">Modify car name</button>
            <button @click="person.car.price++">Modify the price of the car</button>
            <button @click="changeCarPrice">Modify the price of the car</button>
        </template>
    </div>
</template>

<script>
    import {ref,reactive,toRaw,markRaw,toRefs} from 'vue'
    export default {
        name: "toRaw01_component",
        setup(){
            let sum=ref(0);
            let person=reactive({
                name:'Er Lang Shen Yang Jian',
                age:18,
                job:{
                    salary:20
                }
            })
            function showRawPerson() {
                let p=toRaw(person)
                console.log(p);
                let sum=toRaw(sum);
                console.log(sum);   // Invalid responsive data for ref definition
            }
            function addCar() {
                let car={name:'bmw',price:40}
                person.car=markRaw(car);
            }
            function changeCarPrice() {
                person.car.price++;
                console.log(person.car.price)
            }
            return{
                sum,
                person,
                ...toRefs(person),
                showRawPerson,
                addCar,
                changeCarPrice
            }
        }
    }
</script>

<style scoped>

</style>

Here, a method and related attributes of car information are added to the person object. Normally, the added data directly in reactive will be responsive, but the markRaw method is used here. Therefore, when you click to modify the car name and price, the data changes, but the view will not be updated.

customRef

  • Function: create a custom ref and display and control its dependency tracking and update trigger. It requires a factory function that receives track and trigger functions as parameters and should return an object with get and set.
    Achieve anti shake effect:
  • 1. Implement custom two-way binding first
  • 2. After realizing bidirectional binding, anti shake is realized
    Custom bidirectional binding

    <template>
    <h2>customRef Example</h2>
    <input type="text" v-model="msg">
    <h2>{{msg}}</h2>
    </template>
    
    <script>
    import {customRef,} from 'vue'
    export default {
        name: "customRef01_component",
        setup(){
            function myRef(msg){   // Custom ref function
               return customRef((track,trigger)=>{
                   return{
                       get(){
                           console.log('Read value')
                           track();
                           return msg;
                       },
                       set(newValue){
                        console.log(`Modified value,The modified value is: ${newValue}`);
                           msg=newValue;
                           trigger();
                       }
                   }
               })
            }
            let msg=myRef('Hello');
            return{
                msg
            }
        }
    }
    </script>
    
    <style scoped>
    
    </style>


Here we realize the bidirectional binding of data, and then we realize the anti shake

<template>
    <div style="width: 800px;margin: 0 auto">
        <h2>customRef Example</h2>
        <input type="text" v-model="msg">
        <h2>{{msg}}</h2>
    </div>
</template>

<script>
    import {customRef,} from 'vue'
    export default {
        name: "customRef01_component",
        setup(){
            function myRef(msg,delay){   // Custom ref function
                let timer;
               return customRef((track,trigger)=>{
                   return{
                       get(){
                           console.log('Read value')
                           track();
                           return msg;
                       },
                       set(newValue){
                           timer=setTimeout(()=>{
                               console.log(`Modified value,The modified value is: ${newValue}`);
                               msg=newValue;
                               trigger();
                           },delay)
                       }
                   }
               })
            }
            let msg=myRef('Hello',500);
            return{
                msg
            }
        }
    }
</script>

<style scoped>

</style>

Judgment of responsive data

  • isRef: checks whether a value is a ref object
  • isReactive: checks whether an object is a reactive proxy created by reactive
  • isReadonly: checks whether an object is a read-only proxy created by readonly
  • isProxy: check whether an object is a proxy created by the reactive or readonly methods

provide and inject

  • Function: realize communication between progeny and descendant components
  • Routine: the parent component has a provide option to provide data, and the descendant component has an inject option to start using these data

Ancestor component

<template>
    <h2>I'm Zu</h2>
    <h3>Car information</h3>
    <p>name:{{name}}</p>
    <p>Price:{{price}}</p>
    <inject_component></inject_component>
</template>

<script>
    import {reactive,toRefs,provide} from 'vue'
    export default {
        name: "provide_component",
        setup(){
            let car=reactive({
                name:'bmw',
                price:'40w'
            });
            provide('car',car);    // provide
            return{
                ...toRefs(car)
            }
        }
    }
</script>

<style scoped>

</style>

Descendant component

<template>
    <h2>I'm sun</h2>
    <h3>Car information</h3>
    <p>name:{{name}}</p>
    <p>Price:{{price}}</p>
</template>

<script>
    import {inject,toRefs,ref} from 'vue'
    export default {
        name: "inject_component",
        setup(){
            let car=inject("car");    //Receive using inject
            return{
                ...toRefs(car)
            }
        }
    }
</script>

<style scoped>

</style>

Fragment

  • In vue2: the component must have a root label
  • In vue3: components can have no root tags, and multiple root tags will be included in a Fragment virtual element

Benefits: reduce tag levels and memory usage

Teleport

Teleport is a technology that can move our component html structure to a specified location

<teleport to='Move position'>
    <div v-if='isShow' class='mark'>
        <div class="dialog">
            <h3>I am a pop-up window</h3>
            <button @click='isShow=true'>Close pop-up window</button>
        </div>
    </div>
</teleport>

A pop-up window is displayed in the middle. There are four components: report_ parent,teleport_child,teleport_son,teleport_dialog, and then the effect to be realized is in teleport_ Introducing teleport into the son component_ Dialog component, report_ The dialog is displayed in the middle of the screen

teleport_parent.vue

<template>
    <div class="parent">
        <h2>I am parent assembly</h2>
        <teleport_child/>
    </div>
</template>

<script>
    import Teleport_child from "./teleport_child";
    export default {
        name: "teleport_parent",
        components: {Teleport_child}
    }
</script>

<style scoped>
    .parent{
        background-color: red;
        padding: 10px;
    }
</style>

teleport_child.vue

<template>
    <div class="child">
        <h2>I am child assembly</h2>
        <teleport_son/>
    </div>
</template>

<script>
    import Teleport_son from "./teleport_son";
    export default {
        name: "teleport_child",
        components: {Teleport_son}
    }
</script>

<style scoped>
    .child{
        background-color: orange;
        padding: 10px;
    }
</style>

teleport_son.vue

<template>
    <div class="son">
        <h2>I am son assembly</h2>
        <teleport_dialog/>
    </div>
</template>

<script>
    import Teleport_dialog from "./teleport_dialog";
    export default {
        name: "teleport_son",
        components: {Teleport_dialog}
    }
</script>

<style scoped>
    .son{
        background-color: yellow;
        padding: 10px;
    }
</style>

teleport_dialog.vue

<template>
    <div>
        <button @click="isShow=true">Click me to pop up</button>
        <div class="dialog_container" v-if="isShow">
            <h2>I'm the pop-up component</h2>
            <div class="dialog_body">
                <h2>I am the content</h2>
                <h2>I am the content</h2>
                <h2>I am the content</h2>
                <h2>I am the content</h2>
            </div>
            <button @click="isShow=false">close button</button>
        </div>
    </div>
</template>

<script>
    import {ref} from 'vue'
    export default {
        name: "teleport_dialog",
        setup(){
            let isShow=ref(false);
            return{
                isShow
            }
        }
    }
</script>

<style scoped>
    .dialog_container{
        width: 500px;
        height: 300px;
        background: red;
    }
</style>

The results are as follows


When we click the button, the effect is like this


When you click the button, the pop-up window will display, but the height of son will be changed in the son component, which is not beautiful. If the pop-up window uses positioning, it can be separated from the document flow without expanding the height in son. However, position: absolute is positioned according to the nearest parent element with positioning element, so this method is unreliable, The effect we need to achieve is to locate according to the body

Modify the style of dialog

<template>
    <div>
        <button @click="isShow=true">Click me to pop up</button>
        <teleport to="body">
            <div class="mask" v-if="isShow">
                <div class="dialog_container">
                    <h2>I'm the pop-up component</h2>
                    <div class="dialog_body">
                        <h2>I am the content</h2>
                        <h2>I am the content</h2>
                        <h2>I am the content</h2>
                        <h2>I am the content</h2>
                    </div>
                    <button @click="isShow=false">close button</button>
                </div>
            </div>
        </teleport>
    </div>
</template>

<script>
    import {ref} from 'vue'
    export default {
        name: "teleport_dialog",
        setup(){
            let isShow=ref(false);
            return{
                isShow
            }
        }
    }
</script>

<style scoped>
    .mask{
        position: absolute;
        top: 0px;
        left: 0px;
        right: 0px;
        bottom: 0px;
        background: rgba(0,0,0,.5);
    }
    .dialog_container{
        width: 500px;
        height: 300px;
        background: red;
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -250px;
        margin-top: -150px
    }
</style>

Suspense

Function: render some additional content while waiting for asynchronous components to make the application have a better user experience

Use steps:

  • Asynchronous import component
import {defineAsyncComponent} from 'vue'
const child=defineAsyncComponent(()=>import('./components/Child.vue'))
  • Wrap the component with suspend and configure default and fallback
<template>
    <div class="app">
        <h3>I am app assembly</h3>
     <Suspense>
        <template v-slot:default>
                <Child/>
        </template>
        <template v-slot:fallback>
            <h3>Loading......</h3>
        </template>
     </Suspense>
    </div>
</template>

Example

suspense.vue

<template>
    <div class="suspense">
        <h2>I am suspense assembly</h2>
        <child/>
    </div>
</template>

<script>
    import Child from "./child";
    export default {
        name: "suspense01_component",
        components: {Child}
    }
</script>

<style scoped>
    .suspense{
        background-color: red;
        padding: 10px;
    }
</style>

child.vue

<template>
    <div class="child">
        <h2>I am child assembly</h2>
    </div>
</template>

<script>
    export default {
        name: "child"
    }
</script>

<style scoped>
    .child{
        background-color: orange;
        padding: 10px;
    }
</style>

If the above code is used to introduce, suspend and child components will be loaded at the same time. If there are other child components in the child, there are also sub components in the sub components. When the network is slow, the user may not see the child components and other components in the child. This will affect the user experience and modify the corresponding code

suspense.vue

<template>
    <div class="suspense">
        <h2>I am suspense assembly</h2>
        <suspense>
            <template v-slot:default>
                <child/>
            </template>
            <template v-slot:fallback>
                <h3>Please wait, loading...</h3>
            </template>
        </suspense>
    </div>
</template>

<script>
    // import Child from "./child"; //  Static introduction
    import {defineAsyncComponent} from 'vue'
    const Child=defineAsyncComponent(()=>import('./child')) //  Asynchronous introduction
    export default {
        name: "suspense01_component",
        components: {Child}
    }
</script>

<style scoped>
    .suspense{
        background-color: red;
        padding: 10px;
    }
</style>

child.vue

<template>
    <div class="child">
        <h2>I am child assembly</h2>
        <h2>current sum The values are:{{sum}}</h2>
    </div>
</template>

<script>
    import {ref} from 'vue'
    export default {
        name: "child",
        setup(){
            let sum=ref(0);
            return new Promise((resole,reject)=>{
                setTimeout(()=>{
                    resole({
                        sum
                    });
                },3000)
            })
        }
    }
</script>

<style scoped>
    .child{
        background-color: orange;
        padding: 10px;
    }
</style>

In order to see the effect, the component is displayed after a delay of 3 seconds

Other changes in Vue2x and Vue3x

1. Transfer of global API

vue2.x has many global API s and configurations, such as global registration components, registration global instructions, etc

  • Register global components
Vue.component('MyButton',{
    data:()=>{
        count:0,
    },
        template:'<button @click="count++">clicked {{count}} times</button>'
    });
  • Register global directives
Vue.directive('focus',{
    inserted:el=>el.foucus
})
  • Vue3. These API s have been adjusted in 0

The global API, Vue XXX is adjusted to the application instance app

2.x global API(Vue)3.x instance API(app)
Vue.config.xxxapp.config.xxx
Vue.config.productionTipremove
Vue.componentapp.component
Vue.directiveapp.directive
Vue.mixinapp.mixin
Vue.useapp.use
Vue.prototypeapp.config.globalProperties

2. Other changes

  • The data option should always be declared as a function
  • Writing of transition class

Vue2. How to write x

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

Vue3. How to write x

.v-enter-from,
.v-leave-to{
    opacity:0
}
.v-leave-to,
.v-enter-to{
    opacity:1
}
  • Remove keyCode as the modifier of v-on and no longer support config keyCodes
  • Remove v-on Navitive modifier

Parent component binding event

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

Declare custom components in subcomponents

export default{
    emits:['close']
}
  • Remove filter

    Although the filter looks convenient, it needs a custom syntax to break the assumption that the expression in braces is' just javascript ', which has not only learning cost, but also implementation cost. It is recommended to call or calculate attributes to replace the filter

    Vue3x related information

Related library nameOnline address
Vue 3.0 official documents (English)Online address
Vue 3.0 Chinese documentsOnline address
Composition API manualOnline address
Vue 3.0 source code learningOnline address
Vue router official documentOnline address
Vuex 4.0Github
vue-devtoolsGithub
Vite source code learningOnline address
Vite 2.0 Chinese documentsOnline address
New developments in Vue3Online address

Vue3xUI component library

Element-plus

Ant Design of Vue

Vant

NutUI 3

Related library nameOnline address
Vue 3.0 actual constellation story H5 projectOnline address
Vue 3.0 UI component library developmentOnline address
Vue 3.0 + Vite manual readingOnline address
Vue 3.0 introduction project construction (village head Yang)Online address
Vue 3.0 Introduction (technical fat) [not recommended]Online address
Vite 2.0 plug-in development guideOnline address
Vue 3.0 + Vite 2.0 quickly build Electron applicationsOnline address
Vue3.0 video (highly recommended)Online address
Vue3.0 driver's license question bankOnline address

reference material

Nuggets address: https://juejin.cn/post/695512...

Vue.js official website: https://v3.cn.vuejs.org/

bilibili address: https://www.bilibili.com/vide...

MDN address: https://developer.mozilla.org...

ES6 address: https://es6.ruanyifeng.com/

summary

Generally speaking, after learning this blog, it basically covers most of the content in Vue3, and the writing is particularly detailed. There are notes, supporting materials and practical videos. It mainly depends on whether you are willing to take the time to learn. I think learning is a lifelong thing. Of course, learning is also a particularly lonely thing. If this article is helpful to you, remember to praise, collect and pay attention. It's not easy to be original. Thank you for your support!

Keywords: Javascript Front-end Vue.js

Added by Svoboda on Thu, 06 Jan 2022 02:36:50 +0200