The core functions of Vue.js are two, one is the response type data binding system, the other is the component System. This article only explores how two-way binding is Implemented. Start with the knowledge points involved, and then implement a simple Hello World example with code that is simplified and can no longer be simplified.
one, Accessor Properties
An accessor property is a special property in an object that cannot be set directly in an object, but must be defined separately by the DefineProperty () method.
var obj = {};
Defines an accessor property named Hello for obj
Object.defineproperty (obj, "hello", {
Get:function () {return sth},
Set:function (val) {/* do sth */}
})
Obj.hello//can read accessor properties like normal properties
The value of the accessor property is special, reading or setting the value of the accessor property, actually calling its intrinsic property: get and set Functions.
Obj.hello//read property, call get function and return return value of Get function
Obj.hello = "abc"//is The property assignment, is called the set function, the assignment is actually a parameter
The This inside the get and set methods points to obj, which means that the get and set functions can manipulate values inside the Object. In addition, the accessor property will "overwrite" the normal property with the same name, because the accessor property is first accessed, and the normal property with the same name is Ignored.
two, The realization of the minimalist two-way binding
The effect of this example is to enter text in the text box, the same text content will be displayed synchronously in span, and the view will be updated when the value of Obj.hello is modified explicitly in JS or console. This enables the two-way binding of the Model = view and the view = Model.
The above is the basic principle of the Vue implementation of two-way binding.
three, Decomposition Tasks
The above example is just to illustrate the Rationale. What we are ultimately going to achieve is:
First divide the task into several subtasks:
1. Data binding in the input box and the text node
2. When the input box content changes, data Synchronization Changes. That is, the change of the view = Model.
3. When the data changes, the content of the text node changes synchronously. This is the change of model = VIEW.
To implement task one, you need to compile the DOM, here is a knowledge point: Documentfragment.
Iv. DocumentFragment
DocumentFragment (a document Fragment) can be thought of as a node container, which can contain multiple child nodes, and when we insert it into the DOM, only its child nodes are inserted into the target node, so consider it as a container for a set of Nodes. With documentfragment processing nodes, speed and performance are far superior to direct manipulation of the DOM. When Vue compiles, It is the hijacking of all the child nodes of the target (really hijacking, through the append method, the nodes in the DOM will be automatically deleted) to documentfragment, after some processing, and then documentfragment Returns the insert Mount Target as a whole.
# Errata: Flag.append () should be flag.appendchild (). Same below In Chrome with append () unexpectedly normal, no Error.
V. Data initialization bindings
The above code implements the task one, and we can see that Hello World is already present in the input box and the text Node.
VI. Data Binding in response
Consider the implementation of task Two: when we enter data in the input box, we first trigger the input event (or keyup, change event), in the corresponding event handler, we get the value of the input box and assign value to the VM Instance's text Property. We will use DefineProperty to set the text in data to the accessor property of the vm, so assigning a value to Vm.text triggers the set method. In the set method to do two main things, the first is to update the value of the property, the second to leave the task three Again.
Task two is done, and the Text property value synchronizes with the contents of the input box:
Vii. subscription/release Mode (subscribe&publish)
The Text property changes, and the Set method triggers, but the content of the textual node does not change. How do you make text nodes that are also bound to text change synchronously? Here's Another point of knowledge: subscription publishing Mode.
The subscription publishing model (ALSO known as the Observer Pattern) defines a one-to-many relationship that allows multiple observers to listen to a Subject object at the same time, notifying all observer objects when the state of the subject Changes.
Publisher notification-the Subject object receives a notification and pushes the subscriber to do the appropriate action
As mentioned earlier, the second thing to do when the set method triggers is to notify as a publisher: "i am the attribute text, I have changed". The text node is the subscriber who performs the appropriate update operation after the message is Received.
eight, Two-way binding implementation
In retrospect, when new is a Vue, there are two main things: the first is the listening Data: observe (data) and the second is the compilation html:nodetofragement (id).
During the listening process, a topic object DEP is generated for each property in Data.
During HTML compilation, a subscriber is generated for each node associated with the data binding, and Watcher,watcher adds itself to DEP for the corresponding Attribute.
We have implemented: modify the contents of the input box = = Modify the property value in the event callback function and the set method that triggers the Attribute.
The next thing we want to do is to make a notification dep.notify () = + Update method that triggers the subscriber--updates the VIEW.
The key logic here is how to add watcher to the DEP of the associated Attribute.
During the compilation of HTML, A watcher is generated for each node associated with Data. What happens in the watcher function?
first, It assigns itself to a global variable dep.target;
second, the Update method is executed, and the Get method is executed, and the Get method reads the accessor property of the vm, triggering the Get method of the accessor property, which is added to the DEP for the corresponding accessor property in the Get method;
again, get the value of the property, and then update the VIEW.
finally, set the Dep.target to Null. Because it is a global variable and the only bridge associated with dep, watcher must ensure that Dep.target has only one value at any Time.
At this point, Hello World two-way binding is basically implemented. The text content will change with the input box content, modify the value of the Vm.text in the controller, and it will be reflected in the text content synchronously.
Implementation principle of vue.js bidirectional binding