Vue Data Response

Posted by ieda on Sun, 27 Feb 2022 18:13:36 +0100

1. MVVM mode

Both framework Vue and React are now commonly used in MVVM mode. MVVM is short for Model-View-ViewModel. M stands for Model, V stands for View, and VM stands for View-Model, the bridge between data and model. MVVM is essentially an improved version of MVC. MVVM is simply abstracting the state and behavior of the View in it, separating the view UI from the business logic.

Example:

Template

<span> {{count}}</span>

Data Changes

this.count++

As the data changes, the values in the view also change.

2. Data Response

Data-responsive implementations are divided into invasive and non-invasive. The data of the following frameworks triggers the writing of view changes.

Data Changes in Vue

this.count++

Data Changes in React

this.setState({
    count: this.state.count + 1 
})

Applet Data Change

this.setData({
    count: this.data.count + 1 
})
  • Applets and React are intrusive, and the way data responds is intuitive, triggering view updates while modifying data through an active tuning function.
  • Vue is non-intrusive and its data triggers view updates simply by modifying the variable itself. Vue uses the API associated with JS's change in object attributes to hijack data to update the view.

Vue2 detects data changes using Object. The defineProperty () method collects observers in the get method by defining get and set methods on object properties, and notifies observers in the set method to update views or handle other transactions.

3. Object.defineProperty()

Vue2 detects data changes using Object.defineProperty() Method defines the property's get and set methods to implement. This method can define new attributes directly on an object or modify existing attributes and return the object.

const obj = {}
let _count  = 0
Object.defineProperty(obj,"count", {
    get() {
        console.log("Obtain count attribute")
        return _count
    },
    set(val) {
        console.log("modify count Attribute is" + val)
        _count = val
    }
})

console.log(obj.count)
obj.count = 10
console.log(obj.count)

4. DefneReactive Method

As Object above. In the example of the defineProperty method, define obj. When the count attribute is used, a temporary variable_is required Count to store property values for use by get and set methods, at this time_ Counts can be cumbersome to put outside. Vue2 will take advantage of the closure
Object. DefneProperty is encapsulated in the defineReactive method, where temporary variables are stored.

The defineReactive method is used to define a property value of an object as a response.

const obj = {}

function defineReactive(data, key, value) {
    // When no value is passed, it means listening to data[key], but not modifying the value. 
    if(arguments.length === 2) {
        value = data[key]
    }
    Object.defineProperty(data, key, {
        enumerable: true,
        configurale: true,
        get () {
            console.log(`Obtain ${key} attribute`)
            return value
        },
        set (newValue) {
            console.log(`modify ${key} Attribute is` + newValue)
            if (value === newValue) return
            value = newValue
        }
    })
}
defineReactive(obj, "count", 0)

console.log(obj.count)
obj.count = 10
console.log(obj.count)

4. observe: Recursively detect all attributes of the object

observe effect

const obj = {
    a: {
        b: {
            c: 0
        }
    },
    d: 0
}
defineReactive(obj, "a")
defineReactive(obj, "d")

console.log(obj.a.b)
console.log(obj.d)

For example, the defineReactive method can only detect a single attribute value, and the usage in the example cannot detect obj.a.b and obj. Getting and modifying attributes of a.b.c.

In Vue2, an observe method is defined to convert a normal obejct into a responsive property at each level.

observe(obj)

obserse method

The obserse method handles a common object as a responsive object through the new Oberserver().
The observe method is implemented as follows:

/**
 * Convert a normal object to a responsive object
*/
function observe(value) {
    if (typeof value !== "object") return;
    let ob
    // Responsive Object Processing with u ob_u Property points to itself, identified as a responsive object
    if (typeof value.__ob__ !== "undefined") {
        ob = value.__ob__
    } else {
        // 
        ob = new Observer(value)
    }
    return ob
}

Observer class

The Observer class is used to process each property of an incoming object as responsive data. And hang an instance of Observer on u of the object ob_u Property.

class Observer {
    constructor(normalObj) {
        // Hang an instance of Observer on u of the object ob_u On attributes
        def(normalObj, "__ob__", this, false)
        this.defineReactiveObj(normalObj)
    }
    /**
     * Set all properties of the object as responsive
    */
    defineReactiveObj(value) {
        console.log('Set all properties of the object as responsive', value);
        for (let key in value) {
            defineReactive(value, key)
        }
    }
}
/**
 * Defines an object property value and can be set to enumerable or not.
*/
function def(obj, key, value, enumerable) {
    Object.defineProperty(obj, key, {
        value,
        enumerable,
        writable: true,
        configurable: true
    })
}

DefneReactive uses observe to handle object types

The observe() and new Observer() methods hijack data through the defineReactive method for each enumerable property passed into the object.

The previously defined defineReactive hijacks only the value data[key], which is equivalent to data hijacking only for enumerable attributes of incoming objects. If an attribute's attribute value is an object type, its attribute modification cannot be hijacked.

To do this, you need to
The defineReactive method is modified as follows so that each attribute value of the object is processed responsively through the observe method, so that the lower layers of the object are modified recursively into responsive objects. And the new values passed in by the set method also need to be treated as responsive.

function defineReactive(data, key, value) {
    // When no value is passed, it means listening to data[key], but not modifying the value.
    if (arguments.length === 2) {
        value = data[key]
    }
    // Modify the property value of the object type to a responsive object
    let childOb = observe(value)

    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get() {
            console.log(`Obtain ${key} attribute`)
            return value
        },
        set(newValue) {
            console.log(`modify ${key} Attribute is` + newValue)
            if (value === newValue || childOb === newValue) {
                return
            }
            // Modified new values are also processed as responsive
            childOb = observe(newValue)
        }
    })
}

Use examples

let obj = {
    a: {
        b: {
            c: 0
        }
    },
    d: 0
}
observe(obj)

obj.a.b.c = 10
console.log(obj.a.b)
/*
Output:
Get a property
 Get b property
 Modify c attribute to 10
 Get a property
 Get b property
*/

5. Responsive processing of arrays

let obj = {
    a: [1,2,3]
}
observe(obj)
obj.a.push(4)
/*
Output:
Get a property
*/

As an example, the current observe method does not work with data hijacking processing on arrays, and obj cannot be detected. A Property is modified. Further processing of numeric types is required.

The method of the push/pop/shift/splice/sort/reverse seven array element operations needs to be overridden here.

Not finished yet.

Topics: Javascript Front-end Vue Vue.js Framework