First, the implementation process
Second, the main class analysis
2.1. In applybindings, create the BindingContext and then execute the Applybindingstonodeanddescendantsinternal method
2.2. In the Applybindinstonodeanddescendantsinteranl method, the main completion of the current node binding, as well as the child node binding
functionapplybindingstonodeanddescendantsinternal (BindingContext, Nodeverified, Bindingcontextmaydifferfromdomparentelement) {varShouldbinddescendants =true; //Perf optimisation:apply bindings only if ... //(1) We need to store the binding context on this node (because it could differ from the DOM parent node ' s binding conte XT) //Note that we can ' t store binding contexts on non-elements (e.g., text nodes), as IE doesn ' t allow expando propert IES for those //(2) It might bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template) varIselement = (Nodeverified.nodetype = = = 1); if(iselement)//workaround IE <= 8 HTML parsing weirdnessko.virtualElements.normaliseVirtualElementDomStructure (nodeverified); varShouldapplybindings = (iselement && bindingcontextmaydifferfromdomparentelement)//Case (1)|| ko.bindingprovider[' instance ' [' Nodehasbindings '] (nodeverified);//Case (2) if(shouldapplybindings) shouldbinddescendants= Applybindingstonodeinternal (nodeverified,NULL, BindingContext, bindingcontextmaydifferfromdomparentelement) [' Shouldbinddescendants ']; if(Shouldbinddescendants &&!)Bindingdoesnotrecurseintoelementtypes[ko.utils.tagnamelower (nodeverified)]) { //We ' re recursing automatically into (real or virtual) child nodes without changing binding contexts. So, //* for children of a *real* element, the binding context was certainly the same as on their DOM. ParentNode, //Hence bindingcontextsmaydifferfromdomparentelement is false //* for children of a *virtual* element, we can ' t be sure. Evaluating. ParentNode on those children //Skip over any number of intermediate virtual elements, any of which might define a custom binding context, //Hence bindingcontextsmaydifferfromdomparentelement is trueApplybindingstodescendantsinternal (BindingContext, Nodeverified,/*bindingcontextsmaydifferfromdomparentelement:*/!iselement); } }
2.3. Enter the Applybindingstonodeinternal method, which invokes the Bindingprovider Getbindingsaccessors method (for analyzing and retrieving bindings data, Main analysis Data-bind properties)
2.4. Create a Dependentobservable object (dependent on the Monitoring object)
varbindings; if(Sourcebindings &&typeofSourcebindings!== ' function ') {Bindings=sourcebindings; } Else { varProvider = ko.bindingprovider[' instance '], getbindings= provider[' Getbindingaccessors ' | | Getbindingsandmakeaccessors;//Custom Bingindhandler //Get The binding from the provider within a computed observable so we can update the bindings whenever //The binding context is updated or if the binding provider accesses observables. varBindingsupdater = ko.dependentobservable (//Dependent monitoring Objects function() {//do a read, write processing, to achieve a two-way association (only read), the default is to perform a read. Bindings = sourcebindings?sourcebindings (BindingContext, node): Getbindings.call (provider, node, BindingContext); //Register A dependency The binding context to support observable view models. if(Bindings &&bindingcontext._subscribable) bindingcontext._subscribable (); returnbindings; }, NULL, {disposewhennodeisremoved:node}); if(!bindings | |!bindingsupdater.isactive ()) Bindingsupdater=NULL; }
2.5. Then analyze each binding in the bindings and create the INIT, Update method as a Dependentobservable object (where the execution of bindings is sequential).
Three, Bindingprovider analysis
This class mainly provides the parsing of Data-bind properties, mainly provides getbindings, getbindingsaccessors, parsebindingsstring (content use) method to assist the binding process. To create a function object:
functioncreatebindingsstringevaluator (bindingsstring, options) {//Build The source for a function, that evaluates "expression" //for each scope variable, add a extra level of ' with ' nesting //Example Result:with (SC1) {with (SC0) {return (expression)}} varRewrittenbindings =ko.expressionRewriting.preProcessBindings (bindingsstring, Options), Functionbody= "with ($context) {with ($data | | {}) {return{"+ Rewrittenbindings +"}}} ";//Execute with Expression return NewFunction ("$context", "$element", Functionbody); }
1, in the analysis of bindings, will distinguish NodeType 1, 8 of the type. If it is 8 (note), the Virtualnodebindingvalue method of the Virtualelements class is called to parse the binding result.
Four, bindings's sorting skill
See if the custom binding has an after property and recursively if it exists:
functiontopologicalsortbindings (bindings) {//Depth-first Sort varresult = [],//The list of key/handler pairs that we'll returnbindingsconsidered = {},//A temporary record of which bindings is already in ' result 'Cyclicdependencystack = [];//keeps track of a depth-search so, if there ' s a cycle, we know which bindings caused itKo.utils.objectForEach (Bindings,functionpushbinding (bindingkey) {if(!Bindingsconsidered[bindingkey]) { varbinding = ko[' Getbindinghandler '] (Bindingkey); if(binding) {//First add dependencies (if any) of the current binding if(binding[' after ') {//dependency detection, adding an after reference to the array before adding the current itemCyclicdependencystack.push (Bindingkey); Ko.utils.arrayForEach (binding[' After ',function(bindingdependencykey) {if(Bindings[bindingdependencykey]) {if(Ko.utils.arrayIndexOf (Cyclicdependencystack, Bindingdependencykey)!==-1) { ThrowError ("Cannot combine the following bindings, because they has a cyclic dependency:" + cyclicdependencystack.join (",")); } Else{pushbinding (Bindingdependencykey); } } }); Cyclicdependencystack.length--; } //Next Add the current bindingResult.push ({key:bindingkey, handler:binding}); } Bindingsconsidered[bindingkey]=true; } });
Five, attention
1. All Dependentobservable objects, the Readfunction method is executed one time by default during the creation process.
Knockout source code Analysis of the implementation process