乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      自己寫一個JS單向數(shù)據(jù)流動庫

       昵稱10504424 2015-11-18

        JS單向流動其實就是數(shù)據(jù)到視圖的過程, 這幾天突發(fā)奇想,想著弄一個插件, 把DOM結(jié)構(gòu)使用JS進行描述;

        因為DOM中的Class , content, id, attribute, 事件, 子元素全部通過JS進行描述, 最后把這些元素拼接在一起, 生成一個DOM樹, 如果有些DOM數(shù)是可以復(fù)用的,我們就把他包裝成組件(Component), 方便復(fù)用, 但是使用結(jié)構(gòu)化的JS描述DOM并不形象, 不如直接使用HTML生成,如果能夠準(zhǔn)確把握JS結(jié)構(gòu), 然后封裝各個JS組件, 能夠極大的降低耦合, 讓代碼邏輯更加清楚。

        因為DOM是樹形結(jié)構(gòu), 必須有子元素, 所以要迭代渲染, 生成各種各樣的結(jié)構(gòu), 為了減低耦合度, 使用了自定義事件, 讓元素之間的關(guān)系變低;

        為了簡化model到view的過程, 復(fù)用underscore的template, 結(jié)合model, 自動生成view, 自動渲染;

        因為存在組件這個玩意兒, 我們復(fù)用jQuery 的extend方法, 深度復(fù)制組件的屬性, 讓Component組件之間不會相互影響( 因為使用原型繼承的話, 修改單個組件的屬性值會導(dǎo)致所有復(fù)用該組件的組件屬性值發(fā)生改變);

        視覺模型如下:

        整體源代碼如下:

      運行下面代碼

      復(fù)制代碼
      (function() {
          window.util = {};
      
          util.shallowClone =  function (obj) {
              var c = Object.create(Object.getPrototypeOf(obj));
              Object.getOwnPropertyNames(obj).forEach(function (k) {
                  return c[k] = obj[k];
              });
              return c;
          };
      
          //class操作;
          util.hasClass = function(e, arg) {
              return e.className.indexOf(arg)!==-1 ? true : false;
          };
      
          //添加class;
          util.addClass = function(e, arg) {
              if( !util.hasClass(e, arg) ) {
                  e.className = e.className+" "+arg;
              };
          };
      
          //刪除class
          util.removeClass = function(e, arg) {
              if(!arg) {
                  e.className = "";
              }else{
                  if( !util.hasClass(e, arg) )return;
                  if(e.className.indexOf( arg )!=-1) {
                      if( e.className.split(" ").indexOf( arg ) !== -1) {
                          e.className = e.className.replace(new RegExp(arg,"gi"), "");
                      };
                  };
              };
          };
      
          //匹配className匹配的父級節(jié)點;
          util.closest = function (obj, className ) {
              if(!obj||!className)return;
              if(obj.nodeName.toLowerCase() === "body") return;
              if( util.hasClass(obj.parentNode, className) ) {
                  return obj.parentNode;
              }else{
                  return util.closest(obj.parentNode, className);
              };
          };
      
          //underscore抄的模板引擎;
          var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
      
          var escapes = {
              "'":      "'",
              '\\':     '\\',
              '\r':     'r',
              '\n':     'n',
              '\t':     't',
              '\u2028': 'u2028',
              '\u2029': 'u2029'
          };
      
          util.templateSettings = {
              evaluate    : /<%([\s\S]+?)%>/g,
              interpolate : /<%=([\s\S]+?)%>/g,
              escape      : /<%-([\s\S]+?)%>/g
          };
      
          util.template = function(text, data) {
              var render;
              settings = util.templateSettings;
      
              // Combine delimiters into one regular expression via alternation.
              var matcher = new RegExp([
                  (settings.escape || noMatch).source,
                  (settings.interpolate || noMatch).source,
                  (settings.evaluate || noMatch).source
              ].join('|') + '|$', 'g');
      
              // Compile the template source, escaping string literals appropriately.
              var index = 0;
              var source = "__p+='";
              text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
                  source += text.slice(index, offset)
                      .replace(escaper, function(match) { return '\\' + escapes[match]; });
      
                  if (escape) {
                      source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
                  }
                  if (interpolate) {
                      source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
                  }
                  if (evaluate) {
                      source += "';\n" + evaluate + "\n__p+='";
                  }
                  index = offset + match.length;
                  return match;
              });
              source += "';\n";
      
              // If a variable is not specified, place data values in local scope.
              if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
      
              source = "var __t,__p='',__j=Array.prototype.join," +
                  "print=function(){__p+=__j.call(arguments,'');};\n" +
                  source + "return __p;\n";
      
              try {
                  render = new Function(settings.variable || 'obj', '_', source);
              } catch (e) {
                  e.source = source;
                  throw e;
              }
      
              var template = function(data) {
                  return render.call(this, data);
              };
      
              // Provide the compiled function source as a convenience for precompilation.
              template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
      
              return template;
          };
      
          /**
           * @desc 從jQuery里面拷貝了一個extends;
           * @desc 當(dāng)?shù)谝粋€參數(shù)為boolean值時候,可以實現(xiàn)深度繼承;
           * @param (boolean, result, obj)
           * @param (result, obj, obj, obj)
           * @return result;
           */
          util.cloneProps = function () {
              var options, name, src, copy, copyIsArray, clone,
                  target = arguments[0] || {},
                  i = 1,
                  length = arguments.length,
                  deep = false,
                  isArray = function( arr ){
                      return Object.prototype.toString.call( arr ) === "[object Array]";
                  },
                  core_hasOwn = {}.hasOwnProperty,
                  isPlainObject = function( obj ) {
                      if ( !obj || (typeof obj !== "object") || obj.nodeType ) {
                          return false;
                      }
      
                      try {
                          // Not own constructor property must be Object
                          if ( obj.constructor &&
                              !core_hasOwn.call(obj, "constructor") &&
                              !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
                              return false;
                          }
                      } catch ( e ) {
                          // IE8,9 Will throw exceptions on certain host objects #9897
                          return false;
                      }
      
                      // Own properties are enumerated firstly, so to speed up,
                      // if last one is own, then all properties are own.
      
                      var key;
                      for ( key in obj ) {}
      
                      return key === undefined || core_hasOwn.call( obj, key );
                  };
              // Handle a deep copy situation
              if ( typeof target === "boolean" ) {
                  deep = target;
                  target = arguments[1] || {};
                  // skip the boolean and the target
                  i = 2;
              };
      
              // Handle case when target is a string or something (possible in deep copy)
              if ( typeof target !== "object" && typeof target !== "function" ) {
                  target = {};
              }
      
              // extend jQuery itself if only one argument is passed
              if ( length === i ) {
                  target = this;
                  --i;
              }
      
              for ( ; i < length; i++ ) {
                  // Only deal with non-null/undefined values
                  if ( (options = arguments[ i ]) != null ) {
                      // Extend the base object
                      for ( name in options ) {
                          src = target[ name ];
                          copy = options[ name ];
      
                          // Prevent never-ending loop
                          if ( target === copy ) {
                              continue;
                          }
      
                          // Recurse if we're merging plain objects or arrays
                          if ( deep && copy && ( isPlainObject(copy) || (copyIsArray =  isArray(copy) ) )) {
                              if ( copyIsArray ) {
                                  copyIsArray = false;
                                  clone = src && isArray(src) ? src : [];
      
                              } else {
                                  clone = (src && (typeof src === "object")) ? src : {};
                              }
      
                              // Never move original objects, clone them
                              target[ name ] = util.cloneProps( deep, clone, copy );
      
                              // Don't bring in undefined values
                          } else if ( copy !== undefined ) {
                              target[ name ] = copy;
                          }
                      }
                  }
              }
      
              // Return the modified object
              return target;
          };
      
          //EventBase;
          /**
           * @example
           var obj = Object.create( new EventBase )
           obj.addListener("click", function(type) {
                  console.log(type)
               })
           obj.fireEvent("click");
           * */
          var EventBase = function () {};
      
          EventBase.prototype = {
              /**
               * 注冊事件監(jiān)聽器
               * @name addListener
               * @grammar editor.addListener(types,fn)  //types為事件名稱,多個可用空格分隔
               * @example
               * })
               * editor.addListener('beforegetcontent aftergetcontent',function(type){
                   *         if(type == 'beforegetcontent'){
                   *             //do something
                   *         }else{
                   *             //do something
                   *         }
                   *         console.log(this.getContent) // this是注冊的事件的編輯器實例
                   * })
               */
              addListener:function (types, listener) {
                  types = types.split(' ');
                  for (var i = 0, ti; ti = types[i++];) {
                      if(typeof listener === "function") {
                          getListener(this, ti, true).push(listener);
                      }else{
                          for(var j=0 ;j<listener.length; j++) {
                              getListener(this, ti, true).push(listener[j]);
                          };
                      };
                  };
              },
      
              /**
               * 移除事件監(jiān)聽器
               * @name removeListener
               * @grammar editor.removeListener(types,fn)  //types為事件名稱,多個可用空格分隔
               * @example
               * //changeCallback為方法體
               */
              removeListener:function (types, listener) {
                  types = types.trim().split(' ');
                  for (var i = 0, ti; ti = types[i++];) {
                      removeItem(getListener(this, ti) || [], listener);
                  }
              },
      
              /**
               * 觸發(fā)事件
               * @name fireEvent
               * @grammar
               * @example
               */
              fireEvent:function () {
                  var types = arguments[0];
                  types = types.trim().split(' ');
                  for (var i = 0, ti; ti = types[i++];) {
                      var listeners = getListener(this, ti),
                          r, t, k;
                      if (listeners) {
                          k = listeners.length;
                          while (k--) {
                              if(!listeners[k])continue;
                              t = listeners[k].apply(this, arguments);
                              if(t === true){
                                  return t;
                              }
                              if (t !== undefined) {
                                  r = t;
                              }
                          }
                      }
                      if (t = this['on' + ti.toLowerCase()]) {
                          r = t.apply(this, arguments);
                      }
                  }
                  return r;
              }
          };
          /**
           * 獲得對象所擁有監(jiān)聽類型的所有監(jiān)聽器
           * @public
           * @function
           * @param {Object} obj  查詢監(jiān)聽器的對象
           * @param {String} type 事件類型
           * @param {Boolean} force  為true且當(dāng)前所有type類型的偵聽器不存在時,創(chuàng)建一個空監(jiān)聽器數(shù)組
           * @returns {Array} 監(jiān)聽器數(shù)組
           */
          function getListener(obj, type, force) {
              var allListeners;
              type = type.toLowerCase();
              return ( ( allListeners = ( obj.__allListeners || force && ( obj.__allListeners = {} ) ) )
                  && ( allListeners[type] || force && ( allListeners[type] = [] ) ) );
          };
      
          function removeItem(array, item) {
              for (var i = 0, l = array.length; i < l; i++) {
                  if (array[i] === item) {
                      array.splice(i, 1);
                      i--;
                  };
              };
          };
      
          /**
           * 繼承的基本類;
           * */
          var __extends = (this && this.__extends) || function (d, b) {
              for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
              function __() {
                  this.constructor = d;
              }
      
              __.prototype = b.prototype;
              d.prototype = new __();
          };
      
          var nono =  {};
          /**
           * 組件
           * */
          nono.Dom = function( opt ) {
              opt = opt || {};
              //繼承eventBase;
              EventBase.apply(this, arguments);
              this.doc = opt&&opt.doc || document;
              this.opt = opt || {};
          };
          //繼承EventBase的原型;
          __extends( nono.Dom, EventBase);
      
          /**
           * @desc 綁定自定義事件, Dom初始化即可綁定自定義事件;;
           *
           * */
          nono.Dom.prototype.initEmiter = function (evs) {
              for(var e in evs) {
                  this.addListener(e, evs[e]);
              };
          };
      
          /**
           * 主邏輯, 渲染界面;
           * @param 虛擬DOM
           * @param 目標(biāo)節(jié)點
           * @param true的是時候不會綁定事件和屬性
           * @return 虛擬DOM
           * */
          nono.Dom.prototype.render = function( vEl, tar , flag) {
              if( tar ) {
                  //把目標(biāo)內(nèi)部的所有節(jié)點刪除;
                  this._assignChildren( tar );
              };
              return this._render( vEl, tar ,flag);
          };
      
          /**
           * @desc 更新dom的時候調(diào)用改方法;
           * */
          nono.Dom.prototype.update = function ( tar ) {
              if( tar ) {
                  //把目標(biāo)內(nèi)部的所有節(jié)點刪除;
                  this._assignChildren( tar );
              };
              this.render(this.vEl, tar , true);
          };
      
          /**
           * @desc 迭代并生成子元素;
           * @return void;
           * */
          nono.Dom.prototype.renderKids = function ( kids, tar ) {
              for(var i=0 ,len = kids.length; i< len ;i++ ) {
                  var dom = new nono.Dom();
                  //dom.render(kids[i], tar);
                  //this._render( kids[i] , tar);
                  dom._render(kids[i], tar);
              };
          };
      
          /**
           * @desc 內(nèi)部用的渲染;
           * @param 虛擬DOM
           * @param 目標(biāo)節(jié)點
           * @param true的是時候不會綁定事件和屬性
           * */
          nono.Dom.prototype._render = function(  vEl, tar , flag) {
              //緩存虛擬元素和目標(biāo)節(jié)點;
              if(vEl) this.vEl = vEl;
              if(tar) this.tar = tar;
      
              var nNode, tag;
              //初始化要渲染到的父級節(jié)點;
              tar = (tar&&tar.nodeType === 1 ? tar : undefined );
      
              //如果是字符串的話
              this.fireEvent("beforerender", tar);
              if( typeof vEl === "string" || typeof vEl === "number" ) {
      
                  var string = "";
                  try{
                      string = util.template( vEl )( tar&&tar.dom&&tar.dom.vEl&&tar.dom.vEl.model );
                  }catch(e) {
                      string = "util.template string error";
                  };
                  nNode = document.createTextNode( string );
      
                  //如果是一個可以渲染的組件
              }else if( typeof vEl === "object" && vEl.Class ){
      
                  //通過組件渲染; 組件渲染屬于迭代渲染, 會自動渲染子組件;
                  //生成新元素, 該元素要添加到目標(biāo)節(jié)點中;
                  nNode = this.addComponent( vEl );
      
                  //如果只是一個單純的對象, 我們認為這是一個元素;
              }else if( typeof vEl === "object" ) {
      
                  //tag的名稱;
                  tag = vEl.name || "div";
                  nNode = document.createElement( tag );
      
                  //綁定屬性, 事件, 自定義事件;
                  if( !flag ) {
                      this._assignProps( nNode, vEl&&vEl.model );
                  };
                  nNode.dom = this;
                  nNode.dom.nNode = nNode;
      
                  //如果有子元素的話, 就迭代渲染子元素;;
                  if( nNode&&vEl&&vEl.kids ) {
                      this.renderKids( vEl.kids ,nNode );
                  };
      
              }else if(typeof vEl === "undefined"){
      
                  return
      
              };
      
              //如果有目標(biāo)元素, 那就把所有的子元素先刪了吧;
              if( tar ) {
                  this.fireEvent("beforeappend", nNode, tar);
                  tar.appendChild( nNode );
                  this.fireEvent("afterappend", nNode, tar);
              };
              this.fireEvent("afterrender", tar);
      
              return tar || nNode;
      
          };
      
          /**
           * @public
           * @desc 通過組件渲染;
           * @param vEle 虛擬DOM
           * @return DOM;
           * */
          nono.Dom.prototype.addComponent = function ( vEle ) {
              var Class = vEle.Class;
              var kids = Array.prototype.concat.call([],Class.settings.kids || [],  vEle.kids||  []);
              //把Component中的配置加載到vEle上;
              vEle.kids = kids;
      
              vEle.model = vEle.model || {};
              util.cloneProps(true, vEle.model , Class.settings.model);
      
              vEle.name = vEle.name || Class.settings.name;
              Class.init&&Class.init();
              var dom = new nono.Dom();
              //delete vEle.Class;
              vEle.Class = undefined;
              return dom.render(vEle);
          };
      
          /**
           * 添加屬性到虛擬DOM中;
           * @param target
           * @param { key : value };
           * */
          nono.Dom.prototype._assignProps = function(tar, props) {
              var fc, val;
              for( var p in props ) {
                  fc = p.charAt(0);
                  val = props[p];
                  switch (fc) {
                      case "#" :
                          tar.setAttribute("id", val);
                          break;
                      case "@":
                          tar.setAttribute(p.slice(1), val);
                          break;
                      case "-":
                          tar.style.setProperty(p.slice(1), val);
                          break;
                      case ".":
                          tar.className += val;
                          break;
                      case "!" :
                          //綁定事件;
                          this._assignEv( tar,  p.slice(1), props[p] );
                          break;
                      case "*" :
                          this.initEmiter( props[p] || [] );
                          break;
                      default:
                          props.tplData = props.tplData || {};
                          //把數(shù)據(jù)保存到tplData這個對象里面;
                          props.tplData[p] = props[p];
                  };
              };
          };
      
          /**
           * 添加綁定事件;
           *
           * */
          nono.Dom.prototype._assignEv = function(tar,e, fn) {
              eventHandlers(tar, e, fn ,false);
      
              function cancel(ev) {
                  ev.returnValue = false;
                  ev.cancelBubble = true;
                  ev.preventDefault&&ev.preventDefault();
                  ev.stopPropagation&&ev.stopPropagation();
              };
      
              /**
               * @desc 事件綁定;
               * @param 元素
               * @param 事件名字
               * @param 綁定的事件或者事件數(shù)組
               * @param 是否捕獲
               * */
              function eventHandlers(realElem, evName, fns, capture) {
                  if (typeof fns === "object" ) {
                      for (var i = 0, n = fns.length; i < n; i++) {
                          (function(i) {
                              fns[i] && realElem.addEventListener(evName, function(ev) {
                                  //如果返回false就不自動刷新界面;
                                  if( !fns[i].apply(realElem, Array.prototype.slice.apply(arguments).concat( realElem.dom.vEl )) ) {
                                      cancel(ev);
                                      return
                                  };
                                  //作用域被我們捕獲;
                                  try{
                                      realElem.dom.update(realElem);
                                  }catch(e) {
                                      console.log("realElem.dom.update(); error");
                                  };
                              }, capture);
                          })(i);
                      };
      
                  }else if (fns && (typeof fns === "function")) {
                      realElem.addEventListener(evName, function(ev) {
                          //如果返回false就不自動刷新界面;
                          if( !fns.apply(realElem, Array.prototype.slice.apply(arguments).concat( realElem.dom.vEl )) ) {
                              cancel(ev);
                              return;
                          };
                          //每次執(zhí)行事件的時候都會重新刷新dom, 作用域被我們捕獲;
                          try{
                              realElem.dom.update(realElem);
                          }catch(e) {
                              console.log("realElem.dom.update(); error");
                          };
                      }, capture);
                  };
              };
          };
      
          /**
           * @desc 要把目標(biāo)元素中節(jié)點全部刪除;
           * @param tar 目標(biāo)節(jié)點;
           * */
          nono.Dom.prototype._assignChildren = function( tar ) {
              //所有的NODE節(jié)點;
              var child, name;
              while(child = tar.lastChild) {
                  name = (child.tagName || child.nodeName || "").toLocaleLowerCase();
                  if(name === "script" || name === "link" || name === "style") break;
                  this.fireEvent("beforeremovechild" ,child);
                  //如果fireEvent返回值為false,那么就不刪除元素;
                  if( this.fireEvent("removechild" ,child) !== false ) {
                      tar.removeChild( child );
                  };
                  this.fireEvent("afterremovechild" ,child);
              };
          };
      
          /**
           * @desc更新model模型, 到view中?
           *
           * */
          nono.Dom.prototype.setState = function( key, value) {
      
          };
      
          /**
           * @desc 創(chuàng)建DOM組件, 可以進行復(fù)用, COM組件主要是用來保存參數(shù);
           * @return Constructor;
           * */
          nono.Component = function ( settings ) {
              //這樣可以使用無new的方式使用Component組件
              if( this === window) {
                  return new nono.Component( settings );
              };
              this.settings = util.cloneProps(true, {}, settings);//util.shallowClone(settings);
          };
      
          /**
           * @desc 初始化設(shè)置;
           * */
          nono.Component.prototype.init = function(  ) {
          };
      
          /**
           * @desc 為元素附加視圖;
           * @param 參數(shù)為函數(shù)或者一個對象;
           * @return this;
           * */
          nono.Component.prototype.extendView = function ( obj ) {
              if( typeof obj === "function") {
                  obj.call(this,this.settings.kids);
              }else if( typeof obj === "object" ) {
                  this.setting.kids.push( obj );
              };
              return this;
          };
      
          window.nono = nono;
      })();
      復(fù)制代碼

         這個小庫中包含了幾個工具方法,比如addClass, hasClass, removeClass,closest方法, 以及jQ的extend,和underscore的template方法, 都可以單獨拿出來使用, 還算方便吧;

      DEMO0

        通過這個庫實現(xiàn)了一個顯示和隱藏目標(biāo)元素的demo:

      運行下面代碼

      復(fù)制代碼
      <!DOCTYPE html>
      <html>
      <head lang="en">
          <meta charset="UTF-8">
          <title></title>
          <script src="http://files.cnblogs.com/files/diligenceday/ui.js"></script>
          <style>
              .div1{
                  border:1px solid #9482ff;
                  padding:100px;
                  margin:100px;
              }
          </style>
      </head>
      <body>
      </body>
      <script>
          /*
           <div id="div0">
               <button>按鈕</button>
               <div class="div1">
                  我是內(nèi)容;
               </div>
           </div>
           */
      
          
          /**
           * @descption EXAMPLE
           * name為元素的tag名字
           * model包含了這個元素作用域內(nèi)部的變量,如果以特殊符號開頭的key有特殊的作用, 當(dāng)以
           *  ==>> . 開頭的表示該元素的class;
           *  ==>> # 開頭表示的是元素的id;
           *  ==>> @ 開頭表示的是元素的自定義屬性;
           *  ==>> !開頭的表示元素的事件;
           *  ==>> *開頭表示元素的自定義事件;
           *
           *  kids表示該元素內(nèi)部的所有子元素, 值為一個數(shù)組, 值可以為另外的Compnent組件;
           * */
          var dom = new nono.Dom();
          dom.render({
      
              "name" : "div",
              model : {
                  val : true,
                  "*" : {
                      "showOrHide" : function ( name, value ) {
                          var div1 = dom.nNode.getElementsByClassName("div1")[0];
                          div1.style.display = value ? "block" : "none";
                      }
                  }
              },
              kids : [
                  {
                      "name" : "button",
                      kids : [
                              "button"
                      ],
                      model : {
                          "!click" : function() {
                              dom.vEl.model.value = !dom.vEl.model.value;
                              dom.fireEvent("showOrHide",dom.vEl.model.value);
                          }
                      }
                  },
                  {
                      "name" : "div",
                      model : {
                          "." : "div1"
                      },
                      kids : [
                              "我是內(nèi)容"
                      ]
                  }
              ]
          }, document.body);
      </script>
      </html>
      復(fù)制代碼

       

      DEMO1:

        只要更新模型中的數(shù)據(jù), 并return true, 就會自動更新dom節(jié)點;

      運行下面代碼

      復(fù)制代碼
      <!DOCTYPE html>
      <html>
      <head lang="en">
          <meta charset="UTF-8">
          <title></title>
          <script src="http://files.cnblogs.com/files/diligenceday/ui.js"></script>
      </head>
      <body>
          <div id="div0"></div>
      </body>
      <script>
          var dom = new nono.Dom();
          dom.render({
              name : "p",
              model : {
                  "string" : 0,             //model就是this.dom.vEl.model的引用;
                  "!click" : function ( ev, model ) {
                      //this.dom.vEl就是渲染的初始變量, 改變變量string的值;
                      this.dom.vEl.model.string+=1;
                      //return true的話會更新當(dāng)前的dom, return false會自動取消冒泡和默認行為;
                      return true;
                  }
              },
              kids : [
                 "<div><%=string%></div>"
              ]
          }, document.getElementById("div0"));
      </script>
      </html>
      復(fù)制代碼

        因為可以綁定事件, 如果元素發(fā)生點擊事件的話,如果事件函數(shù)的return值為true,插件會自動刷新當(dāng)前的DOM,

        return false的話會 阻止默認行為以及冒泡;

       

      DEMO2:

        使用該插件先實現(xiàn)了一個簡單的TIP插件:

      運行下面代碼

      復(fù)制代碼
      <!DOCTYPE html>
      <html>
      <head lang="en">
          <meta charset="UTF-8">
          <title></title>
          <script src="http://files.cnblogs.com/files/diligenceday/ui.js"></script>
      </head>
      <style>
          body{
              padding: 40px;
          }
          button{
              margin:10px;
              width: 70px;
              height:30px;
              border-radius: 4px;
          }
          .div0{
              position: relative;
          }
          .content{
              position: absolute;
              width: 200px;
              height: 200px;
              border: 1px solid #eee;
              box-shadow: 1px 1px 1px 1px #666;
              background:#fefefe;
          }
      </style>
      <body>
      
      </body>
      <script>
          var Com = function( con ,callback, callback2 ) {
              return new nono.Component({
                  "name" : "button",
                  model : {
                      "!mouseover" : function ( ev ) {
                          callback( this, ev );
                      },
                      "!mouseout" : function ( ev ) {
                          callback2( this , ev);
                      }
                  },
                  kids:[ con ]
              });
          };
      
          var ComContent = function (  ) {
              return new nono.Component({
                  model : {
                      "." : "content",
                      "con" : "con"
                  },
                  kids:["<%=con%>"]
              });
          };
          /*
           <div class="div0">
               <button>btn0</button>
               <button>btn1</button>
               <button>btn2</button>
               <button>btn3</button>
              <div class="content"></div>
           </div>
           */
      
          var dom = new nono.Dom();
      
          dom.render({
              kids : [
                  {
                      Class : new Com( "button0" , function (el, ev) {
                          dom.fireEvent("mouseoverFn",dom,ev,"one--"+Math.random());
                      }, function() {
                          dom.fireEvent("mouseoutFn", dom);
                      })
                  },
                  {
                      Class : new Com( "button0" , function (el, ev) {
                          dom.fireEvent("mouseoverFn",dom,ev,"two--"+Math.random());
                      }, function() {
                          dom.fireEvent("mouseoutFn", dom);
                      })
                  },
                  {
                      Class : new Com( "button0" , function (el, ev) {
                          dom.fireEvent("mouseoverFn",dom,ev,"thr--"+Math.random());
                      }, function() {
                          dom.fireEvent("mouseoutFn", dom);
                      })
                  },{
                      Class : new ComContent("content")
                  }
              ],
              model : {
                  "*" : {
                      //鼠標(biāo)移入和移出的事件函數(shù)
                      mouseoverFn : function (name, dom, ev, text) {
                          var node = dom.nNode.getElementsByClassName("content")[0];
                          node.style.display = "block";
                          node.style.left = ev.clientX + "px";
                          node.style.top = ev.clientY + "px";
                          node.innerText = text;
                      },
                      mouseoutFn : function () {
                          dom.nNode.getElementsByClassName("content")[0].style.display = "none"
                      }
                  }
              }
          }, document.body);
      </script>
      </html>
      復(fù)制代碼

       

       DEMO2:

        使用ui.js也可以實現(xiàn)TAB頁切換效果:

      運行下面代碼

      復(fù)制代碼
      <!DOCTYPE html>
      <html>
      <head lang="en">
          <meta charset="UTF-8">
          <title></title>
          <script src="http://files.cnblogs.com/files/diligenceday/ui.js"></script>
          <link rel="stylesheet" href="http://cdn./bootstrap/3.3.5/css/bootstrap.min.css"/>
      </head>
      <body>
          <div class="container">
              <div class="row">
                  <div id="div0">
      
                  </div>
              </div>
          </div>
          <script>
              //基于JS描述型的導(dǎo)航欄組件;
              function ComNavButton(content, index) {
                  return new nono.Component({
                      model : {
                          "." : "btn-group",
                          "@role" : "group"
                      },
                      kids : [
                          {
                              name : "button",
                              model : {
                                  "." : "btn btn-default",
                                  "@type" : "button",
                                  "!click" : function() {
                                      util.closest(this,"master").dom.fireEvent("showPanel",index)
                                  }
                              },
                              kids : [content]
                          }
                      ]
                  });
              }
      
              //導(dǎo)航欄組件;
              var ComNav = new nono.Component({
                  model : {
                      "." : "navi btn-group btn-group-justified",
                      "@role" : "group"
                  },
                  kids : [
                       //調(diào)用ComNavButton并生成不同參數(shù)的組件;
                      {Class:ComNavButton("L",0)},
                      {Class:ComNavButton("M",1)},
                      {Class:ComNavButton("R",2)}
                  ]
              });
      
              //內(nèi)容組件;
              var Content = function( content ) {
                  return new nono.Component({
                      model: {
                          "." : "panel panel-default panel-e",
                          "*" : {
                              "show":function() {
                                  this.nNode.style.display = "block"
                              }
                          }
                      },
                      kids : [
                          {
                              model : {
                                  "." : "panel-body"
                              },
                              kids : [ content ]
                          }
                      ]
                  })
              };
      
              //內(nèi)容區(qū)域的組件;
              var ConContent = new nono.Component({
                  model : {
                      "." : "content-group"
                  },
                  kids : [
                      {
                          Class : Content("heheda")
                      },
                      {
                          Class : Content("lallalal")
                      },
                      {
                          Class : Content("ooooooo")
                      }
                  ]
              });
      
              //基于JS描述型的結(jié)構(gòu)化語言;
      /*
              <div class="btn-group btn-group-justified" role="group">
                      <div class="btn-group" role="group">
                      <button type="button" class="btn btn-default">L</button>
              </div>
              <div class="btn-group" role="group">
                      <button type="button" class="btn btn-default">M</button>
              </div>
              <div class="btn-group" role="group">
                      <button type="button" class="btn btn-default">R</button>
              </div>
              </div>
      
              <div class="content-group">
                      <div class="panel panel-default">
                      <div class="panel-body">
                      Panel content0
              </div>
              </div>
              <div class="panel panel-default">
                      <div class="panel-body">
                      Panel content1
              </div>
              </div>
              <div class="panel panel-default">
                      <div class="panel-body">
                      Panel content2
              </div>
              </div>
              </div>
      */
              var dom = new nono.Dom();
      
              dom.render( {
                  kids : [
                      {
                          Class : ComNav,
                          model : {
                          }
                      },
                      {
                          Class : ConContent
                      }
                  ],
                  model : {
                      "." : "master",
                      //綁定自定義事件;
                      "*" :  {
                          "hideAllPanle" : function() {
                              var bodys = document.getElementsByClassName("panel-e")
                              for(var i=0 ;i< bodys.length; i++ ) {
                                  bodys[i].style.display = "none";
                              };
                          },
                          "showPanel" : function (eventName, i) {
                              dom.fireEvent("hideAllPanle");
                              dom.nNode.getElementsByClassName("panel-e")[i].dom.fireEvent("show");
                          }
                      }
                  }
              }, document.getElementById("div0") );
      
          </script>
      </body>
      </html>
      復(fù)制代碼

       

        如果你比較喜歡的可以直接把這個庫作為模板引擎來用, 方便, 如果kids里面有##開頭的字符串, 那么這個庫就認為這是一個模板標(biāo)簽, 會去讀取模板內(nèi)容, 比如這樣:

      運行下面代碼

      復(fù)制代碼
      <!DOCTYPE html>
      <html>
      <head lang="en">
          <meta charset="UTF-8">
          <title></title>
          <script src="http://files.cnblogs.com/files/diligenceday/ui.js"></script>
      </head>
      <body>
      <script id="tpl" type="text/tpl">
              <% for (var i=0 ;i < 10; i++) {%>
                  <p>
                      <%=i%>
                  </p>
              <%}%>
          </script>
          <script id="tpl2" type="text/tpl">
              <% for (var i=0 ;i < 4; i++) {%>
                  <p><%=i%></p>
              <%}%>
          </script>
          <div id="div0">
      
          </div>
      </body>
      <script>
          var dom = new nono.Dom();
          dom.render({
              kids : [
                  "##tpl",
                  "##tpl2"
              ]
          }, document.getElementById("div0"));
      </script>
      </html>
      復(fù)制代碼

       

        在事件觸發(fā)的時候可以通過調(diào)用this.dom.vEl.model獲取model的引用, 或者獲取事件函數(shù)的第二個參數(shù)model,這個model就是this.dom.vEl.model的引用 , 這也是讓父元素和子元素解耦的好方法, DEMO也有咯:

      運行下面代碼

      復(fù)制代碼
      <!DOCTYPE html>
      <html>
      <head lang="en">
          <meta charset="UTF-8">
          <title></title>
          <script src="http://files.cnblogs.com/files/diligenceday/ui.js"></script>
      </head>
      <body>
          <div id="div0">
      
          </div>
      </body>
      <script>
          var Com = new nono.Component({
              name : "p",
              model : {
                  "name" : "name---0",
                  "age" : 17,
                  "!click" : function ( ev , scope ) {
                      this.dom.vEl.model.age += parseInt( this.dom.vEl.model.click() );
                      return true;
                  }
              },
              kids : [
                  "<div><%=name%></div>",
                  "<p style='color:#f00'><%=age%></p>"
              ]
          });
      
          var dom = new nono.Dom();
          dom.render({
              Class : Com,
              model : {
                  "click" : function() {
                      return 1;
                  }
              }
          }, document.getElementById("div0"));
      </script>
      </html>
      復(fù)制代碼

       

       

        使用UI.js的優(yōu)勢是:

          1:JS到HTML組件化的優(yōu)勢可以提現(xiàn)出來,各個單元耦合降低;

          2:你完全可以把這個插件當(dāng)做一個模板引擎來用, 因為復(fù)用了底線庫的template方法, 但是功能更加多樣化;

          3:如果元素dom.model下的屬性發(fā)生改變, 會自動刷新DOM結(jié)構(gòu), 不用人為地去設(shè)置innerHTML或者innerText;

        缺點:

          1:不好學(xué)啊, 又要學(xué)習(xí)新API..;

          2:自定義事件是綁定到指定元素的dom上, 用起來會不習(xí)慣;

       

        這個插件僅供參考, 希望可以慢慢優(yōu)化;

      作者: NONO
      出處:http://www.cnblogs.com/diligenceday/
      QQ:287101329

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多