Above, no picture, no truth

Spent 400 ocean bought frontedmasters member, a month, is to see the man of god the vue tutorial, no Chinese subtitles, painfully devoured, advice and English good rich people directly buy members went to the website to see video, especially the great god who grow handsome, a high standard of business and English also super Sue, I’m sorry, can’t help but make the anthomaniac, If there is no money can only see my English and slag are summarized, and see the benefits of my article is not to spend money, don’t have to be English, bad is my writing level and business level is really limited, step by step, not heuristic analysis principle and the realization of the code, can only post code and I will try my best to explain and understand how to look at all levels, This is not unscrupulous business, not after sale ah, ha ha.

This article series will introduce VUE from the following aspects

  1. Reactivity (reactive)
  2. The plugin (plug-in)
  3. Render (function)
  4. Routing (routing)
  5. State management
  6. International (Multilingual support)

1 reactivity

Vue is MVVM framework, the biggest feature of which is two-way data binding. After the data Model is modified, the View View will be automatically updated. The View can also synchronize the changes of the ViewModel to the Model through v-Model

This article explores how VUE monitors data changes to automatically update views, and how vUE responsiveness is implemented, step by step.

1.1. The getter and setter

Consider the following code, a simple algebraic relationship, where B depends on A, and b is 10 times as much as A

    var a= 10;
    var b = a*10;
    a = 20
    //b = ? How do I listen for changes in B

Copy the code

How do you monitor a and update B every time you change the value of A, ensuring that their mathematical relationship B is 10 times that of A? I left 10 lines blank for you. Have you thought about the above questions carefully?

We can monitor the change of an object’s properties. When the properties change, we can collect its dependencies and trigger the update of the dependencies

Defineproperty.js has a method called Object.defineProperty that can hijack the getter and setter for a property

  let obj = {
        a:10
    };
    observer(obj, 'a');
    obj.a = 20;
    let b = obj.a;
    obj.a = 30;
    // Implement a function that monitors changes in object properties
    function observer(obj, key) {
        Object.defineProperty(obj, key, {
            configurable: true.// Can be deleted
            enumerable: true.// for in iteration
            set(val) {
                console.log('Properties of the object${key}By assignment${val}`);
            },
            get() {
                console.log('Properties of the object${key}'was read); }}); }// The attribute a of the object is assigned to 20
    // The property a of the object is read
    // The attribute a of the object is assigned to 30
Copy the code

As you can see from the above example, we can simply override the getter and setter of the Object’s property with Object.defineProperty to listen for changes in the Object’s property. The above code can only monitor changes in one property. For all properties of the Object, we need to traverse the transformation. Change the Observer method (here only consider a layer of objects, deep need recursive traversal, array monitoring also need to write another method, interested to see vue source code)

 function observer(obj) {
        Object.keys(obj).forEach(key= > {
            let internalValue = obj[key]
            Object.defineProperty(obj, key, {
                get() {
                    console.log(`getting key "${key}": ${internalValue}`)
                    return internalValue
                },
                set(newVal) {
                    console.log(`setting key "${key}" to: ${internalValue}`)
                    internalValue = newVal
                }
            })
        })
    }
Copy the code

Now we can listen to the changes of all attributes of an object. Half of the problem proposed at the beginning has been solved. The next problem to be solved is how to collect its dependencies and trigger the update of dependencies when attributes change. This is the topic of this article, how to implement a simple responsive system.

The idea is that dependencies are collected when properties are read and dependencies are updated when property values are changed

  1. Implement an observer that hijacks getters and setters for object properties
  2. Implement a global subscriber Dep that can append subscribers and notify dependent updates
  3. Append the current dependency to the Dep when a property is read, and trigger a loop to update the dependency when a property is set

According to this idea, practice a simple responsive system.

   // Global dependency collector Dep
   window.Dep = class Dep {
       constructor() {
           this.subscribers = new Set(a);// Ensure that dependencies are not added repeatedly
       }
       // Add subscribers
       depend() {
           if(activeUpdate) { ActiveUpdate registers as a subscriber
               this.subscribers.add(activeUpdate)
           }

       }
       // Run all subscriber update methods
       notify() {
           this.subscribers.forEach(sub= >{ sub(); }}})let activeUpdate
   // js single-threaded language, only one function can be executed at any time, that is, only one dependent at any time in the update // with a global variable activeUpdate to mark, here is a bit difficult to understand, we think more will understand the arty of autorun
   // Autorun accepts an update function
   function autorun(update) {
       function wrapperUpdate() {
           activeUpdate = wrapperUpdate
           update() / / wrapperUpdate, closures
           activeUpdate = null;
       }
       wrapperUpdate();
   }
   function observer(obj) {
       Object.keys(obj).forEach(key= > {
           var dep = new Dep(); // Create subscriber Dep for each key
           let internalValue = obj[key]
           Object.defineProperty(obj, key, {
               get() {
                   // console.log(`getting key "${key}": ${internalValue}`)
                   // Appends the currently running update function to the subscriber list
                   if(activeUpdate) { 
                       dep.depend() // Collect dependencies
                   }
                   return internalValue
               },
               set(newVal) {
               	//console.log(`setting key "${key}" to: ${internalValue}`)
               	// Add an if to determine if the data changes and then trigger the update
               	if(internalValue ! == newVal) { internalValue = newVal dep.notify()// Trigger dependent updates}}})})}let state = {
       count:0
   }
   observer(state);
   autorun((a)= > {
       console.log('state.count has changed ', state.count)
   })
   state.count = state.count + 5;
   // state.count changes by 0
   // state.count changes by 5
Copy the code

This article will stop here for now, and there is time to update the follow-up content. Although the update time is uncertain, we plan to finish the update by the end of this month. I hope you can pay more attention and support.