Mvvm framework source code learning notes for "Computer son"

Source: Internet
Author: User
Tags hasownproperty

With the launch of the avron V2 project, I began to learn various mvvm frameworks in the industry. In an accidental opportunity, we were lucky to have access to the mvvm source code of winter-CN, the child of the computer. We need to study it carefully.

However, this release is relatively early source code, now may improve a lot, worship address: http://shaofei.name/mvvm/

Mvvm, the son of the computer, now only supports very advanced browsers and is still using ie678 to break the browser, so it is easy to go into. the foresight of others is far beyond the imagination of Lisi!

The framework consists of three files: eventsource. JS, viewmodel. JS, and htmltemplate. js.

Eventsource can be viewed as the W3C eventtarget class and provides the observer mode mechanism.

 function eventsource () {var eventhandlers ={}; this. addeventlistener = function (type, Handler) {// bind event if (! Eventhandlers [type]) {eventhandlers [type] = [];} eventhandlers [type]. push (handler) ;}; this. removeeventlistener = function (type, Handler) {// uninstall the event if (! Eventhandlers [type]) {return;} eventhandlers [type] = eventhandlers [type]. Filter (function (f) {return F! = Handler;})}; this. dispatchevent = function (e) {// dispatch event if (eventhandlers. hasownproperty (E. type) {eventhandlers [E. type]. foreach (function (f) {f. call (this, e) ;}} if (this ["on" + E. type]) {//? Is this useful? I didn't see this ["on" + E. Type] (e) ;}}

viewmodel. js provides two eventsource subclasses, called viewmodel and arrayviewmodel, which have the following functions: Model and collection of backbone, Ko. observable and Ko. observablearray of knouckout. But how can Spam like backbone be compared with advanced products like mvvm? It's cool to the end!

Function viewmodel (data, parent) {If (Data instanceof array) // instanceof is sufficient only for the current page. However, since IE is not supported, you can use array. isarray return New arrayviewmodel (data, parent); var children ={}; var me = this; for (var p in data) {If (data. hasownproperty (p) {void function (p) {// a closure // use the attribute descriptor to convert the attributes of a user's object to the attribute object with accessors of the viewmodel instance. defineproperty (this, P, {Get: function () {// when the user uses "AAA. if (typeof data [p] = "object") return children [p]; else return data [p] ;}, set: function (v) {// when the user uses "AAA. this function is called when BBB = V is assigned a value. Data [p] = V; If (typeof data [p] = "object") {// This is not necessary,★★★★Children [p] = new viewmodel (data [p]); Children [p]. addeventlistener ("propertychange", function (e) {me. dispatchevent ({type: "propertychange", propertyname: P, path: P + ". "+ E. path});})} // dispatch the event to its subscriber at the same time. The event object is just a common object that describes the event type, attribute name, and attribute path (that is, this property belongs to a certain owner) This. dispatchevent ({type: "propertychange", propertyname: P, path: p}) ;}); If (typeof data [p] = "object "){//★★★★If the attribute is an object, recursion is performed. However, it should be determined that the value is null! Children [p] = new viewmodel (data [p]); // bind the propertychange event children [p] to its properties. addeventlistener ("propertychange", function (e) {me. dispatchevent ({type: "propertychange", propertyname: P, path: P + ". "+ E. path });})}}. call (this, p) ;}} eventsource. call (this );}

The arrayviewmodel has a large number of minor differences in viewmodel, that is, a loop method:

Function arrayviewmodel (data, parent) {var me = new array (data. Length); var children ={}; for (VAR I = 0; I

My suggestion is to compress them into the following:

Function defineproperty (me, children, Data, p) {object. defineproperty (Me, P, {Get: function () {If (typeof data [p] = "object") return children [p]; else return data [p] ;}, set: function (v) {data [p] = V; me. dispatchevent ({type: "propertychange", propertyname: P, path: p}) ;}); If (typeof data [p] = "object ") {// hesitate to identify null children [p] = new viewmodel (data [p]); Children [p]. addeventlistener ("propertychan GE ", function (e) {me. dispatchevent ({type: "propertychange", propertyname: P, path: P + ". "+ E. path});})} // This new is not new! Function arrayviewmodel (data, parent) {var me = new array (data. Length); For (VAR I = 0; I

Htmltemplate. JS, indicating low completeness. From the source code observation, we found that the gods like to put allCodePlug it into a constructor, Alexander!

There is an htmltemplate class, passing in an HTML string, returning a File Fragment object through parse, and retaining a parameters object in the body, waiting for the user to call its apply method, upload the VM instance and bind it with the propertychange event! However, propertychange is only a custom event. You have to rely on native events to operate on the control. Instructions on how to bind native events and what native events to bind are written in the template, it will be analyzed in parse and bound one by one!

 
<SCRIPT type = "text/XHTML-template" id = "T"> <Div style = "Background: RGB ($ {r}, $ {g }, $ {B}); width: 100px; Height: 100px; "> </div> <input value =" $ {r | input} "type =" text "/> <input value =" $ {G | input} "/> <input value = "$ {B | input}"/> </SCRIPT>

$ {R | input}Here is its command. It listens to the value of the input element through the input event, which corresponds to the r attribute of the VM.

Function htmltemplate (STR) {var input = NULL; var EOF = {}; var element = NULL; var ATTR = ""; var attributenode = NULL; var state = data; vaR text = NULL; var tag = ""; var errors = []; var isendtag = false; var stack = []; var I; // The three most useful things: var attrsetter = NULL; var parametername = NULL; var parameters = NULL; function attributesetter (attributenode) {This. parts = []; // used to piece together the attribute value this. appendpart = Function (Part) {This. parts. push (part);} This. apply = function () {// value attributenode. value = This. parts. join ("") ;}} function consumecharacterreference (additionalallowedcharacter) {/* omitted */} function unconsume (n) {/* omitted */} function consume (N) {/* slightly */} function next (n) {/* slightly */} function error () {} function _ assert (FLAG) {/* omitted */} var DATA = function (c) {/* omitted */}; var tagopen = function (c) {/* omitted */}; VaR endtagopen = function (c) {/* slightly */}; var tagname = function (c) {/* slightly */}; var beforeattributename = function (c) {/* slightly */}; var attributename = function (c) {/* slightly */}; var afterattributename = function (c) {/* slightly */}; vaR beforeattributevalue = function (c) {/* omitted */}; var attributevaluedq = function (c) {If (C = "\" ") {If (attrsetter) {// collect attribute value fragments attrsetter. appendpart (attributenode. value);}/* slightly */}; VaR attributevaluesq = function (c) {If (C = "\ '") {If (attrsetter) {// collect attribute value fragments attrsetter. appendpart (attributenode. value);}/* slightly */}; var attributevalueuq = function (c) {If (C = "\ n" | C = "\ f" | C = "\ t" | C = "") {If (attrsetter) {// collect attribute value fragments attrsetter. appendpart (attributenode. value);}/* slightly */}; var afterattributevalueq = function (c) {/* slightly */}; var selfclosingstarttag = function (c) {/* omitted */}; VaR afterdollarintext = function (c) {/* omitted */}; var parameterintext = function (c) {/* process commands in innertext */If (C = "}") {text = document. createtextnode (""); var name = parametername. join ("") if (parameters [name]) parameters [name]. push (text); // put it in parameters. This is just a common text node else parameters [name] = [text]; element. appendchild (text); parametername = []; text = NULL; return data;} else {If (parametername = NUL L) parametername = []; parametername. push (c); // patchwork attribute name return parameterintext;} var afterdollarinattributevaluedq = function (c) {/* omitted */} var afterdollarinattributevaluesq = function (c) {/* slightly */} var afterdollarinattributevalueuq = function (c) {/* slightly */} var parameterinattributevaluedq = function (c) {If (C = "}") {If (! Attrsetter) {attrsetter = new attributesetter (attributenode);} attrsetter. appendpart (attributenode. value); attributenode. value = ""; // This is a special object with textcontent. Operations on textcontent will cause a chain reaction var text = {setter: attrsetter, value :"", set textcontent (v) {This. value = V; this. setter. apply () ;}, tostring: function () {return this. value ;}}; var parameterattr = parametername. join (""). split ("|") var name = parameterattr [0] If (parameters [name]) // put it in parameters, parameters [name]. push (text); else parameters [name] = [text]; parametername = []; attrsetter. appendpart (text); text = NULL; If (parameterattr [1]) {void function (element, attributename) {// This is the starting point of everything. The host bound to the current attribute, the input element, which indicates the attributes to be monitored and the listener. // <input value = "$ {r | input}" type = "text"/> element. addeventlistener (parameterattr [1], function () {console. log ("element. value = "+ element. value) setback (name, element [attributename])}, false);} (element, attributenode. name);} return attributevaluedq;} else {If (parametername = NULL) parametername = []; parametername. push (c); // piece together the attribute name return parameterinattributevaluedq;} var parameters = function (c) {/* function is similar to parameterinattributevaluedq */} var parameterinattributevalueuq = function (c) {/* is similar to parameterinattributevaluedq */} function parse () {// The analysis is started, but it is the input = STR called by apply. split (""); input. push (EOF); var root = document. createdocumentfragment (); State = data; element = root; stack = []; I = 0; while (I <input. length) {state = State (input [I ++]);} return root;} var fragment = NULL; var setback = function () {}; this. apply = function (OBJ) {input = NULL; element = NULL; ATTR = ""; attributenode = NULL; State = data; text = NULL; tag = ""; errors = []; isendtag = false; stack = []; I; Parameters = object. create (null); fragment = parse (STR); // a File Fragment this. BIND (OBJ); setback = function (name, value) {// here is the callback OBJ [name] = value;} If (obj. addeventlistener) {// obj is a VM obj. addeventlistener ("propertychange", function (e) {// then traverse the parameters object. Each value is a text object // when we execute textnode. when textcontent = "XXX", textcontent is a setter, which will trigger the apply method of its setter member. // The setter member is actually an attributesetter class instance, the apply method changes the value of a feature node (nodetype = 2) referenced by it to parameters [E. propertyname]. foreach (function (textnode) {textnode. textcontent = OBJ [E. propertyname] ;}) ;}, false) ;}return fragment ;}; object. defineproperty (this, "fragment", {getter: function () {return fragment ;}}); this. bind = function (OBJ) {If (fragment = NULL) return; // a very important step is to collect the parameters collected during the parse process, assign the Vm value to the object through textcontent. keys (parameters ). foreach (function (prop, I) {parameters [prop]. foreach (function (textnode) {textnode. textcontent = OBJ [prop] ;}) ;};};}

The Source Code released from now on is still weak. Look forward to a more complete version!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.