The principle of response in vue3

Before talking about the response of vue3, let's briefly talk about the response principle of vue2.

Object type: through object Defineproperty() intercepts the reading and modification of properties (data hijacking)

Array type: intercept by rewriting a series of methods to update the array.

vue2's response will have the following problems:

1. If you add or delete an attribute, the interface will not be updated

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

Let's verify:

When clicking the button, add the age attribute to the object. At this time, we see that obj has been printed on the browser console Sex is female. This indicates that we have added attributes to the obj object. But nothing has changed on the page. The reason is that vue cannot detect it.

<template>
    <div>
        <div>
            <h1>full name:{{obj.name}}</h1>
            <h1>Age:{{obj.age}}</h1>
            <h1 v-if="obj.sex">Gender:{{obj.sex}}</h1>
        </div>
        <div>
            <button @click="addSex">Click Add gender</button>
        </div>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                obj:{
                    name:'Sun WuKong',
                    age:'99',
                }
            }
        },
        methods:{
            addSex(){
                console.log(this.obj.sex)
                this.obj.sex = 'female'
                console.log(this.obj.sex)
            }
        }
    }
</script>

<style scoped>

</style>

Solution: use $set

<template>
    <div>
        <div>
            <h1>full name:{{obj.name}}</h1>
            <h1>Age:{{obj.age}}</h1>
            <h1 v-if="obj.sex">Gender:{{obj.sex}}</h1>
        </div>
        <div>
            <button @click="addSex">Click Add gender</button>
        </div>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                obj:{
                    name:'Sun WuKong',
                    age:'99',
                }
            }
        },
        methods:{
            addSex(){
                console.log(this.obj.sex)
                this.$set(this.obj,'sex','female')
                console.log(this.obj.sex)
            }
        }
    }
</script>

<style scoped>

</style>

Add a button again and click to delete the name attribute under obj. As you can see, there is still no change on the page.

<template>
    <div>
        <div>
            <h1>full name:{{obj.name}}</h1>
            <h1>Age:{{obj.age}}</h1>
            <h1 v-if="obj.sex">Gender:{{obj.sex}}</h1>
        </div>
        <div>
            <button @click="addSex">Click Add gender</button>
        </div>
        <br>
        <div>
            <button @click="delAge">Click Delete age</button>
        </div>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                obj:{
                    name:'Sun WuKong',
                    age:'99',
                }
            }
        },
        methods:{
            addSex(){
                console.log(this.obj.sex)
                this.$set(this.obj,'sex','female')
                console.log(this.obj.sex)
            },
            delAge(){
                console.log(this.obj.age)
                delete this.obj.age
                console.log(this.obj.age)
            }
        }
    }
</script>

<style scoped>

</style>

Solution: use $delete

<template>
    <div>
        <div>
            <h1>full name:{{obj.name}}</h1>
            <h1 v-if="obj.age">Age:{{obj.age}}</h1>
            <h1 v-if="obj.sex">Gender:{{obj.sex}}</h1>
        </div>
        <div>
            <button @click="addSex">Click Add gender</button>
        </div>
        <br>
        <div>
            <button @click="delAge">Click Delete age</button>
        </div>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                obj:{
                    name:'Sun WuKong',
                    age:'99',
                }
            }
        },
        methods:{
            addSex(){
                console.log(this.obj.sex)
                this.$set(this.obj,'sex','female')
                console.log(this.obj.sex)
            },
            delAge(){
                console.log(this.obj.age)
                this.$delete(this.obj,'age')
                console.log(this.obj.age)
            }
        }
    }
</script>

<style scoped>

</style>

Next, let's talk about arrays. If you want to change the value in the array. Using indexes is ineffective. The page will not change.

<template>
    <div>
        <div>
            <h1>full name:{{obj.name}}</h1>
            <h1 v-if="obj.age">Age:{{obj.age}}</h1>
            <h1 v-if="obj.sex">Gender:{{obj.sex}}</h1>
            <h1>Hobbies:{{obj.hobby}}</h1>
        </div>
        <div>
            <button @click="addSex">Click Add gender</button>
        </div>
        <br>
        <div>
            <button @click="delAge">Click Delete age</button>
        </div>
        <br>
        <div>
            <button @click="updateHobby">Click to modify your hobby</button>
        </div>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                obj:{
                    name:'Sun WuKong',
                    age:'99',
                    hobby:['smoking','Hot head'],
                }
            }
        },
        methods:{
            addSex(){
                console.log(this.obj.sex)
                this.$set(this.obj,'sex','female')
                console.log(this.obj.sex)
            },
            delAge(){
                console.log(this.obj.age)
                this.$delete(this.obj,'age')
                console.log(this.obj.age)
            },
            updateHobby(){
                console.log(this.obj.hobby);
                this.obj.hobby[0] = 'Fight monsters'
                console.log(this.obj.hobby);
            }
        }
    }
</script>

<style scoped>

</style>

 

There are two solutions:

1.$set()

2.splice()

<template>
    <div>
        <div>
            <h1>full name:{{obj.name}}</h1>
            <h1 v-if="obj.age">Age:{{obj.age}}</h1>
            <h1 v-if="obj.sex">Gender:{{obj.sex}}</h1>
            <h1>Hobbies:{{obj.hobby}}</h1>
        </div>
        <div>
            <button @click="addSex">Click Add gender</button>
        </div>
        <br>
        <div>
            <button @click="delAge">Click Delete age</button>
        </div>
        <br>
        <div>
            <button @click="updateHobby">Click to modify your hobby</button>
        </div>
    </div>
</template>

<script>
    export default {
        data(){
            return {
                obj:{
                    name:'Sun WuKong',
                    age:'99',
                    hobby:['smoking','Hot head'],
                }
            }
        },
        methods:{
            addSex(){
                console.log(this.obj.sex)
                this.$set(this.obj,'sex','female')
                console.log(this.obj.sex)
            },
            delAge(){
                console.log(this.obj.age)
                this.$delete(this.obj,'age')
                console.log(this.obj.age)
            },
            updateHobby(){
                console.log(this.obj.hobby);
                // this.obj.hobby[0] = 'fight monsters'
                // this.$set(this.obj.hobby,0, 'fight monsters')
                this.obj.hobby.splice(0,1,'Fight monsters')
                console.log(this.obj.hobby);
            }
        }
    }
</script>

<style scoped>

</style>

The above is vue2 responsive principle and solutions to some problems.

Next, let's talk about the writing of vue3

Install the latest version of scaffold:

npm install -g @vue/cil

Here is a brief introduction to setup

1. It is vue3 A new configuration in 0 with a value of a function

2. The data and methods used in the component are configured in setup. (data and methods)

3. The setup function has two return values. If an object is returned, the properties and methods in the object can be used directly in the template. In another way, you can customize the rendering content by returning a rendering function.

code:

<template>
    <div class="hello">
        
    </div>
</template>

<script>
    import {h} from  'vue'
    export default {
        name: 'HelloWorld',
        setup() {

            return ()=> h('h1','I am vue3')
           
        },
        props: {
            msg: String
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

effect:

4. When using setup, you should pay attention to the following points:

  • Do not mix with vue2 configuration. If mixed, you can access the properties and methods in setup in data and methods of vue2. However, the configuration in Vue cannot be accessed in setup. If the configurations of vue2 and vue3 have the same name, the configuration in setup takes precedence.
  • setup cannot be an async function, because the return value is no longer a return object, but a promise. The template cannot see the attributes in the return object.

The same is to add two buttons: add gender, delete age and modify hobbies. In vue3, directly obj Sex and delete obj The object OBJ can be added, modified, deleted and updated to the page by using the index of age and array. It all benefits from reactive.

<template>
    <div class="hello">
        <div>
            <h1>full name:{{obj.name}}</h1>
            <h1 v-if="obj.age">Age:{{obj.age}}</h1>
            <h1 v-if="obj.sex">Gender:{{obj.sex}}</h1>
        </div>
        <div>
            <button @click="addSex">Click Add gender</button>
        </div>
        <br>
        <div>
            <button @click="delAge">Click Delete age</button>
        </div>
    </div>
</template>

<script>
    import {reactive} from  'vue'
    export default {
        name: 'HelloWorld',
        setup() {
            let obj = reactive({
                name:'Sun WuKong',
                age:99,
            })

            function addSex() {
                obj.sex = 'male'
                console.log('I added sex');
                console.log(obj.sex)
            }

            function delAge() {
                delete obj.age
                console.log('I deleted the age');
                console.log(obj.age)
            }

            return {
                obj,
                addSex,
                delAge
            }
        },
        props: {
            msg: String
        }
    }
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

</style>

 

 

Response principle of vue3

Implementation principle:

  • Through Proxy: intercept the changes of any attribute in the object, including the reading and writing of attributes, the addition of attributes, the deletion of attributes, etc.
  • Through Reflect: operate on the properties of the source object

First, let's talk about the basic usage of Proxy:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script>
    //Source data
    let obj = {
        name:'Sun WuKong',
        age:100
    }

    // Response expression in simulation vue3
    //The first parameter of Proxy is the source data. The second parameter is configuration
    const p = new Proxy(obj,{
        // read
        get(target,propName){
            console.log(`Read p of ${propName}attribute`)
            return target[propName]
        },
        // Modify, add
        set(target,propName,value){
            console.log(`Modified p of ${propName}Properties, ready to update the interface`)
            return target[propName] = value
        },
        //delete
        deleteProperty(target,propName){
            console.log(`Deleted p of ${propName}Properties, ready to update the interface`)
            return delete target[propName]
        }
    })
</script>
</html>

After talking about reflection, first define an object obj. Under obj, there are a and two attributes. Generally, when we want to read the a attribute, we will use obj A to achieve. In fact, there is another way. Just reflect. Reflect.get(obj,'a')

vue3 implements the principle of responsiveness by using Reflect

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

</body>
<script>
    //Source data
    let obj = {
        name:'Sun WuKong',
        age:100
    }

    // Response expression in simulation vue3
    //The first parameter of Proxy is the source data. The second parameter is configuration
    const p = new Proxy(obj,{
        // read
        get(target,propName){
            console.log(`Read p of ${propName}attribute`)
            return Reflect.get(target,propName)
        },
        // Modify, add
        set(target,propName,value){
            console.log(`Modified p of ${propName}Properties, ready to update the interface`)
            return Reflect.set(target,propName,value)
        },
        //delete
        deleteProperty(target,propName){
            console.log(`Deleted p of ${propName}Properties, ready to update the interface`)
            return Reflect.deleteProperty(target,propName)
        }
    })
</script>
</html>

To sum up, the implementation principle of vue2 mainly depends on object defineProperty. vue3 refers to Proxy as Proxy.

Keywords: Javascript Front-end Vue.js

Added by deadlyp99 on Tue, 01 Feb 2022 17:27:32 +0200