From c45a5e36c18484e71bd1a670be02e21b2c34dba9 Mon Sep 17 00:00:00 2001 From: kmdjs Date: Wed, 1 Mar 2017 09:42:20 +0800 Subject: [PATCH] update docs --- website/dist/bundler.js | 11 ++++++----- website/dist/bundler_en.js | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/website/dist/bundler.js b/website/dist/bundler.js index b8f483b4d..0e86fd736 100644 --- a/website/dist/bundler.js +++ b/website/dist/bundler.js @@ -2,8 +2,9 @@ * mustache.js - Logic-less {{mustache}} templates with JavaScript * http://github.com/janl/mustache.js */ -!function(r,s){"object"===a(e)&&e&&"string"!=typeof e.nodeName?s(e):(i=[e],t=s,o="function"==typeof t?t.apply(e,i):t,!(void 0!==o&&(n.exports=o)))}(void 0,function(n){function e(n){return"function"==typeof n}function r(n){return g(n)?"array":"undefined"==typeof n?"undefined":a(n)}function t(n){return n.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function i(n,e){return null!=n&&"object"===("undefined"==typeof n?"undefined":a(n))&&e in n}function o(n,e){return v.call(n,e)}function s(n){return!o(b,n)}function l(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return y[n]})}function d(e,r){function i(){if(v&&!b)for(;f.length;)delete h[f.pop()];else f=[];v=!1,b=!1}function o(n){if("string"==typeof n&&(n=n.split(w,2)),!g(n)||2!==n.length)throw new Error("Invalid tags: "+n);a=new RegExp(t(n[0])+"\\s*"),l=new RegExp("\\s*"+t(n[1])),d=new RegExp("\\s*"+t("}"+n[1]))}if(!e)return[];var a,l,d,p=[],h=[],f=[],v=!1,b=!1;o(r||n.tags);for(var y,k,j,C,S,M,H=new m(e);!H.eos();){if(y=H.pos,j=H.scanUntil(a))for(var L=0,D=j.length;L0?o[o.length-1][4]:t;break;default:i.push(e)}return t}function m(n){this.string=n,this.tail=n,this.pos=0}function p(n,e){this.view=n,this.cache={".":this.view},this.parent=e}function h(){this.cache={}}var f=Object.prototype.toString,g=Array.isArray||function(n){return"[object Array]"===f.call(n)},v=RegExp.prototype.test,b=/\S/,y={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},x=/\s*/,w=/\s+/,O=/\s*=/,_=/\s*\}/,T=/#|\^|\/|>|\{|&|=|!/;m.prototype.eos=function(){return""===this.tail},m.prototype.scan=function(n){var e=this.tail.match(n);if(!e||0!==e.index)return"";var r=e[0];return this.tail=this.tail.substring(r.length),this.pos+=r.length,r},m.prototype.scanUntil=function(n){var e,r=this.tail.search(n);switch(r){case-1:e=this.tail,this.tail="";break;case 0:e="";break;default:e=this.tail.substring(0,r),this.tail=this.tail.substring(r)}return this.pos+=e.length,e},p.prototype.push=function(n){return new p(n,this)},p.prototype.lookup=function(n){var r,t=this.cache;if(t.hasOwnProperty(n))r=t[n];else{for(var o,a,s=this,l=!1;s;){if(n.indexOf(".")>0)for(r=s.view,o=n.split("."),a=0;null!=r&&a"===o?a=this.renderPartial(i,e,r,t):"&"===o?a=this.unescapedValue(i,e):"name"===o?a=this.escapedValue(i,e):"text"===o&&(a=this.rawValue(i)),void 0!==a&&(s+=a);return s},h.prototype.renderSection=function(n,r,t,i){function o(n){return s.render(n,r,t)}var s=this,l="",d=r.lookup(n[1]);if(d){if(g(d))for(var c=0,u=d.length;c",this.HTML):(this._mergeData(n),this._generateHTMLCSS(),this._extractChildren(this),e&&this.children.forEach(function(n,e){r._omi_order[e]=e}),this.children.forEach(function(n,e){r.HTML=r.HTML.replace(n._omiChildStr,r.children[r._omi_order[e]].HTML)}),this.HTML=(0,u.default)(this.HTML,this.id),this.HTML)}},{key:"_queryElements",value:function(n){n._mixRefs(),n._execPlugins(),n.children.forEach(function(e){e.node=n.node.querySelector("["+s.default.STYLESCOPEDPREFIX+e.id+"]"),n._queryElements(e)})}},{key:"_mixRefs",value:function(){var n=this,e=s.default.$$("*[ref]",this.node);e.forEach(function(e){e.hasAttribute(n._omi_scoped_attr)&&(n.refs[e.getAttribute("ref")]=e)});var r=this.node.getAttribute("ref");r&&(this.refs[r]=this.node)}},{key:"_execPlugins",value:function(){var n=this;Object.keys(s.default.plugins).forEach(function(e){var r=s.default.$$("*["+e+"]",n.node);r.forEach(function(r){r.hasAttribute(n._omi_scoped_attr)&&s.default.plugins[e](r,n)}),n.node.hasAttribute(e)&&s.default.plugins[e](n.node,n)})}},{key:"_childrenInstalled",value:function(n){var e=this;n.children.forEach(function(n){e._childrenInstalled(n),n.installed()})}},{key:"_fixForm",value:function(){s.default.$$("input",this.node).forEach(function(n){var e=n.type.toLowerCase();""===n.getAttribute("value")&&(n.value=""),"checked"!==e&&"radio"!==e||(n.hasAttribute("checked")?n.checked="checked":n.checked=!1)}),s.default.$$("textarea",this.node).forEach(function(n){n.value=n.getAttribute("value")}),s.default.$$("select",this.node).forEach(function(n){var e=n.getAttribute("value");if(e)s.default.$$("option",n).forEach(function(n){e===n.getAttribute("value")&&n.setAttribute("selected","selected")});else{var r=s.default.$$("option",n)[0];r&&r.setAttribute("selected","selected")}})}},{key:"_replaceTags",value:function(n,e){var r=n.join("|"),t=new RegExp("<("+r+"+)((?:\\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*)\\s*(\\/?)>","g");return e.replace(t,function(n,e){var r=n.length-2;return r>=0&&n.lastIndexOf("/>")===n.length-2?n.replace("<"+e,'":n.lastIndexOf(">")===n.length-1?n.replace("<"+e,'":void 0})}},{key:"_createHiddenNode",value:function(){var n=document.createElement("input");return n.setAttribute("type","hidden"),n.setAttribute(this._omi_scoped_attr,""),n}},{key:"_mergeData",value:function(n){this.dataFirst?this.data=Object.assign({},this._getDataset(n),this.data):this.data=Object.assign({},this.data,this._getDataset(n))}},{key:"_generateHTMLCSS",value:function(){this.CSS=(this.style()||"").replace(/<\/?style>/g,""),this.CSS&&(this.CSS=d.default.scoper(this.CSS,"["+this._omi_scoped_attr+"]"),this.CSS===this._preCSS||this._omi_server_rendering||(d.default.addStyle(this.CSS,this.id),this._preCSS=this.CSS));var n=this.render();this.HTML=this._scopedAttr(s.default.template(n?n:"",this.data),this._omi_scoped_attr).trim(),this._omi_server_rendering&&(this.HTML='\r\n\r\n"+this.HTML,this.HTML+='\r\n\r\n")}},{key:"_scopedAttr",value:function(n,e){return n.replace(/<[^\/]([A-Za-z]*)[^>]*>/g,function(n){var r=n.split(" ")[0].replace(">","");return n.replace(r,r+" "+e)})}},{key:"_getDataset",value:function(n){var e=this,r=(0,f.default)(n),t=r.child[0].attr;return Object.keys(t).forEach(function(n){0===n.indexOf("data-")&&(e._dataset[e._capitalize(n.replace("data-",""))]=t[n])}),this._dataset}},{key:"_capitalize",value:function(n){return n=n.toLowerCase(),n=n.replace(/\b\w+\b/g,function(n){return n.substring(0,1).toUpperCase()+n.substring(1)}).replace(/-/g,""),n.substring(0,1).toLowerCase()+n.substring(1)}},{key:"_extractPropertyFromString",value:function(n,e){var r=n.replace(/['|"|\]]/g,"").replace(/\[/g,".").split("."),t=e;return r.forEach(function(n){t=t[n]}),r=null,t}},{key:"_extractChildren",value:function(n){var e=this;s.default.customTags.length>0&&(n.HTML=this._replaceTags(s.default.customTags,n.HTML));var r=n.HTML.match(/][\s\S]*?tag=['|"](\S*)['|"][\s\S]*?><\/child>/g);r&&r.forEach(function(r,t){var i=(0,f.default)(r),o=i.child[0].attr,a=o.tag;delete o.tag;var l=e.children[t];l&&l.___omi_constructor_name===a?l._childRender(r):!function(){var i={},d={},c={},u={},m=null,p=null;Object.keys(o).forEach(function(r){var t=o[r];if(0===r.indexOf("on")){var a=n[t];a&&(i[r]=a.bind(n))}else"omi-id"===r?m=t:"name"===r?p=t:"group-data"===r?(n._omiGroupDataCounter.hasOwnProperty(t)?n._omiGroupDataCounter[t]++:n._omiGroupDataCounter[t]=0,u=e._extractPropertyFromString(t,n)[n._omiGroupDataCounter[t]]):0===r.indexOf("data-")?d[e._capitalize(r.replace("data-",""))]=t:"data"===r&&(c=e._extractPropertyFromString(t,n))});var h=s.default.getClassFromString(a);if(!h)throw"Can't find Class called ["+a+"]";var f=new h(Object.assign(i,n.childrenData[t],d,c,u),!1);f._omiChildStr=r,f.parent=n,f.___omi_constructor_name=a,f._dataset={},f.install(),m&&(s.default.mapping[m]=f),p&&(n[p]=f),l?n.children[t]=f:n.children.push(f),f._childRender(r,!0)}()})}}]),n}();e.default=g},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){var r=new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|s*{)","g");return n=n.replace(r,function(n,r,t){return r.match(/^\s*(@media|@keyframes|to|from|@font-face)/)?r+t:(r.match(/:scope/)&&(r=r.replace(/([^\s]*):scope/,function(n,e){return""===e?"> *":"> "+e})),r=r.replace(/^(\s*)/,r.trim()+e+",$1"+e+" ").replace(/\s+/g," "),r+t)})}function o(n,e){var r=document.getElementById(s.default.STYLEPREFIX+e),t=document.getElementsByTagName("head")[0];r&&r.parentNode===t&&t.removeChild(r);var i=document.createElement("style");t.appendChild(i),i.setAttribute("type","text/css"),i.setAttribute("id",s.default.STYLEPREFIX+e),window.ActiveXObject?i.styleSheet.cssText=n:i.textContent=n}Object.defineProperty(e,"__esModule",{value:!0});var a=r(3),s=t(a);e.default={scoper:i,addStyle:o}},function(n,e){"use strict";function r(n,e,r){return n.split(e).map(function(n){return n.replace(new RegExp(r,"g"),e)}).join(r)}function t(n){return JSON.stringify(n).replace(/(^"|"$)/g,"")}function i(n){return n=r(n,"'",'"'),r(t(n),"'",'"')}function o(n){return n.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function a(n,e){return String.prototype.endsWith?String.prototype.endsWith.call(n,e):n.substr(n.length-1,1)===e}function s(n,e){return n.replace(/<[\s\S]*?[^=]>/g,function(n){return n.replace(/on(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave|Abort|Blur|Cancel|CanPlay|CanPlayThrough|Change|Click|Close|ContextMenu|CueChange|DblClick|Drag|DragEnd|DragEnter|DragLeave|DragOver|DragStart|Drop|DurationChange|Emptied|Ended|Error|Focus|Input|Invalid|KeyDown|KeyPress|KeyUp|Load|LoadedData|LoadedMetadata|LoadStart|MouseDown|MouseEnter|MouseLeave|MouseMove|MouseOut|MouseOver|MouseUp|MouseWheel|Pause|Play|Playing|Progress|RateChange|Reset|Resize|Scroll|Seeked|Seeking|Select|Show|Stalled|Submit|Suspend|TimeUpdate|Toggle|VolumeChange|Waiting|AutoComplete|AutoCompleteError|BeforeCopy|BeforeCut|BeforePaste|Copy|Cut|Paste|Search|SelectStart|Wheel|WebkitFullScreenChange|WebkitFullScreenError|TouchStart|TouchMove|TouchEnd|TouchCancel|PointerDown|PointerUp|PointerCancel|PointerMove|PointerOver|PointerOut|PointerEnter|PointerLeave)=('|"|{)([\s\S]*)('|"|})/g,function(n,r,t,s,l){if(0===s.indexOf("Omi.instances[")||0===s.indexOf("new Function("))return n;if("{"===t){var d="("+s+").bind(Omi.instances["+e+"])(event)",c="on"+r+"=\"new Function('event', '"+o(i(d))+"')(event)\"";return c.split("\n").map(function(n){return a(n,";")?n:n+";"}).join("")}return s.match(/.*?\(.*?\)/)?n.replace(/=(['|"])/,"=$1Omi.instances["+e+"]."):n})})}Object.defineProperty(e,"__esModule",{value:!0}),e.default=s},function(n,e,r){var t,i,o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(a,s){"object"===o(e)&&"undefined"!=typeof n?n.exports=s():(t=s,i="function"==typeof t?t.call(e,r,e,n):t,!(void 0!==i&&(n.exports=i)))}(void 0,function(){"use strict";function n(n){!d&&m.createRange&&(d=m.createRange(),d.selectNode(m.body));var e;return d&&d.createContextualFragment?e=d.createContextualFragment(n):(e=m.createElement("body"),e.innerHTML=n),e.childNodes[0]}function e(n,e){var r=n.nodeName,t=e.nodeName;return r===t||!!(e.actualize&&r.charCodeAt(0)<91&&t.charCodeAt(0)>90)&&r===t.toUpperCase()}function r(n,e){return e&&e!==u?m.createElementNS(e,n):m.createElement(n)}function t(n,e){for(var r=n.firstChild;r;){var t=r.nextSibling;e.appendChild(r),r=t}return e}function i(n,e){var r,t,i,o,a,s,l=e.attributes;for(r=l.length-1;r>=0;--r)t=l[r],i=t.name,o=t.namespaceURI,a=t.value,o?(i=t.localName||i,s=n.getAttributeNS(o,i),s!==a&&n.setAttributeNS(o,i,a)):(s=n.getAttribute(i),s!==a&&n.setAttribute(i,a));for(l=n.attributes,r=l.length-1;r>=0;--r)t=l[r],t.specified!==!1&&(i=t.name,o=t.namespaceURI,o?(i=t.localName||i,h(e,o,i)||n.removeAttributeNS(o,i)):h(e,null,i)||n.removeAttribute(i))}function o(n,e,r){n[r]!==e[r]&&(n[r]=e[r],n[r]?n.setAttribute(r,""):n.removeAttribute(r,""))}function a(){}function s(n){return n.id}function l(i){return function(o,l,d){function c(n){O?O.push(n):O=[n]}function u(n,e){if(n.nodeType===g)for(var r=n.firstChild;r;){var t=void 0;e&&(t=_(r))?c(t):(M(r),r.firstChild&&u(r,e)),r=r.nextSibling}}function p(n,e,r){S(n)!==!1&&(e&&e.removeChild(n),M(n),u(n,r))}function h(n){if(n.nodeType===g)for(var e=n.firstChild;e;){var r=_(e);r&&(D[r]=e),h(e),e=e.nextSibling}}function y(n){k(n);for(var r=n.firstChild;r;){var t=r.nextSibling,i=_(r);if(i){var o=D[i];o&&e(r,o)&&(r.parentNode.replaceChild(o,r),x(o,r))}y(r),r=t}}function x(n,r,t){var a,s=_(r);if(s&&delete D[s],!l.isSameNode||!l.isSameNode(o)){if(!t){if(j(n,r)===!1)return;if(i(n,r),C(n),H(n,r)===!1)return}if("TEXTAREA"!==n.nodeName){var d,u,h,w,O=r.firstChild,k=n.firstChild;n:for(;O;){for(h=O.nextSibling,d=_(O);k;){if(u=k.nextSibling,O.isSameNode&&O.isSameNode(k)){O=h,k=u;continue n}a=_(k);var S=k.nodeType,M=void 0;if(S===O.nodeType&&(S===g?(d?d!==a&&((w=D[d])?k.nextSibling===w?M=!1:(n.insertBefore(w,k),u=k.nextSibling,a?c(a):p(k,n,!0),k=w):M=!1):a&&(M=!1),M=M!==!1&&e(k,O),M&&x(k,O)):S!==v&&S!=b||(M=!0,k.nodeValue=O.nodeValue)),M){O=h,k=u;continue n}a?c(a):p(k,n,!0),k=u}if(d&&(w=D[d])&&e(w,O))n.appendChild(w),x(w,O);else{var L=T(O);L!==!1&&(L&&(O=L),O.actualize&&(O=O.actualize(n.ownerDocument||m)),n.appendChild(O),y(O))}O=h,k=u}for(;k;)u=k.nextSibling,(a=_(k))?c(a):p(k,n,!0),k=u}var A=f[n.nodeName];A&&A(n,r)}}if(d||(d={}),"string"==typeof l)if("#document"===o.nodeName||"HTML"===o.nodeName){var w=l;l=m.createElement("html"),l.innerHTML=w}else l=n(l);var O,_=d.getNodeKey||s,T=d.onBeforeNodeAdded||a,k=d.onNodeAdded||a,j=d.onBeforeElUpdated||a,C=d.onElUpdated||a,S=d.onBeforeNodeDiscarded||a,M=d.onNodeDiscarded||a,H=d.onBeforeElChildrenUpdated||a,L=d.childrenOnly===!0,D={};h(o);var A=o,E=A.nodeType,P=l.nodeType;if(!L)if(E===g)P===g?e(o,l)||(M(o),A=t(o,r(l.nodeName,l.namespaceURI))):A=l;else if(E===v||E===b){if(P===E)return A.nodeValue=l.nodeValue,A;A=l}if(A===l)M(o);else if(x(A,l,L),O)for(var I=0,X=O.length;I\s]+))?)*)\s*(\/?)>/,t=/^<\/([-A-Za-z0-9_]+)[^>]*>/,i=/([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,o=function(n,e){function o(n,r,t,o){if(r=r.toLowerCase(),o=!!o,o||c.push(r),e.start){var a=[];t.replace(i,function(n,e){var r=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:"";a.push({name:e,value:r,escaped:r.replace(/(^|[^\\])"/g,'$1\\"')})}),e.start&&e.start(r,a,o)}}function a(n,r){if(r)for(var t=c.length-1;t>=0&&c[t]!=r;t--);else var t=0;if(t>=0){for(var i=c.length-1;i>=t;i--)e.end&&e.end(c[i]);c.length=t}}var s,l,d,c=[],u=n;for(c.last=function(){return this[this.length-1]};n;){if(l=!0,c.last())n=n.replace(new RegExp("([\\s\\S]*?)]*>"),function(n,r){return e.chars&&e.chars(r),""}),a("",c.last());else if(0==n.indexOf(">>0,i=0;if(2==arguments.length)e=arguments[1];else{for(;i=t)throw new TypeError("Reduce of empty array with no initial value");e=r[i++]}for(;i640){var o=document.querySelectorAll("pre"),a=this.getHighLight();if(a){for(var s in a)o[s]&&o[s].setAttribute("data-line",a[s]);n||lineHighLight()}}}},{key:"getHighLight",value:function(){var n=this,e=null;return m.default.menus[this.data.lan].forEach(function(r){r.list.forEach(function(r){r.md===n.data.name&&(e=r.highlight)})}),e}},{key:"installed",value:function(){}},{key:"render",value:function(){return this.data.html=marked(s(this.data.name,this.data.lan)),'\n
\n {{{html}}}\n
\n '}},{key:"style",value:function(){return"\n \n "}}]),e}(c.default.Component);e.default=p},function(n,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r={isMobile:!1,mds:{cn:["installation","hello_world","components","communication","lifecycle","events","condition","loop","form","inherit","template","get_dom","plugin","thinking_in_omi","pr_env","pr_hello"],en:["installation","hello_world","components","communication","lifecycle","events","condition","loop","form","inherit","template","get_dom","plugin"]},menus:{cn:[{active:!0,title:"快速开始",currentIndex:0,list:[{name:"安装",md:"installation"},{name:"Hello World",md:"hello_world",highlight:{2:"6",5:"4,6"}},{name:"组件",md:"components",highlight:{2:"3,9,34"}},{name:"组件通讯",md:"communication",highlight:{0:"34",1:"5,11"}},{name:"生命周期",md:"lifecycle"},{name:"事件处理",md:"events"},{name:"条件判断",md:"condition"},{name:"循环遍历",md:"loop",highlight:{1:"9-11"}},{name:"表单",md:"form"},{name:"继承",md:"inherit"},{name:"模板切换",md:"template"},{name:"获取DOM节点",md:"get_dom"},{name:"插件体系",md:"plugin"},{name:"Omi的理念",md:"thinking_in_omi"}]}],en:[{title:"QUICK START",currentIndex:0,list:[{name:"Installation",md:"installation"},{name:"Hello World",md:"hello_world"},{name:"Components",md:"components"},{name:"Communication",md:"communication"},{name:"Lifecycle",md:"lifecycle"},{name:"Handling Events",md:"events"},{name:"Conditional Rendering",md:"condition"},{name:"Loop",md:"loop"},{name:"Forms",md:"form"},{name:"Inheritance",md:"inherit"},{name:"Templates",md:"template"},{name:"Get DOM",md:"get_dom"},{name:"Plugin",md:"plugin"},{name:"Thinking in Omi",md:"thinking_in_omi"}]}]}},t={versions:function(){var n=navigator.userAgent;navigator.appVersion;return{trident:n.indexOf("Trident")>-1,presto:n.indexOf("Presto")>-1,webKit:n.indexOf("AppleWebKit")>-1,gecko:n.indexOf("Gecko")>-1&&n.indexOf("KHTML")==-1,mobile:!!n.match(/AppleWebKit.*Mobile.*/),ios:!!n.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),android:n.indexOf("Android")>-1||n.indexOf("Linux")>-1,iPhone:n.indexOf("iPhone")>-1,iPad:n.indexOf("iPad")>-1,webApp:n.indexOf("Safari")==-1}}(),language:(navigator.browserLanguage||navigator.language).toLowerCase()};(t.versions.mobile||t.versions.ios||t.versions.android||t.versions.iPhone||t.versions.iPad)&&(r.isMobile=!0),e.default=r},function(n,e,r){function t(n){return r(i(n))}function i(n){return o[n]||function(){throw new Error("Cannot find module '"+n+"'.")}()}var o={"./README.md":13,"./cn_communication.md":14,"./cn_components.md":15,"./cn_condition.md":16,"./cn_events.md":17,"./cn_form.md":18,"./cn_get_dom.md":19,"./cn_hello_world.md":20,"./cn_inherit.md":21,"./cn_installation.md":22,"./cn_lifecycle.md":23,"./cn_loop.md":24,"./cn_plugin.md":25,"./cn_pr_nearby.md":26,"./cn_template.md":27,"./cn_thinking_in_omi.md":28,"./deep_in/README.md":29,"./deep_in/cn_env.md":30,"./deep_in/cn_hello.md":31,"./deep_in/cn_nearby.md":32,"./deep_in/cn_omi-cli.md":33,"./en_communication.md":34,"./en_components.md":35,"./en_condition.md":36,"./en_events.md":37,"./en_form.md":38,"./en_get_dom.md":39,"./en_hello_world.md":40,"./en_inherit.md":41,"./en_installation.md":42,"./en_lifecycle.md":43,"./en_loop.md":44,"./en_plugin.md":45,"./en_template.md":46,"./en_thinking_in_omi.md":47};t.keys=function(){return Object.keys(o)},t.resolve=i,n.exports=t,t.id=12},function(n,e){n.exports='module.exports = "## [Docs Website](https://alloyteam.github.io/omi/website/docs.html)\\r\\n\\r\\n### Usage\\r\\n* [安装](./cn_installation.md)\\r\\n* [Hello World](./cn_hello_world.md)\\r\\n* [组件](./cn_components.md)\\r\\n* [组件通讯](./cn_communication.md)\\r\\n* [生命周期](./cn_lifecycle.md)\\r\\n* [事件处理](./cn_events.md)\\r\\n* [条件判断](./cn_condition.md)\\r\\n* [循环遍历](./cn_loop.md)\\r\\n* [表单](./cn_form.md)\\r\\n* [继承](./cn_inherit.md)\\r\\n* [模板切换](./cn_template.md)\\r\\n* [获取DOM节点](./cn_get_dom.md)\\r\\n* [插件体系](./cn_plugin.md)\\r\\n* [Omi理念](./cn_thinking_in_omi.md)\\r\\n\\r\\n### Usage(en-us)\\r\\n* [installation](./en_installation.md)\\r\\n* [Hello World](./en_hello_world.md)\\r\\n* [components](./en_components.md)\\r\\n* [communication](./en_communication.md)\\r\\n* [lifecycle](./en_lifecycle.md)\\r\\n* [events](./en_events.md)\\r\\n* [condition](./en_condition.md)\\r\\n* [loop](./en_loop.md)\\r\\n* [form](./en_form.md)\\r\\n* [inherit](./en_inherit.md)\\r\\n* [template](./en_template.md)\\r\\n\\r\\n"'; -},function(n,e){n.exports='module.exports = "

组件通讯

\\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)组建间的通讯非常遍历灵活,因为有许多可选方案进行通讯:\\r\\n\\r\\n* 通过在组件上声明 data-* 传递给子节点 \\r\\n* 通过在组件上声明 data 传递给子节点 (支持复杂数据类型的映射)\\r\\n* 父容器设置 childrenData 自动传递给子节点\\r\\n* 声明 group-data 传递(支持复杂数据类型的映射)\\r\\n* 完全面向对象,可以非常容易地拿到对象的实例,之后可以设置实例属性和调用实例的方法\\r\\n\\r\\n所以通讯变得畅通无阻,下面一一来举例说明。\\r\\n\\r\\n### data-*通讯 \\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n \\tcursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\t

Hello ,{{name}}!

\\r\\n
\\r\\n \\t\\t`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n一般data-*用来传递值类型,如string、number。值得注意的是,通过data-*接收到的数据类型都是string,需要自行转成number类型。\\r\\n通常情况下,data-*能满足我们的要求,但是遇到复杂的数据类型是没有办法通过大量data-*去表达,所以可以通过data通讯,请往下看。\\r\\n\\r\\n### data通讯 \\r\\n\\r\\n如上面代码所示,通过 data-name=\\"Omi\\"可以把name传递给子组件。下面的代码也可以达到同样的效果。\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.helloData = { name : \'Omi\' };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n使用data声明,会去组件的instance(也就是this)下找对应的属性,this下可以挂载任意复杂的对象。所以这也就突破了data-*的局限性。\\r\\n\\r\\n如果instance下面的某个属性下面的某个属性下面的某个数组的第一个元素的某个属性要作为data传递Hello怎么办?\\r\\n没关系,data声明是支持复杂类型的,使用方式如下:\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n点击这里→data映射复杂数据\\r\\n\\r\\n### childrenData通讯\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.childrenData = [{ name : \'Omi\' } , { name : \'dntzhang\' }];\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n使用this.childrenData传递data给子组件,childrenData是一个数组类型,所以支持同时给多个组件传递data,与render里面的组件会一一对应上。\\r\\n\\r\\n### group-data通讯\\r\\n\\r\\nchildrenData的方式可以批量传递数据给组件,但是有很多场景下data的来源不一定非要都从childrenData来,childrenData是个数组,会和组件的顺序一一对应,这就给不同传递方式的data必须全部集中的childrenData中,非常不方便。group-data专门为解决上面的痛点而生,专门是为了给一组组件批量传递data。\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.testData = [{name: \'Omi\'}, {name: \'dntzhang\'}, {name: \'AlloyTeam\'}];\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n只需要在声明的子组件上标记group-data,就会去当前组件的instance(也就是this)下面找对应的属性,然后根据当前的位置,和对应数组的位置会一一对应起来。\\r\\n\\r\\n运行结果如下:\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170216110701535-1698390390.png)\\r\\n\\r\\n点击这里→group-data\\r\\n\\r\\n同样group-data支持复杂数据类型的映射,需要注意的是,group-data映射的终点必须是一个数组:\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n点击这里→group-data映射复杂数据\\r\\n\\r\\n### 通过对象实例\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n this.hello.data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n### 通过omi-id\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n Omi.get(\\"hello\\").data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n通过在组件上声明omi-id,在程序任何地方拿到该对象的实例。这个可以算是跨任意组件通讯神器。\\r\\n\\r\\n### 特别强调\\r\\n\\r\\n* 通过childrenData或者data方式通讯都是一锤子买卖。后续变更只能通过组件实例下的data属性去更新组件\\r\\n* 通过data-✼通讯也是一锤子买卖。后续变更只能通过组件实例下的data属性去更新组件。\\r\\n* 关于data-✼通讯也可以不是一锤子买卖,但是要设置组件实例的dataFirst为false,这样的话data-✼就会覆盖组件实例的data对应的属性\\r\\n\\r\\n关于上面的第三条也就是这样的逻辑伪代码:\\r\\n```js\\r\\nif(this.dataFirst){\\r\\n this.data = Object.assign({},data-✼ ,this.data);\\r\\n}else{\\r\\n this.data = Object.assign({},this.data, data-✼);\\r\\n}\\r\\n```"'},function(n,e){n.exports='module.exports = "

组件

\\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)完全基于组件体系设计,我们希望开发者可以像搭积木一样制作Web程序,一切皆是组件,组件也可以嵌套子组件形成新的组件,新的组件又可以当作子组件嵌套至任意组件形成新的组件...\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170210093427338-1536910080.png)\\r\\n\\r\\n## 简单组件\\r\\n\\r\\n这里使用Todo的例子来讲解Omi组件体系的使用。\\r\\n\\r\\n```js\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.data.items.push(this.data.text);\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
\\r\\n

TODO

\\r\\n
    {{#items}}
  • {{.}}
  • {{/items}}
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Todo({ items: [] ,text : \'\' }),\\"body\\");\\r\\n```\\r\\n\\r\\n组件生成的HTML最终会插入到body中。上面的例子展示了Omi的部分特性:\\r\\n\\r\\n- data传递: new Todo(data,..)的data可以直接提供给render方法里的模板\\r\\n- 局部CSS: h3只对render里的h3生效,不会污染外面的h3;button也是同样的\\r\\n- 声明式事件绑定: onchange调用的就是组件内的handleChange,this可以拿到当然的DOM元素,还可以拿到当前的event\\r\\n- 需要手动调用update方法才能更新组件\\r\\n\\r\\n这里需要特别强调的是,为了更加的自由和灵活度。Omi没有内置数据变更的自动更新,需要开发者自己调用update方法。\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n## 组件嵌套\\r\\n\\r\\n如果页面超级简单的话,可以没有组件嵌套。但是绝大部分Web网页或者Web应用,需要嵌套定义的组件来完成所有的功能和展示。比如上面的Todo,我们也是可以抽取出List。\\r\\n这样让程序易维护、可扩展、方便复用。如,我们抽取出List:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    {{#items}}
  • {{.}}
  • {{/items}}
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n怎么使用这个List?我们需要使用Omi.makeHTML把List制作成可以声明式的标签,在render方法中就能直接使用该标签。如下所示:\\r\\n\\r\\n```js\\r\\nimport List from \'./list.js\';\\r\\n\\r\\nOmi.makeHTML(\'List\', List);\\r\\n\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.data.length = this.data.items.length;\\r\\n this.listData = { items : this.data.items };\\r\\n }\\r\\n\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.list.data.items.push(this.data.text);\\r\\n this.data.length = this.list.data.items.length;\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
\\r\\n

TODO

\\r\\n \\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n* 第3行,通过makeHTML方法把组件制作成可以在render中使用的标签。当然Omi.makeHTML(\'List\', List);也可以写在List组件的代码下面。\\r\\n* 第9行,在父组件上定义listData属性用来传递给子组件。\\r\\n* 第34行,在render方法中使用List组件。其中name方法可以让你在代码里通过this快速方法到该组件的实例。data=\\"listData\\"可以让你把this.listData传递给子组件。\\r\\n\\r\\n需要注意的是,父组件的this.listData会被通过Object.assign浅拷贝到子组件。\\r\\n这样做的目的主要是希望以后DOM的变更都尽量修改子组件自身的data,然后再调用其update方法,而不是去更改父组件的listData。\\r\\n\\r\\n关于Omi组件通讯其实有4种方案,这个后续教程会专门来讲。\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports="module.exports = \"

条件判断

\\r\\n\\r\\n我们经常需要根据不同的状态呈现不同的界面,比如有的用户是vip要显示vip的Logo。Omi有许多种方式满足你的要求。\\r\\n\\r\\n### 方式一\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `{{#isVip}}\\r\\n
you are VIP.
\\r\\n {{/isVip}}\\r\\n {{^isVip}}\\r\\n
you are not VIP.
\\r\\n {{/isVip}}`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n上面完全使用mustachejs的条件判断的语法。当然Omi不强制你使用mustachejs。你可以是omi.lite.js,然后重写Omi.template方法去使用任意你喜爱的模板引擎。\\r\\n\\r\\n### 方式二\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
you are VIP.
';\\r\\n }else{\\r\\n return '
you are not VIP.
';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nrender就是提供了很好的可编程性,里面可以写任意js逻辑代码。对了,差点忘了,style方法里面也可以写js逻辑的。\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style (){\\r\\n if(this.data.isVip){\\r\\n return 'div{ color : red; }';\\r\\n }else{\\r\\n return 'div{ color : green; }';\\r\\n }\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
you are VIP.
';\\r\\n }else{\\r\\n return '
you are not VIP.
';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\""},function(n,e){n.exports='module.exports = "

事件处理

\\r\\n\\r\\nOmi的事件分内置事件和自定义事件。在内置事件处理方面巧妙地利用了浏览器自身的管线机制,可以通过event和this轻松拿到事件实例和触发该事件的元素。\\r\\n\\r\\n### 内置事件\\r\\n\\r\\n什么算内置事件?只要下面正则能匹配到就算内置事件。\\r\\n\\r\\n```js\\r\\non(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave)\\r\\n```\\r\\n\\r\\n内置事件怎么绑定?如下所示:\\r\\n\\r\\n```js\\r\\nclass EventTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n handleClick(dom, evt){\\r\\n alert(dom.innerHTML);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
Hello, Omi!
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 自定义事件\\r\\n\\r\\n开发者自己定义的组件的事件,称为自定义事件,自定义事件必须以on开头,即onXXXX的格式,不然Omi识别不到。这里拿分页作为例子:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\nimport Pagination from \'./pagination.js\';\\r\\nimport Content from \'./content.js\';\\r\\n\\r\\nOmi.makeHTML(\'Pagination\', Pagination);\\r\\nOmi.makeHTML(\'Content\', Content);\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.content.goto(this.pagination.data.currentPage+1);\\r\\n }\\r\\n handlePageChange(index){\\r\\n this.content.goto(index+1);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
\\r\\n

Pagination Example

\\r\\n \\r\\n \\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render( new Main(),\'body\');\\r\\n```\\r\\n\\r\\n如上面的onPageChange就是自定义事件,触发会执行handlePageChange。onPageChange方法是在Pagination中执行:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\n\\r\\nclass Pagination extends Omi.Component {\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n linkTo: \\"#\\",\\r\\n prevText: \\"Prev\\",\\r\\n nextText: \\"Next\\",\\r\\n ellipseText: \\"...\\",\\r\\n prevShow: true,\\r\\n nextShow: true,\\r\\n onPageChange: function () { return false; }\\r\\n }, this.data);\\r\\n\\r\\n this.pageNum = Math.ceil(this.data.total / this.data.pageSize);\\r\\n }\\r\\n goto (index,evt) {\\r\\n evt.preventDefault();\\r\\n this.data.currentPage=index;\\r\\n this.update();\\r\\n this.data.onPageChange(index);\\r\\n }\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\n这里取了Pagination组件的部分代码。高亮的就是执行onPageChange的地方。\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/pagination/)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/pagination)\\r\\n"'},function(n,e){n.exports='module.exports = "

表单

\\r\\n\\r\\nOmi让一些表单操控起来更加方便,特别是select!\\r\\n\\r\\n### select标签\\r\\n\\r\\n以前,我们需要像如下的方式选中一个选项:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n第三个option由于加上了selected,所有会被选中。这样带来的问题就是,开发者写的程序可能要操遍历每个option。而使用Omi,你只需要这样子:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n这样就能达到同样的效果。比如你想选择第一项:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n是不是非常方便?\\r\\n\\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass FormTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n \\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n console.log(target.value)\\r\\n this.data.value = target.value;\\r\\n }\\r\\n\\r\\n handleSubmit(evt) {\\r\\n alert(\'Your favorite flavor is: \' + this.data.value);\\r\\n evt.preventDefault();\\r\\n }\\r\\n \\r\\n render () {\\r\\n return `\\r\\n
\\r\\n \\r\\n \\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new FormTest({ value: \'mango\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

获取DOM节点

\\r\\n\\r\\n虽然绝大部分情况下,开发者不需要去查找获取DOM,但是还是有需要获取DOM的场景,所以Omi提供了方便获取DOM节点的方式。\\r\\n\\r\\n### ref和refs\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(){\\r\\n alert(this.refs.abc.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n

Hello ,{{name}}!

\\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\n可以看到通过在HTML中标记ref为abc,那么就通过this.refs.abc访问到该DOM节点。\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

Hello World

\\r\\n\\r\\n你可以使用ES6+或者ES5的方式编写Omi程序来搭建你的Web程序。\\r\\n\\r\\n### Hello World with ES6+\\r\\n\\r\\n你可以使用 [webpack](https://webpack.github.io/) 打包工具,webpack会把你的模块代码打成一个很小的包,优化加载时间。使用[babel](http://babeljs.io/),让你立刻马上使用ES6+来编写你的web程序。你只需要在webpack配置的module设置好[babel-loader](https://github.com/babel/babel-loader)便可。\\r\\n\\r\\n一个Omi的简短的例子如下所示:\\r\\n\\r\\n```js\\r\\nimport Omi from \'./omi.js\';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n

Hello ,{{name}}!

\\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\n组件生成的HTML最终会插入到#container中。上面的例子展示了Omi的部分特性:\\r\\n\\r\\n- data传递: new Hello(data,..)的data可以直接提供给render方法里的模板\\r\\n- 局部CSS: h1只对render里的h1生效,不会污染外面的h1\\r\\n- 声明式事件绑定: onclick调用的就是组件内的handleClick,this可以拿到当前的DOM元素,还可以拿到当前的event\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n你可以使用Omi.makeHTML来生成组件标签用于嵌套。\\r\\n```js\\r\\n Omi.makeHTML(\'Hello\', Hello);\\r\\n```\\r\\n那么你就在其他组件中使用,如\\r\\n```js\\r\\n ...\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n
Test
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n ...\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### Hello World with ES5\\r\\n\\r\\n当然Omi没有抛弃ES5的用户。你可以使用ES5的方式编写Omi。如,在你的HTML中引用omi.js:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n然后:\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\", {\\r\\n style: function () {\\r\\n return \\"h1{ cursor:pointer }\\";\\r\\n },\\r\\n handleClick: function (dom) {\\r\\n alert(dom.innerHTML)\\r\\n },\\r\\n render: function () {\\r\\n return \'
\\\\\\r\\n

\\\\\\r\\n Hello ,{{name}}!\\\\\\r\\n

\\\\\\r\\n
\'\\r\\n }\\r\\n});\\r\\n\\r\\nvar Test = Omi.create(\\"Test\\", {\\r\\n render: function () {\\r\\n return \'
\\\\\\r\\n
Test
\\\\\\r\\n \\\\\\r\\n
\'\\r\\n }\\r\\n});\\r\\n\\r\\nOmi.render(new Test(),\'#container\');\\r\\n```\\r\\n当然除了在HTML引入脚本,你还可以使用AMD、CMD或者CommonJS的方式引入Omi,这里就不再一一列举。\\r\\n\\r\\n需要注意的是,Omi.create的第一个参数Hello是用来生成Tag Name的。你可以在其他地方嵌入你的组件。如:\\r\\n\\r\\n```js\\r\\n ...\\r\\n render:function() {\\r\\n return \'
\\\\\\r\\n \\\\\\r\\n
Test XXXX
\\\\\\r\\n \\\\\\r\\n
\';\\r\\n }\\r\\n ...\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports='module.exports = "

继承

\\r\\n\\r\\n通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。\\r\\n\\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n div{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return \'
Hello {{name}}!
\'\\r\\n }\\r\\n}\\r\\n\\r\\nclass SubHello extends Hello {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### ES5下的继承\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\",{\\r\\n render:function(){\\r\\n return \'
Hello {{name}}!
\'\\r\\n }\\r\\n})\\r\\n\\r\\nvar SubHello = Omi.create(\\"SubHello\\",Hello,{ });\\r\\n\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

安装

\\n\\n[Omi](https://github.com/AlloyTeam/omi)(读音 / [ˈomɪ] /, 汉字类似于 欧米) 是一款用于创建用户界面的组件化框架,开放并且现代,故得名:Omi。\\n\\n### 安装 Omi\\n\\n我们推荐使用 [npm](https://www.npmjs.com/) 来管理你的前端依赖.\\n\\n通过npm安装Omi,你只需要执行下面的命令:\\n\\n``` js\\nnpm install omi\\n```\\n\\n## omi-cli\\n\\n你也可以通过omi-cli去初始化你的项目:\\n\\n``` js\\n$ npm install omi-cli -g //安装cli\\n$ omi init your_project_name //初始化项目,你也可以在一个空的文件夹下执行 omi init\\n$ cd your_project_name //如果你是在空文件夹下执行的 omi init。请无视这条命令\\n$ npm run dev //开发\\n$ npm run dist //部署发布\\n```"'},function(n,e){n.exports='module.exports = "

生命周期

\\r\\n\\r\\n|name |avatars |company | \\r\\n|---|---|---|\\r\\n| constructor | 构造函数 | new的时候 |\\r\\n| install | 初始化安装,这可以拿到用户传进的data进行处理 | 实例化 |\\r\\n| installed | 安装完成,HTML已经插入页面之后执行 | 实例化 |\\r\\n| uninstall | 卸载组件。执行remove方法会触发该事件 | 销毁时 |\\r\\n| beforeUpdate | 更新前 | 存在期 |\\r\\n| afterUpdate | 更新后 | 存在期 |\\r\\n\\r\\n## 示意图\\r\\n\\r\\n![lc](http://images2015.cnblogs.com/blog/105416/201701/105416-20170119153018546-1566368987.png)\\r\\n \\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass Timer extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n install () {\\r\\n this.data = {secondsElapsed: 0};\\r\\n }\\r\\n\\r\\n tick() {\\r\\n this.data.secondsElapsed++;\\r\\n this.update();\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.interval = setInterval(() => this.tick(), 1000);\\r\\n }\\r\\n\\r\\n uninstall() {\\r\\n clearInterval(this.interval);\\r\\n }\\r\\n\\r\\n\\r\\n style () {\\r\\n return `\\r\\n .num { color:red; }\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
Seconds Elapsed: {{secondsElapsed}}
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports='module.exports = "

循环遍历

\\r\\n\\r\\n下面介绍mustache.js的方式和javascript遍历的方式。\\r\\n\\r\\n### 方式一\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
\\r\\n
    \\r\\n {{#items}} \\r\\n
  • {{text}}
  • \\r\\n {{/items}}\\r\\n
\\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nmustache.js更详细的循环遍历使用可看[https://github.com/janl/mustache.js#non-empty-lists](https://github.com/janl/mustache.js#non-empty-lists)。 比如还支持:\\r\\n\\r\\n* 如果items的每一项是字符串,可以直接**{{.}}**的方式来输出每一项\\r\\n* 循环的时候调用定义好的函数\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### 方式二\\r\\n\\r\\n既然ES6+了,当然可以使用${ }以及Array的map方法: \\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `
\\r\\n
    \\r\\n ${this.data.items.map(item =>\\r\\n `
  • ${item.text}
  • `\\r\\n ).join(\'\')}\\r\\n
\\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\n你将在页面看到如下效果:\\r\\n\\r\\n![pv](http://images2015.cnblogs.com/blog/105416/201701/105416-20170122095724129-2059595233.png)\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports="module.exports = \"

插件体系

\\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi)是Web组件化框架,怎么又来了个插件的概念?\\r\\n\\r\\n可以这么理解: Omi插件体系可以赋予dom元素一些能力,并且可以和组件的实例产生关联。\\r\\n\\r\\n### omi-drag\\r\\n\\r\\n且看这个例子:\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n```js\\r\\nimport OmiDrag from './omi-drag.js';\\r\\n\\r\\nOmiDrag.init();\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n
Drag Me
\\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n\\r\\n style(){\\r\\n return `\\r\\n .test{\\r\\n width:100px;\\r\\n height:100px;\\r\\n color:white;\\r\\n line-height:90px;\\r\\n text-align:center;\\r\\n background-color:#00BFF3;\\r\\n }\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n如上面的代码所示,通过在div上标记omi-drag,这个div就能够被用户使用鼠标拖拽。我们称omi-drag.js为omi插件。\\r\\n是不是非常方便?那么这个omi-drag是怎么实现的?\\r\\n\\r\\n## Omi.extendPlugin\\r\\n\\r\\n核心方法: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n下面的代码就是展示了如何通过 Omi.extendPlugin 赋予dom拖拽的能力:\\r\\n\\r\\n```js\\r\\n;(function () {\\r\\n\\r\\n var OmiDrag = {};\\r\\n var Omi = typeof require === 'function'\\r\\n ? require('omi')\\r\\n : window.Omi;\\r\\n\\r\\n OmiDrag.init = function(){\\r\\n Omi.extendPlugin('omi-drag',function(dom, instance){\\r\\n dom.style.cursor='move';\\r\\n var isMouseDown = false,\\r\\n preX = null,\\r\\n preY = null,\\r\\n currentX = null,\\r\\n currentY = null,\\r\\n translateX = 0,\\r\\n translateY = 0;\\r\\n\\r\\n dom.addEventListener('mousedown',function(evt){\\r\\n isMouseDown = true;\\r\\n preX = evt.pageX;\\r\\n preY = evt.pageY;\\r\\n evt.stopPropagation();\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n }\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mouseup',function(){\\r\\n isMouseDown = false;\\r\\n preX = preY = currentX = currentY = null;\\r\\n },false);\\r\\n });\\r\\n }\\r\\n\\r\\n OmiDrag.destroy = function(){\\r\\n delete Omi.plugins['omi-drag'];\\r\\n };\\r\\n\\r\\n if (typeof exports == \\\"object\\\") {\\r\\n module.exports = OmiDrag;\\r\\n } else if (typeof define == \\\"function\\\" && define.amd) {\\r\\n define([], function(){ return OmiDrag });\\r\\n } else {\\r\\n window.OmiDrag = OmiDrag;\\r\\n }\\r\\n\\r\\n})();\\r\\n```\\r\\n\\r\\n方法: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n其中pluginName为插件的名称\\r\\n其中handler为处理器。handler可以拿到标记了pluginName的dom以及dom所在的组件的实例,即 dom 和 instance。\\r\\n\\r\\n通过 Omi.extendPlugin,可以赋予dom元素一些能力,也可以和组件的实例(instance)产生关联。\\r\\n但是上面的例子没有和instance产生关联,我们接下来试试:\\r\\n\\r\\n## 关联instance\\r\\n\\r\\n我们想在组件里面能够监听到move并且执行回调。如下:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandler(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
\\r\\n
Drag Me
\\r\\n
\\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n主要被拖动过程中,moveHandler就不断地被执行。插件代码需要修改:\\r\\n\\r\\n```js\\r\\n...\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance.moveHandler(evt);\\r\\n }\\r\\n},false);\\r\\n```\\r\\n\\r\\n我们在里面增加了instance.moveHandler(evt);方法,用来执行组件实例上的moveHandler方法。\\r\\n这样的话:就是组件的实例(instance)产生关联。但是还是有问题?如果标记了多个omi-drag 就会有问题!如:\\r\\n\\r\\n```js\\r\\n...\\r\\nrender() {\\r\\n return `\\r\\n
\\r\\n
Drag Me
\\r\\n
Drag Me
\\r\\n
\\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n通常我们系统每个omi-drag都能对应一个回调函数,如:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
\\r\\n
Drag Me A
\\r\\n
Drag Me B
\\r\\n
\\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n怎么办?怎么实现?有办法!通过dom传递数据给插件。\\r\\n\\r\\n## 传递数据\\r\\n\\r\\n先来看最后实现的效果:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
\\r\\n
Drag Me A
\\r\\n
Drag Me B
\\r\\n
\\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nomi-drag修改的地方:\\r\\n\\r\\n```js\\r\\n...\\r\\nvar handlerName = dom.getAttribute('dragMove');\\r\\n\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance[handlerName](evt);\\r\\n }\\r\\n},false);\\r\\n...\\r\\n```\\r\\n\\r\\n* 通过 var handlerName = dom.getAttribute('dragMove') 拿到dom上声明的dragMove\\r\\n* 通过 instance[handlerName](evt) 去执行对应的方法\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n## 更多插件\\r\\n\\r\\n* [omi-finger](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-finger) Omi的[AlloyFinger](https://github.com/AlloyTeam/AlloyFinger)插件,支持各种触摸事件和手势\\r\\n* [omi-transform](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-transform) Omi的[transformjs](http://alloyteam.github.io/AlloyTouch/transformjs/)插件,快速方便地设置DOM的CSS3 Transform属性\\r\\n* [omi-touch](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-touch) Omi的[AlloyTouch](https://github.com/AlloyTeam/AlloyTouch)插件,Omi项目的触摸运动解决方案(支持触摸滚动、旋转、翻页、选择等等)\\r\\n* [omi-jquery-date-picker](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-jquery-date-picker) Omi的时间选择插件,支持各种时间或者时间区域选择\\r\\n\""; -},function(n,e){n.exports='module.exports = "## 写在前面\\r\\nOmi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。\\r\\n\\r\\n项目开始之前,实现选择一个脚手架。这个项目用的就是[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)\\r\\n\\r\\nGulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)\\r\\n\\r\\n\\r\\n所以,要使用Fiddler并配置Extention:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)\\r\\n\\r\\n\\r\\n## 目录\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)\\r\\n\\r\\n\\r\\n目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。\\r\\n组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。\\r\\n\\r\\n## 命令\\r\\n\\r\\n开发\\r\\n```js\\r\\nnpm run dev\\r\\n```\\r\\n\\r\\n发布\\r\\n```js\\r\\nnpm run dist\\r\\n```\\r\\n\\r\\n## 开始写码\\r\\n\\r\\n万事具备,开始写码。先写组件:\\r\\n\\r\\n```js\\r\\nimport Omi from \'omi\'\\r\\n\\r\\nclass UserList extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n install() {\\r\\n this.data.uin_info || (this.data.uin_info = [])\\r\\n this.data.uin_info.forEach(user => {\\r\\n this.prepareData(user)\\r\\n })\\r\\n }\\r\\n \\r\\n prepareData(user){\\r\\n user.desc_d = user.desc.split(\\" \\")[0]\\r\\n user.desc_t = user.desc.split(\\" \\")[1]\\r\\n user.isBoy = user.sex === \\"男\\"\\r\\n user.qlogo = user.url.replace(\\"http://\\", location.protocol + \\"//\\").replace(/&/g, \\"&\\")\\r\\n if (user.profession_desc) {\\r\\n user.hasProfession_desc = true\\r\\n }\\r\\n }\\r\\n \\r\\n appendUsers (users) {\\r\\n users.uin_info && users.uin_info.forEach(user =>{\\r\\n this.prepareData(user)\\r\\n this.data.uin_info.push(user)\\r\\n })\\r\\n this.update()\\r\\n }\\r\\n\\r\\n sendGift(uin, nick, qlogo) {\\r\\n //送礼物并关闭webview,此处省略\\r\\n //..\\r\\n //..\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n {{#uin_info}}\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n
\\r\\n
{{{nick}}}
\\r\\n
\\r\\n {{#isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{^isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{#hasProfession_desc}} {{profession_desc}} {{/hasProfession_desc}}\\r\\n
\\r\\n
{{{intro}}}
\\r\\n
\\r\\n
{{desc_d}} · {{desc_t}}
\\r\\n
\\r\\n {{/uin_info}}\\r\\n
加载中...
\\r\\n
\\r\\n`\\r\\n }\\r\\n\\r\\n style() {\\r\\n return `\\r\\n\\r\\n\\r\\n.qlogo {\\r\\n overflow: hidden;\\r\\n width: 70px;\\r\\n height: 70px;\\r\\n -webkit-border-radius: 50%;\\r\\n border-radius: 50%;\\r\\n position: absolute;\\r\\n top: 10px;\\r\\n left: 12px;\\r\\n}\\r\\n...\\r\\n...\\r\\n..这里省略大量.....\\r\\n...\\r\\n...\\r\\n\\r\\n.distance_info {\\r\\n position: absolute;\\r\\n top: 15px;\\r\\n right: 9px;\\r\\n color: #7B7B84;\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nexport default UserList\\r\\n```\\r\\n\\r\\n组件里面有5个方法:\\r\\n\\r\\n* constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this\\r\\n* install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理\\r\\n* prepareData 对数据进行一些处理来满足模板的渲染\\r\\n* appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用\\r\\n* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..\\r\\n\\r\\n其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。\\r\\nrender里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;\\r\\n如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。\\r\\n\\r\\n这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)\\r\\n\\r\\n\\r\\n下面来看index.js:\\r\\n\\r\\n```js\\r\\nimport Root from \'./config.js\'\\r\\nimport Omi from \'omi\'\\r\\nimport UserList from \'../component/user_list/index.js\'\\r\\n\\r\\nOmi.makeHTML(\'UserList\', UserList)\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n installed() {\\r\\n window.onscroll = () => this.loadMore()\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n\\r\\n loadMore() {\\r\\n const body = document.body,\\r\\n html = document.documentElement,\\r\\n height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),\\r\\n vp_height = window.innerHeight\\r\\n\\r\\n if (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n }\\r\\n\\r\\n requestData(callback) {\\r\\n if (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }else{\\r\\n \\t//ajax 请求数据,这里省略\\r\\n }\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
`\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Main(),\'body\')\\r\\n```\\r\\n\\r\\n通过Omi.makeHTML(\'UserList\', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:\\r\\n\\r\\n```js\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
`\\r\\n }\\r\\n```\\r\\n\\r\\n下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。\\r\\n\\r\\n```js\\r\\nwindow.onscroll = () => this.loadMore()\\r\\n```\\r\\n\\r\\n通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:\\r\\n\\r\\n```js\\r\\nif (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n}\\r\\n```\\r\\n\\r\\nrequestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。\\r\\n慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:\\r\\n\\r\\n```js\\r\\n \\r\\n```\\r\\n\\r\\n上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!\\r\\n\\r\\n再来看下数据模拟:\\r\\n\\r\\n```js\\r\\nif (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }\\r\\n```\\r\\n\\r\\n这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!\\r\\n\\r\\n## 最后\\r\\n\\r\\n好了,就这么多,Omi让代码真心方便简洁~~~\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)"'},function(n,e){n.exports='module.exports = "

模板切换

\\r\\n\\r\\nOmi有三个版本。其中的omi.js和omi.lite.js属于Web端使用的版本。\\r\\n\\r\\n* omi.js内置了[mustache.js](https://github.com/janl/mustache.js)作为模版引擎\\r\\n* omi.lite.js不包含任何模版引擎\\r\\n\\r\\nOmi不强制开发者使用mustache.js,你可以根据业务场景使用任意模板引擎或者不使用模板引擎。\\r\\n\\r\\n那么怎么使用别的模板引擎?下面拿[artTemplate](https://github.com/aui/artTemplate)作为例子。\\r\\n\\r\\n### 使用artTemplate\\r\\n\\r\\n```js\\r\\nOmi.template = function(tpl, data){\\r\\n return artTemplate.compile(tpl)(data);\\r\\n}\\r\\n```\\r\\n重写Omi.template方法,tpl为传入的模板,data为模板所需的数据,返回值为HTML。\\r\\n重写完毕后就能在render使用artTemplate的语法,如:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h1 { color:red; }\\r\\n li{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `

{{title}}

\\r\\n
    \\r\\n {{each list as value i}}\\r\\n
  • 索引 {{i + 1}} :{{value}}
  • \\r\\n {{/each}}\\r\\n
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/artTemplate/)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/artTemplate)"'},function(n,e){n.exports='module.exports = "

Omi的理念

\\r\\n\\r\\nOmi的理念是基于面向对象编程体系,内建积木系统。\\r\\n 传统的单向数据流或者抛出event的组件通讯方式增加了系统的稳定性,但是丧失了灵活性。一定程度上也降低了组建的复用。所谓鱼和熊掌不可兼得。\\r\\n 面向对象体系需要多一个逻辑层,可以自由操作所有组件的instance,instance之间的逻辑关系构建出了整个程序。这样组建间的逻辑,通信,复用就全部迎刃而解。组建也更加单一职责,更松耦合。\\r\\n\\r\\n对比函数式编程、命令式编程与面向对象编程,可以归纳总结出下面几条:\\r\\n\\r\\n- 命令式编程干脆直接,利用循环条件等控制流程,强调执行过程\\r\\n- 命令式编程对硬件执行友好,运行更容易,却阻碍了复杂程序的设计\\r\\n- 函数式强调输入和输出,并非执行过程\\r\\n- 函数式倡导多个简单执行单元组合成复杂运算程序\\r\\n- 面向对象编程将对象作为程序的基本单元,更具有重用性、灵活性和扩展性\\r\\n\\r\\nJavascript是哪种类型的语言?现在ES6+已经有了class。那么他是面向对象语言?\\r\\n但是JS可以在任意地方定义函数并且当作把函数当作值来传递。那么他是函数式编程语言?\\r\\n所以,没有精准的定义,取决于你的用法和姿势。其次,Web组件化架构层面编程模型和语言层面编程模型是非常自由的关系。意思就是,你可以用Javascript构建函数式编程框架如React,也可以基于面向对象体系搭建Omi。\\r\\n\\r\\n### 函数式编程 VS 面向对象编程\\r\\n\\r\\n在UI组件框架层面,函数式编程的代表有React,Omi属于面向对象编程体系。那么他们各有什么优缺点?下面做了个对比(其实也是函数式编程与面向对象编程的对比):\\r\\n\\r\\n| | React | Omi |\\r\\n| ------------- |:-------------:|:-----:|\\r\\n| 组件通信 | ★★★★☆| ★★★★★ |\\r\\n| 稳定性 | ★★★★★ | ★★★★☆ |\\r\\n| 灵活性 | ★★★★☆| ★★★★★ |\\r\\n| 扩展性 | ★★★★☆ | ★★★★★ |\\r\\n| 测试性 | ★★★★★ | ★★★★☆ |\\r\\n| 文件大小 | ★★★☆☆ | ★★★★★ |\\r\\n| 功能特性 | ★★★☆☆ | ★★★★☆ |\\r\\n| DOM性能 | ★★★★★ | ★★★★☆ |\\r\\n| 动画性能 | ★★★★☆ | ★★★★★ |\\r\\n| 抽象复杂度 | ★★★★☆ | ★★★★★ |\\r\\n| 异步编程 | ★★★★★ | ★★★★☆ |\\r\\n\\r\\n可以看得出,鱼和熊掌不可兼得。面向对象编程更具有重用性、灵活性和扩展性,带来的问题就是更加难测试。\\r\\n具体来说,如函数式编程,其测试面积是state1 + state2 + ... + stateN;在面向对象编程中,其测试面积是state1×event1 + state2×event2 + ... + stateN×eventN。\\r\\n\\r\\n总结来说,更加推荐使用面向对象的方式去搭建UI组件化框架。\\r\\n\\r\\n
\\r\\n\\r\\n### 全文结束,感谢阅读。[开始Omi之旅吧!](https://github.com/AlloyTeam/omi) \\r\\n\\r\\n"'},function(n,e){n.exports='module.exports = "# 深入Omi\\r\\n\\r\\n(待续...)\\r\\n\\r\\n* [环境搭建](./cn_env.md)\\r\\n* [Hello Omi](./cn_hello.md)\\r\\n* [手Q附近Web页Omi实战](./cn_nearby.md)\\r\\n* 局部CSS揭秘\\r\\n* 组件嵌套揭秘\\r\\n* 事件处理揭秘\\r\\n* 服务器端渲染揭秘\\r\\n* 模板切换揭秘\\r\\n* 容器系统揭秘"'},function(n,e){n.exports='module.exports = "

环境搭建

\\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)使用 Webpack + ES6 的方式去开发;使用karma+jasmine来作为Omi的测试工具。\\r\\n\\r\\n## Karma介绍\\r\\n\\r\\nKarma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner)。该工具可用于测试所有主流Web浏览器,也可集成到CI(Continuous integration)工具,也可和其他代码编辑器一起使用。这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行。但是集成到travis ci要把singleRun设置成true,让其只执行一遍。\\r\\n\\r\\n## Jasmine介绍\\r\\nJasmine 是一款 JavaScript BDD(行为驱动开发)测试框架,它不依赖于其他任何 JavaScript 组件。它有干净清晰的语法,让您可以很简单的写出测试代码。\\r\\n\\r\\n## 开发依赖包\\r\\n\\r\\n在package.json中,有如下配置:\\r\\n\\r\\n```js\\r\\n \\"devDependencies\\": {\\r\\n \\"babel-core\\": \\"^6.0.20\\",\\r\\n \\"babel-loader\\": \\"^6.0.1\\",\\r\\n \\"babel-preset-es2015\\": \\"^6.0.15\\",\\r\\n \\"node-libs-browser\\": \\"^0.5.3\\",\\r\\n \\"webpack\\": \\"^1.14.0\\",\\r\\n \\"jasmine-core\\": \\"^2.5.2\\",\\r\\n \\"karma\\": \\"^1.3.0\\",\\r\\n \\"karma-chrome-launcher\\": \\"^2.0.0\\",\\r\\n \\"karma-jasmine\\": \\"^1.1.0\\",\\r\\n \\"karma-webpack\\": \\"^1.8.1\\"\\r\\n }\\r\\n```\\r\\n\\r\\n* ES6+相关依赖有babel-core、babel-loader和babel-preset-es2015\\r\\n\\r\\n在webpack.config.js中配置js文件使用babel-loader编译。\\r\\n```js\\r\\nloaders: [\\r\\n {\\r\\n loader: \'babel-loader\',\\r\\n test: /\\\\.js$/,\\r\\n query: {\\r\\n presets: \'es2015\',\\r\\n }\\r\\n }\\r\\n]\\r\\n```\\r\\n\\r\\n* webpack相关依赖有node-libs-browser和webpack\\r\\n* 其余都是单元测试相关依赖\\r\\n\\r\\n 注意,这里使用了karma-webpack。因为使用Omi框架支持ES6+和ES5,使用karma-webpack是为了在单元测试里面使用ES6+的import和Class等语法。\\r\\n\\r\\n在karma.conf.js中配置webpack:\\r\\n\\r\\n```js\\r\\n webpack: webpackConfig,\\r\\n webpackMiddleware:{\\r\\n noInfo:false\\r\\n },\\r\\n plugins: [\\r\\n \'karma-webpack\',\\r\\n \'karma-jasmine\',\\r\\n \'karma-chrome-launcher\'\\r\\n ]\\r\\n```\\r\\n\\r\\n具体配置看test目录下的[karma.conf.js](https://github.com/AlloyTeam/omi/blob/master/test/karma.conf.js)和[webpack.test.config.js](https://github.com/AlloyTeam/omi/blob/master/test/webpack.test.config.js)便可。\\r\\n\\r\\n注意,karma.conf.js需要设置\\r\\n\\r\\n```js\\r\\n// if true, Karma captures browsers, runs the tests and exits\\r\\nsingleRun: true,\\r\\n```\\r\\n\\r\\n不然,travis ci脚本执行的时候不会中断导致执行超时异常。\\r\\n\\r\\n## npm 脚本\\r\\n\\r\\n```js\\r\\n \\"scripts\\": {\\r\\n \\"build\\": \\"webpack -w\\",\\r\\n \\"test\\": \\"karma start test/karma.conf.js\\",\\r\\n \\"hello\\": \\"webpack -w\\",\\r\\n \\"todo\\": \\"webpack -w\\"\\r\\n }\\r\\n```\\r\\n\\r\\n其中:\\r\\n* npm run build : 生成dist目录的omi.js文件\\r\\n* npm run test : 执行单元测试\\r\\n* npm run hello : 编译hello的demo\\r\\n* npm run todo : 编译todo的demo\\r\\n\\r\\n在webpack.config.js中,会根据 process.env.npm_lifecycle_event去设置不同的入口文件。所以同样是执行webpack -w,执行结果可以不一样。\\r\\n\\r\\n来看下build的相关webpack配置:\\r\\n\\r\\n```js\\r\\nif(ENV === \'build\'){\\r\\n config = {\\r\\n entry: {\\r\\n omi: \'./src/index.js\'\\r\\n },\\r\\n output: {\\r\\n path: \'dist/\',\\r\\n library:\'Omi\',\\r\\n libraryTarget: \'umd\',\\r\\n filename: \'[name].js\'\\r\\n },\\r\\n```\\r\\n\\r\\n这里把libraryTarget设置成了umd,webpack会帮助我们build出umd的Omi。\\r\\n\\r\\n如果是打包demo(npm run hello 和 npm run todo)的话,会进入下面的条件判断:\\r\\n\\r\\n```js\\r\\nelse {\\r\\n config.entry = \'./example/\' + ENV + \'/main.js\';\\r\\n config.output.path = \'./example/\' + ENV + \'/\';\\r\\n}\\r\\n```\\r\\n\\r\\n会去example下对应的目录查找main.js作为webpack入口文件。\\r\\n\\r\\n这里可以看到,我们不仅用webpack build出Omi框架,也使用webpack build所有demo。\\r\\n详细配置参考[webpack.config.js](https://github.com/AlloyTeam/omi/blob/master/webpack.config.js)的配置。\\r\\n\\r\\n## 参考文档\\r\\n\\r\\n* [http://www.cnblogs.com/cqhaibin/p/5867125.html](http://www.cnblogs.com/cqhaibin/p/5867125.html)\\r\\n* [https://karma-runner.github.io/latest/intro/installation.html](https://karma-runner.github.io/latest/intro/installation.html)\\r\\n* [https://karma-runner.github.io/latest/intro/configuration.html](https://karma-runner.github.io/latest/intro/configuration.html)\\r\\n\\r\\n"'},function(n,e){n.exports="module.exports = \"

Hello Omi

\\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)的每个组件都继承自Omi.Component,本篇会去完成Omi的Component的基本锥形,让其能够渲染第一个组件。\\r\\n\\r\\n## omi.js实现\\r\\n\\r\\n```js\\r\\nvar Omi = {};\\r\\nOmi._instanceId = 0;\\r\\nOmi.getInstanceId = function () {\\r\\n return Omi._instanceId++;\\r\\n};\\r\\n\\r\\nOmi.render = function(component, renderTo){\\r\\n component.renderTo = typeof renderTo === \\\"string\\\" ? document.querySelector(renderTo) : renderTo;\\r\\n component._render();\\r\\n return component;\\r\\n};\\r\\n\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n* Omi.getInstanceId 用来给每个组件生成自增的ID\\r\\n* Omi.render 用来把组件渲染到页面\\r\\n\\r\\n## 基类Omi.Component实现\\r\\n\\r\\n所有的组件都是继承自Omi.Component。\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\n\\r\\nclass Component {\\r\\n constructor(data) {\\r\\n this.data = data || {};\\r\\n this.id = Omi.getInstanceId();\\r\\n this.HTML = null;\\r\\n this.renderTo = null;\\r\\n }\\r\\n\\r\\n _render() {\\r\\n this.HTML = this.render();\\r\\n this.renderTo.innerHTML = this.HTML;\\r\\n }\\r\\n}\\r\\n\\r\\nexport default Component;\\r\\n```\\r\\n\\r\\n* Omi使用完全面向对象的方式去开发组件,这里约定好带有下划线的方法是用于内部实现调用,不建议Omi框架的使用者去调用。\\r\\n* 其中,_render为私有方法用于内部实现调用,会去调用组件的真正render方法用于生成HTML,并且把生成的HTML插入到renderTo容器里面。\\r\\n* 注意,这里目前没有引入dom diff,不管第几次渲染都是无脑设置innerHTML,复杂HTML结构对浏览器的开销很大,这里后续会引入diff。\\r\\n\\r\\n## index.js整合\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi = Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n这里把Omi给直接暴露在window下,因为每个组件都生成了唯一的ID,后续实现事件作用域以及对象实例获取都要通过window下的Omi获取。\\r\\n\\r\\n## 最后使用\\r\\n\\r\\n实现完omi.js和component.js以及index.js之后,你就可以实现Hello Omi拉:\\r\\n\\r\\n```js\\r\\nimport Omi from 'index.js'; \\r\\n//或者使用webpack build之后的omi.js \\r\\n//import Omi from 'omi.js';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\t

Hello ,`+ this.data.name +`!

\\r\\n
\\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : 'Omi' }),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n什么?都2017年了还在拼接字符串?!虽然ES6+的template string让多行字符串拼接更加得心应手,但是template string+模板引擎可以让更加优雅方便。既然用了template string,也可以写成这样子:\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n

Hello ,${this.data.name}!

\\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : 'Omi' }),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n## 引入mustachejs模板引擎\\r\\n\\r\\nOmi支持任意模板引擎。可以看到,上面是通过拼接字符串的形式生成HTML,这里当然可以使用模板引擎。\\r\\n\\r\\n修改一下index.js:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Mustache from './mustache.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.template = Mustache.render;\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi=Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n这里把Mustache.render挂载在Omi.template下。再修改一下component.js:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\n\\r\\nclass Component {\\r\\n constructor(data) {\\r\\n this.data = data || {};\\r\\n this.id = Omi.getInstanceId();\\r\\n this.HTML = null;\\r\\n }\\r\\n\\r\\n _render() {\\r\\n this.HTML = Omi.template(this.render(), this.data);\\r\\n this.renderTo.innerHTML = this.HTML;\\r\\n }\\r\\n}\\r\\n\\r\\nexport default Component;\\r\\n```\\r\\n\\r\\nOmi.template(即Mustache.render)需要接受两个参数,第一个参数是模板,第二个参数是模板使用的数据。\\r\\n\\r\\n现在,你便可以使用mustachejs模板引擎的语法了:\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\t

Hello ,{{name}}!

\\r\\n
\\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n从上面的代码可以看到,你完全可以重写Omi.template方法去使用任意模板引擎。重写Omi.template的话,建议使用omi.lite.js,因为omi.lite.js是不包含任何模板引擎的。那么怎么build出两个版本的omi?且看webpack里设置的多入口:\\r\\n\\r\\n```js\\r\\n entry: {\\r\\n omi: './src/index.js',\\r\\n 'omi.lite': './src/index.lite.js'\\r\\n},\\r\\noutput: {\\r\\n path: 'dist/',\\r\\n library:'Omi',\\r\\n libraryTarget: 'umd',\\r\\n filename: '[name].js'\\r\\n},\\r\\n```\\r\\n\\r\\nindex.lite.js的代码如下:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.template = function(tpl, data){\\r\\n return tpl;\\r\\n}\\r\\n\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi=Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n可以看到Omi.template没有对tpl做任何处理直接返回,开发者可以重写该方法。\\r\\n\\r\\n## 总结\\r\\n\\r\\n到目前为止,已经实现了:\\r\\n\\r\\n* 第一个组件的渲染\\r\\n* 模板引擎的接入\\r\\n* 多入口打包omi.js和omi.lite.js\\r\\n\\r\\n下片,将介绍《Omi原理-局部CSS》,欢迎关注...\\r\\n\""},function(n,e){n.exports='module.exports = "## 写在前面\\r\\nOmi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。\\r\\n\\r\\n项目开始之前,实现选择一个脚手架。这个项目用的就是[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)\\r\\n\\r\\nGulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)\\r\\n\\r\\n\\r\\n所以,要使用Fiddler并配置Extention:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)\\r\\n\\r\\n\\r\\n## 目录\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)\\r\\n\\r\\n\\r\\n目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。\\r\\n组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。\\r\\n\\r\\n## 命令\\r\\n\\r\\n开发\\r\\n```js\\r\\nnpm run dev\\r\\n```\\r\\n\\r\\n发布\\r\\n```js\\r\\nnpm run dist\\r\\n```\\r\\n\\r\\n## 开始写码\\r\\n\\r\\n万事具备,开始写码。先写组件:\\r\\n\\r\\n```js\\r\\nimport Omi from \'omi\'\\r\\n\\r\\nclass UserList extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n install() {\\r\\n this.data.uin_info || (this.data.uin_info = [])\\r\\n this.data.uin_info.forEach(user => {\\r\\n this.prepareData(user)\\r\\n })\\r\\n }\\r\\n \\r\\n prepareData(user){\\r\\n user.desc_d = user.desc.split(\\" \\")[0]\\r\\n user.desc_t = user.desc.split(\\" \\")[1]\\r\\n user.isBoy = user.sex === \\"男\\"\\r\\n user.qlogo = user.url.replace(\\"http://\\", location.protocol + \\"//\\").replace(/&/g, \\"&\\")\\r\\n if (user.profession_desc) {\\r\\n user.hasProfession_desc = true\\r\\n }\\r\\n }\\r\\n \\r\\n appendUsers (users) {\\r\\n users.uin_info && users.uin_info.forEach(user =>{\\r\\n this.prepareData(user)\\r\\n this.data.uin_info.push(user)\\r\\n })\\r\\n this.update()\\r\\n }\\r\\n\\r\\n sendGift(uin, nick, qlogo) {\\r\\n //送礼物并关闭webview,此处省略\\r\\n //..\\r\\n //..\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n {{#uin_info}}\\r\\n
\\r\\n
\\r\\n \\r\\n
\\r\\n
\\r\\n
{{{nick}}}
\\r\\n
\\r\\n {{#isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{^isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{#hasProfession_desc}} {{profession_desc}} {{/hasProfession_desc}}\\r\\n
\\r\\n
{{{intro}}}
\\r\\n
\\r\\n
{{desc_d}} · {{desc_t}}
\\r\\n
\\r\\n {{/uin_info}}\\r\\n
加载中...
\\r\\n
\\r\\n`\\r\\n }\\r\\n\\r\\n style() {\\r\\n return `\\r\\n\\r\\n\\r\\n.qlogo {\\r\\n overflow: hidden;\\r\\n width: 70px;\\r\\n height: 70px;\\r\\n -webkit-border-radius: 50%;\\r\\n border-radius: 50%;\\r\\n position: absolute;\\r\\n top: 10px;\\r\\n left: 12px;\\r\\n}\\r\\n...\\r\\n...\\r\\n..这里省略大量.....\\r\\n...\\r\\n...\\r\\n\\r\\n.distance_info {\\r\\n position: absolute;\\r\\n top: 15px;\\r\\n right: 9px;\\r\\n color: #7B7B84;\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nexport default UserList\\r\\n```\\r\\n\\r\\n组件里面有5个方法:\\r\\n\\r\\n* constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this\\r\\n* install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理\\r\\n* prepareData 对数据进行一些处理来满足模板的渲染\\r\\n* appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用\\r\\n* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..\\r\\n\\r\\n其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。\\r\\nrender里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;\\r\\n如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。\\r\\n\\r\\n这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)\\r\\n\\r\\n\\r\\n下面来看index.js:\\r\\n\\r\\n```js\\r\\nimport Root from \'./config.js\'\\r\\nimport Omi from \'omi\'\\r\\nimport UserList from \'../component/user_list/index.js\'\\r\\n\\r\\nOmi.makeHTML(\'UserList\', UserList)\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n installed() {\\r\\n window.onscroll = () => this.loadMore()\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n\\r\\n loadMore() {\\r\\n const body = document.body,\\r\\n html = document.documentElement,\\r\\n height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),\\r\\n vp_height = window.innerHeight\\r\\n\\r\\n if (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n }\\r\\n\\r\\n requestData(callback) {\\r\\n if (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }else{\\r\\n \\t//ajax 请求数据,这里省略\\r\\n }\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
`\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Main(),\'body\')\\r\\n```\\r\\n\\r\\n通过Omi.makeHTML(\'UserList\', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:\\r\\n\\r\\n```js\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
`\\r\\n }\\r\\n```\\r\\n\\r\\n下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。\\r\\n\\r\\n```js\\r\\nwindow.onscroll = () => this.loadMore()\\r\\n```\\r\\n\\r\\n通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:\\r\\n\\r\\n```js\\r\\nif (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n}\\r\\n```\\r\\n\\r\\nrequestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。\\r\\n慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:\\r\\n\\r\\n```js\\r\\n \\r\\n```\\r\\n\\r\\n上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!\\r\\n\\r\\n再来看下数据模拟:\\r\\n\\r\\n```js\\r\\nif (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }\\r\\n```\\r\\n\\r\\n这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!\\r\\n\\r\\n## 最后\\r\\n\\r\\n好了,就这么多,Omi让代码真心方便简洁~~~\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)"'},function(n,e){n.exports='module.exports = "# Omi命令行界面omi-cli发布\\r\\n\\r\\n通常认为,命令行界面(CLI)没有图形用户界面(GUI)那么方便用户操作。但是CLI比GUI节约资源,在熟悉命令之后,CLI会比GUI更加高效地帮你完成想要的任务。\\r\\n\\r\\n下面来介绍下[pasturn](https://github.com/pasturn)童鞋为Omi开发的CLI的两种使用姿势:\\r\\n\\r\\n## 姿势一\\r\\n\\r\\n```js\\r\\n$ npm install omi-cli -g //安装cli\\r\\n$ omi init your_project_name //初始化项目\\r\\n$ cd your_project_name //转到项目目录\\r\\n$ npm run dev //开发\\r\\n$ npm run dist //部署发布\\r\\n```\\r\\n\\r\\n## 姿势二\\r\\n\\r\\n当我们在一个空文件夹的时候,可以执行下面的命令。\\r\\n\\r\\n```js\\r\\n$ npm install omi-cli -g //安装cli\\r\\n$ omi init //初始化项目\\r\\n$ npm run dev //开发\\r\\n$ npm run dist //部署发布\\r\\n```\\r\\n\\r\\n这里不用再去跳转目录了,当前目录就是项目的目录。\\r\\n\\r\\n## 安装过程截图\\r\\n\\r\\n安装omi-cli:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100545470-696026058.png)\\r\\n\\r\\n\\r\\n安装初始化项目omi init:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100554891-1802174132.png)\\r\\n\\r\\n上面的成功的界面。注意:初始化项目会自动安装相关的npm依赖包,所以时间较长,请耐心等待。\\r\\n安装完成之后,在项目目录下你可以看到下面的目录结构:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100755845-465268116.png)\\r\\n\\r\\n开发 npm run dev:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100601235-1477801934.png)\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100608985-921528126.png)\\r\\n\\r\\n如果,你看到了上面的界面,说明一切OK了。创建出来的项目主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。Gulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n## 后续\\r\\n\\r\\n更多脚手架模板以及更多功能的命令正在开发中,如果有什么意见或者建议欢迎让我们知道。\\r\\n\\r\\n## 相关\\r\\n\\r\\n* Omi的Github地址[https://github.com/AlloyTeam/omi](https://github.com/AlloyTeam/omi)\\r\\n* 如果想体验一下Omi框架,可以访问 [Omi Playground](http://alloyteam.github.io/omi/example/playground/)\\r\\n* 如果想使用Omi框架或者开发完善Omi框架,可以访问 [Omi使用文档](https://github.com/AlloyTeam/omi/tree/master/docs#omi使用文档)\\r\\n* 如果你想获得更佳的阅读体验,可以访问 [Docs Website](http://alloyteam.github.io/omi/website/docs.html)\\r\\n* 如果你懒得搭建项目脚手架,可以试试 [omi-cli](https://github.com/AlloyTeam/omi/tree/master/cli)\\r\\n* 如果你有Omi相关的问题可以 [New issue](https://github.com/AlloyTeam/omi/issues/new)\\r\\n* 如果想更加方便的交流关于Omi的一切可以加入QQ的Omi交流群(256426170)\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170208095745213-1049686133.png)"'},function(n,e){n.exports='module.exports = "

Component Communication

\\r\\n\\r\\nCommunication between [Omi](https://github.com/AlloyTeam/omi) components is very flexible, there are many options:\\r\\n\\r\\n- By declaring `data-*` on the component to pass data to child node\\r\\n- By declaring `data` on the component to pass data to child node (support complex data types mapping)\\r\\n- By declaring `childrenData` on parent component to automatically pass data to child node\\r\\n- By declaring `group-data` (support complex data types mapping)\\r\\n- It\'s completely object-oriented, you can easily get the object instance, then you can set the instance of the property or call the instance of the method\\r\\n\\r\\nLet\'s see some examples.\\r\\n\\r\\n### Communicate by `data-*`\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n \\tcursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\t

Hello ,{{name}}!

\\r\\n
\\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nGenerally `data-*` is used to pass value types such as string and number. It is worth noting that, through `data-*`, received data types are string. You need to manually transform it to the number type.\\r\\n\\r\\nNormally, communicate by `data-*` is enough, but sometimes we may need to use complex data types, then we can use `data` to communicate.\\r\\n\\r\\n### Communicate by `data`\\r\\n\\r\\nAs shown in the above code, name can be passed to the subcomponent by `data-name=\\"Omi\\"`. The following code can also achieve the same effect.\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.helloData = { name : \'Omi\' };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nUse the `data` tag, it will find the property from the component instance (that is, this), this can be mounted with any complex objects. This also broke the limitations of `data-*`.\\r\\n\\r\\nThen how do we pass `data` that is in a deep depth of the instance to the Hello? No worries, `data` tag can be a complex statement:\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nClick me for the complex data mapping\\r\\n\\r\\n### Communicate by `childrenData`\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.childrenData = [{ name : \'Omi\' } , { name : \'dntzhang\' }];\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nWe can use `this.childrenData` to transfer data to the sub-component. In this case, `childrenData` is an array, so it can pass data to multiple components in the same time. In the meanwhile, the data will be passed to components one by one.\\r\\n\\r\\n### Communicate by `group-data`\\r\\n\\r\\n`childrenData` can pass data to multiple components. However, there are many scenes where the source of data does not have to be from `childrenData`. `childrenData` is an array, and it should be the same order with the components, so that the data must all concentrated in `childrenData`, it\'s very inconvenient. `group-data` dedicated to solve the above pain points, specifically to pass data to a group of components.\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.testData = [{name: \'Omi\'}, {name: \'dntzhang\'}, {name: \'AlloyTeam\'}];\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n \\r\\n \\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nBy declaring a `group-data` tag in the sub-components, it will go to the current instance of the component (that is, `this`) to find the corresponding property. Then according to the current location, the data will pass to the positions one by one.\\r\\n\\r\\nThe results are as follows:\\r\\n\\r\\n![group-data results](http://images2015.cnblogs.com/blog/105416/201702/105416-20170216110701535-1698390390.png)\\r\\n\\r\\nClick me for the group-data example\\r\\n\\r\\nSimilarly, `group-data` supports the mapping of complex data types. It should be noted that the end of the group-data mapping must be an array:\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nClick me for the complex group-data mapping\\r\\n\\r\\n### By object instance\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n this.hello.data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n### By omi-id\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n Omi.get(\\"hello\\").data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
\\r\\n \\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nBy declaring `omi-id` on the component, we can get the instance of the object anywhere in the program. This can be regarded as any component communication artifacts.\\r\\n\\r\\n### Warm Tips\\r\\n\\r\\n- The data that passed by `childrenData` or `data` is shadow copied to sub-components. In order to update it, we need to update the `data` attribute of the component instance.\\r\\n- The data that passed by `data-*` is also shadow copied to sub-components. In order to update it, we need to update the `data` attribute of the component instance.\\r\\n- If we set the `dataFirst` property of the component instance to `false`, then `data-*` will override the `data` of component instance.\\r\\n\\r\\nFor the third tip, please checkout the pseudo-code:\\r\\n\\r\\n```js\\r\\nif(this.dataFirst){\\r\\n this.data = Object.assign({},data-✼ ,this.data);\\r\\n}else{\\r\\n this.data = Object.assign({},this.data, data-✼);\\r\\n}\\r\\n```"'; -},function(n,e){n.exports='module.exports = "

Components

\\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is based entirely on component architecture, which allows developers to build web applications like building blocks. Everything is components, components can be nested to create new components.\\r\\n\\r\\n![Omi Components System](http://images2015.cnblogs.com/blog/105416/201702/105416-20170210093427338-1536910080.png)\\r\\n\\r\\n### Simple Components\\r\\n\\r\\nLet\'s explore a simple Todo example to learn the components system in Omi.\\r\\n\\r\\n```js\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.data.items.push(this.data.text);\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
\\r\\n

TODO

\\r\\n
    {{#items}}
  • {{.}}
  • {{/items}}
\\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Todo({ items: [] ,text : \'\' }),\\"body\\");\\r\\n```\\r\\n\\r\\nThe HTML generated by the component will eventually be inserted into the body. The above example shows some of the features of Omi:\\r\\n\\r\\n- Data flow: `data` in `new Todo(data,..)` can be used directly in the template in render method.\\r\\n- Partial CSS: `h3` in `style()` only effect inside of render. It\'ll never pollute `h3` outside of this component. The same rule applies to `button`.\\r\\n- Declarative event binding: `onchange` will call `handleChange` that inside of the component. `this` refers to the current DOM element, `event` refers to the current DOM Event Object.\\r\\n- You need to manually call the `this.update()` method to update the component\\r\\n\\r\\nIt is important to note that, for more freedom and flexibility, Omi does not automatically update DOM while data changes. Developers need to call the `update` method manually.\\r\\n\\r\\nYou can also use [oba] (https://github.com/dntzhang/oba) or mobx to implement automatic updates.\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n## Component Nesting\\r\\n\\r\\nIt\'s ok to not use nesting component if your page is super simple. However, for most of webpages and web applications, it is a necessary to define the nesting Components to implement complex features.\\r\\n\\r\\nFor instance, we can extract a `List` component form the Todo example. This brings maintainable, scalable and reuseable to our project:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    {{#items}}
  • {{.}}
  • {{/items}}
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nThen how to use this `List`? We need to use `Omi.makeHTML` to make the `List` to a tag which can be used in render method:\\r\\n\\r\\n```js\\r\\nimport List from \'./list.js\';\\r\\n\\r\\nOmi.makeHTML(\'List\', List);\\r\\n\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.data.length = this.data.items.length;\\r\\n this.listData = { items : this.data.items };\\r\\n }\\r\\n\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.list.data.items.push(this.data.text);\\r\\n this.data.length = this.list.data.items.length;\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
\\r\\n

TODO

\\r\\n \\r\\n
\\r\\n \\r\\n \\r\\n
\\r\\n
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n- In line 3, we use `makeHTML` to make the component to a tag which can be used in render method. Of course, `Omi.makeHTML(\'List\', List);` can also be written in the end of List component.\\r\\n- In line 9, the parent component defines the \'listData\' property\\r\\n- In line 34, we use List component in the render method. `name` attribute allows us easily find the instance of the component by using `this`.`data=\\"listData\\"` attribute allows us easily pass `this.listData` to the sub component from parent component.\\r\\n\\r\\nIt should be noted that the `data` passed from `data=\\"listData\\"` is cloned to the subcomponents by Object.assign(shallow copy) , which means if we want to change the DOM, we recommend that first update the `data` of the instance of subcomponent(not the parent component\'s `listData` ) and secondly call the `update` method.\\r\\n\\r\\nIn fact there are 4 way to communicate between components, it\'ll be explained later.\\r\\n\\r\\nClick me for the live demo\\r\\n"'},function(n,e){n.exports="module.exports = \"

Conditional Rendering

\\r\\n\\r\\nIn most case, we need to show different layouts according to different states. For example, some users are vip and we need to show vip logo for them. Omi has many ways to meet this kind of requirements.\\r\\n\\r\\n### First Option\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `{{#isVip}}\\r\\n
you are VIP.
\\r\\n {{/isVip}}\\r\\n {{^isVip}}\\r\\n
you are not VIP.
\\r\\n {{/isVip}}`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nIn the above case, we use the condition in mustachejs for rendering. Of course Omi does not force you to use mustachejs. You can use omi.lite.js and then override the `Omi.template` method to use any of your favorite template engines.\\r\\n\\r\\n### Second Option\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
you are VIP.
';\\r\\n }else{\\r\\n return '
you are not VIP.
';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n`render` provides a very good programmability, which can write any js code inside. Oh, don't forget that `style` method can also have js code inside it.\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style (){\\r\\n if(this.data.isVip){\\r\\n return 'div{ color : red; }';\\r\\n }else{\\r\\n return 'div{ color : green; }';\\r\\n }\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
you are VIP.
';\\r\\n }else{\\r\\n return '
you are not VIP.
';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\""},function(n,e){n.exports='module.exports = "

Handling Events

\\r\\n\\r\\nThere are two types of events in Omi, built-in events and custom events. Built-in events clever use of the browser\'s own pipeline mechanism, you can easily get events instance and the triggered event elements through `event` and `this`.\\r\\n\\r\\n### Built-in events\\r\\n\\r\\nWhat is the built-in event? As long as the it can match the following regular expression.\\r\\n\\r\\n```js\\r\\non(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave)\\r\\n```\\r\\n\\r\\nHow to bind built-in events? As follows:\\r\\n\\r\\n```js\\r\\nclass EventTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n handleClick(dom, evt){\\r\\n alert(dom.innerHTML);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
Hello, Omi!
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### Custom events\\r\\n\\r\\nEvents that defined by developers is the custom events. Here is the pagination example:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\nimport Pagination from \'./pagination.js\';\\r\\nimport Content from \'./content.js\';\\r\\n\\r\\nOmi.makeHTML(\'Pagination\', Pagination);\\r\\nOmi.makeHTML(\'Content\', Content);\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.content.goto(this.pagination.data.currentPage+1);\\r\\n }\\r\\n handlePageChange(index){\\r\\n this.content.goto(index+1);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
\\r\\n

Pagination Example

\\r\\n \\r\\n \\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render( new Main(),\'body\');\\r\\n```\\r\\n\\r\\nAs we can see, the `onPageChange` is a custom event, `handlePageChange` will being executed when `onPageChange` is triggered. The `onPageChange` method is executed in `Pagination`:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\n\\r\\nclass Pagination extends Omi.Component {\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n linkTo: \\"#\\",\\r\\n prevText: \\"Prev\\",\\r\\n nextText: \\"Next\\",\\r\\n ellipseText: \\"...\\",\\r\\n prevShow: true,\\r\\n nextShow: true,\\r\\n onPageChange: function () { return false; }\\r\\n }, this.data);\\r\\n\\r\\n this.pageNum = Math.ceil(this.data.total / this.data.pageSize);\\r\\n }\\r\\n goto (index,evt) {\\r\\n evt.preventDefault();\\r\\n this.data.currentPage=index;\\r\\n this.update();\\r\\n this.data.onPageChange(index);\\r\\n }\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\nThis is a part of `Pagination` code. Highlight is the place to execute `onPageChange`.\\r\\n\\r\\n### Links\\r\\n\\r\\n- [Demo](http://alloyteam.github.io/omi/example/pagination/)\\r\\n- [Source](https://github.com/AlloyTeam/omi/tree/master/example/pagination)"'},function(n,e){n.exports='module.exports = "

Forms

\\r\\n\\r\\nIt\'s much more convenient to control forms in Omi, especially `\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n\\r\\n```\\r\\n\\r\\nThe third option is selected because it is being set to `selected` attribute. The problem is that developers need to traversed each option. While using Omi, you can write code like this:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\nThis will achieve the same effect. For example, you want to choose the first item:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\nIsn\'t it very convenient?\\r\\n\\r\\n### For Example\\r\\n\\r\\n```js\\r\\nclass FormTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n \\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n console.log(target.value)\\r\\n this.data.value = target.value;\\r\\n }\\r\\n\\r\\n handleSubmit(evt) {\\r\\n alert(\'Your favorite flavor is: \' + this.data.value);\\r\\n evt.preventDefault();\\r\\n }\\r\\n \\r\\n render () {\\r\\n return `\\r\\n
\\r\\n \\r\\n \\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new FormTest({ value: \'mango\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for a live demo"'},function(n,e){n.exports='module.exports = "

Get DOM

\\r\\n\\r\\nWhile most of the time, developers do not need to find the DOM, but sometimes is a need to get the DOM.\\r\\n\\r\\nOmi provides a way to get the DOM node.\\r\\n\\r\\n### ref and refs\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(){\\r\\n alert(this.refs.abc.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n

Hello ,{{name}}!

\\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\nAs we can see, by referencing `ref` as `abc` in HTML, the DOM node can be accessed through `this.refs.abc`.\\r\\n\\r\\nClick me for the live demo\\r\\n"'},function(n,e){n.exports='module.exports = "

Hello World

\\r\\n\\r\\n\\r\\n### Hello World with ES20XX \\r\\n\\r\\nWe recommend using a bundler like [webpack](https://webpack.github.io/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time.\\r\\n\\r\\nThe small Omi example looks like this:\\r\\n\\r\\n```js\\r\\nimport Omi from \'./omi.js\';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n

Hello ,{{name}}!

\\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"body\\");\\r\\n\\r\\n```\\r\\n\\r\\nThis code renders into body element. \\r\\n\\r\\n\\r\\n### Hello World with ES5\\r\\n\\r\\n\\r\\n```html\\r\\n\\r\\n```"'},function(n,e){n.exports='module.exports = "

Inheritance

\\r\\n\\r\\nThrough the inheritance mechanism, we can define new classes base on old classes. The new classes not only have newly defined members, but also have old members at the same time.\\r\\n\\r\\nWe call the existing class the base class, also known as the parent class. And the new class derived from the existing class is called a derived class, also known as a subclass.\\r\\n\\r\\n### For Example\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n div{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return \'
Hello {{name}}!
\'\\r\\n }\\r\\n}\\r\\n\\r\\nclass SubHello extends Hello {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n### inherit in ES5\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\",{\\r\\n render:function(){\\r\\n return \'
Hello {{name}}!
\'\\r\\n }\\r\\n})\\r\\n\\r\\nvar SubHello = Omi.create(\\"SubHello\\",Hello,{ });\\r\\n\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports='module.exports = "

Installation

\\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is open and modern framework for building user interfaces.\\r\\n\\r\\n### Installing Omi\\r\\n\\r\\nWe recommend using [npm](https://www.npmjs.com/) for managing front-end dependencies. If you\'re new to package managers.\\r\\n\\r\\nTo install Omi with npm, run:\\r\\n\\r\\n``` js\\r\\nnpm install omi\\r\\n```\\r\\n### omi-cli\\r\\n\\r\\n``` js\\r\\n$ npm install omi-cli -g \\r\\n$ omi init your_project_name \\r\\n$ cd your_project_name \\r\\n$ npm run dev \\r\\n$ npm run dist \\r\\n```"'},function(n,e){n.exports='module.exports = "

Lifecycle

\\r\\n\\r\\n| Name | Meaning | Occasion |\\r\\n| :-------------: | :-------------: | :-----: |\\r\\n| constructor | The constructor | When new a constructor |\\r\\n| install | The installation. We can process the data that user pass | When instantiate |\\r\\n| installed | Complete the installation. It\'ll trigger after HTML being inserted to the page. Please note that it\'ll trigger when component being removed and restored | **Instantiation and existence** |\\r\\n| uninstall | Uninstall the component. It\'ll trigger when remove is executed | When destroy |\\r\\n| beforeUpdate | Before update | When existence |\\r\\n| afterUpdate | After update | When existence |\\r\\n\\r\\n## Illustration\\r\\n\\r\\n![lc](http://images2015.cnblogs.com/blog/105416/201701/105416-20170119153018546-1566368987.png)\\r\\n\\r\\nIt should be noted that the installed will be executed during the instantiation, which is not shown above. For example, it\'ll executed when a component is removed and restored, or when the new component is being added.\\r\\n\\r\\n### Examples\\r\\n\\r\\n```js\\r\\nclass Timer extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n install () {\\r\\n this.data = {secondsElapsed: 0};\\r\\n }\\r\\n\\r\\n tick() {\\r\\n this.data.secondsElapsed++;\\r\\n this.update();\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.interval = setInterval(() => this.tick(), 1000);\\r\\n }\\r\\n\\r\\n uninstall() {\\r\\n clearInterval(this.interval);\\r\\n }\\r\\n\\r\\n\\r\\n style () {\\r\\n return `\\r\\n .num { color:red; }\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
Seconds Elapsed: {{secondsElapsed}}
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports='module.exports = "

Loop

\\r\\n\\r\\nThe following describes how to traverses in mustache.js and javascript.\\r\\n\\r\\n### First Option\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
\\r\\n
    \\r\\n {{#items}} \\r\\n
  • {{text}}
  • \\r\\n {{/items}}\\r\\n
\\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nMustache.js more detailed loop traversal use can see \\r\\n\\r\\nFor more details for traversal in mustache.js please view [https://github.com/janl/mustache.js#non-empty-lists](https://github.com/janl/mustache.js#non-empty-lists).\\r\\n\\r\\nFor example, it also support:\\r\\n\\r\\n- If each item of items is a string, you can directly use **{{.}}** to output each item\\r\\n- Call the defined function when looping\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n### Second Option\\r\\n\\r\\nOf course, you can also use template string inside the `map`:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `
\\r\\n
    \\r\\n ${this.data.items.map(item =>\\r\\n `
  • ${item.text}
  • `\\r\\n ).join(\'\')}\\r\\n
\\r\\n
`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nYou will see the following page:\\r\\n\\r\\n![pv](http://images2015.cnblogs.com/blog/105416/201701/105416-20170122095724129-2059595233.png)\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports="module.exports = \"

Plugin

\\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is a componentized web framework. Then what is plugin?\\r\\n\\r\\nIt can be understood that the Omi plugin system can give the dom element some ability and can be associated with the instance of the components.\\r\\n\\r\\n### omi-drag\\r\\n\\r\\nLet's see this example:\\r\\n\\r\\nClick me for the live deme\\r\\n\\r\\n```js\\r\\nimport OmiDrag from './omi-drag.js';\\r\\n\\r\\nOmiDrag.init();\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
\\r\\n
Drag Me
\\r\\n
\\r\\n `;\\r\\n\\r\\n }\\r\\n\\r\\n style(){\\r\\n return `\\r\\n .test{\\r\\n width:100px;\\r\\n height:100px;\\r\\n color:white;\\r\\n line-height:90px;\\r\\n text-align:center;\\r\\n background-color:#00BFF3;\\r\\n }\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\\"#container\\\");\\r\\n```\\r\\n\\r\\nAs shown above, by adding `omi-drag` attribute to the div, it can be dragged by the user using the mouse. We call omi-drag.js an omi plugin.\\r\\n\\r\\nIsn't it very convenient? So how did this omi-drag implement?\\r\\n\\r\\n如上面的代码所示,通过在div上标记omi-drag,这个div就能够被用户使用鼠标拖拽。我们称omi-drag.js为omi插件。\\r\\n是不是非常方便?那么这个omi-drag是怎么实现的?\\r\\n\\r\\n## Omi.extendPlugin\\r\\n\\r\\nCore method: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\nThe following code shows how to use `Omi.extendPlugin` to give dom the drap and drop ability:\\r\\n\\r\\n```js\\r\\n;(function () {\\r\\n\\r\\n var OmiDrag = {};\\r\\n var Omi = typeof require === 'function'\\r\\n ? require('omi')\\r\\n : window.Omi;\\r\\n\\r\\n OmiDrag.init = function(){\\r\\n Omi.extendPlugin('omi-drag',function(dom, instance){\\r\\n dom.style.cursor='move';\\r\\n var isMouseDown = false,\\r\\n preX = null,\\r\\n preY = null,\\r\\n currentX = null,\\r\\n currentY = null,\\r\\n translateX = 0,\\r\\n translateY = 0;\\r\\n\\r\\n dom.addEventListener('mousedown',function(evt){\\r\\n isMouseDown = true;\\r\\n preX = evt.pageX;\\r\\n preY = evt.pageY;\\r\\n evt.stopPropagation();\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n }\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mouseup',function(){\\r\\n isMouseDown = false;\\r\\n preX = preY = currentX = currentY = null;\\r\\n },false);\\r\\n });\\r\\n }\\r\\n\\r\\n OmiDrag.destroy = function(){\\r\\n delete Omi.plugins['omi-drag'];\\r\\n };\\r\\n\\r\\n if (typeof exports == \\\"object\\\") {\\r\\n module.exports = OmiDrag;\\r\\n } else if (typeof define == \\\"function\\\" && define.amd) {\\r\\n define([], function(){ return OmiDrag });\\r\\n } else {\\r\\n window.OmiDrag = OmiDrag;\\r\\n }\\r\\n\\r\\n})();\\r\\n```\\r\\n\\r\\nMethod: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n`pluginName` is the name of the plugin.\\r\\n\\r\\n`handler` is the processor. The handler can get the dom which marked as the `pluginName` and the instance of the component.\\r\\n\\r\\nWith `Omi.extendPlugin`, we can give the dom some ability, and can also be associated with the component instance.\\r\\n\\r\\nThe above example is not associated with the instance, let's try it:\\r\\n\\r\\n## Associated with instance\\r\\n\\r\\nWe want to be able to listen to the `move` inside the component and perform a callback. As follows:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandler(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
\\r\\n
Drag Me
\\r\\n
\\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nIn this case, the `moveHandler` will be continually executed while dragging. We can modify some code to solve this issue:\\r\\n\\r\\n```js\\r\\n...\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance.moveHandler(evt);\\r\\n }\\r\\n},false);\\r\\n```\\r\\n\\r\\nWe add `instance.moveHandler(evt)` method to execute the `moveHandler` method of component instance.\\r\\n\\r\\nThis is how associated with instance works.\\r\\n\\r\\nHowever, this may still have an issue if we add `omi-drag` to a list of `div`:\\r\\n\\r\\n```js\\r\\n...\\r\\nrender() {\\r\\n return `\\r\\n
\\r\\n
Drag Me
\\r\\n
Drag Me
\\r\\n
\\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nUsually each of our `omi-drag` can correspond to a callback function, such as:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
\\r\\n
Drag Me A
\\r\\n
Drag Me B
\\r\\n
\\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nHow to achieve this? We can pass the data to the plugin via dom.\\r\\n\\r\\n## Passing data\\r\\n\\r\\nLet's see the final code:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
\\r\\n
Drag Me A
\\r\\n
Drag Me B
\\r\\n
\\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nWhere `omi-drag` modified:\\r\\n\\r\\n```js\\r\\n...\\r\\nvar handlerName = dom.getAttribute('dragMove');\\r\\n\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance[handlerName](evt);\\r\\n }\\r\\n},false);\\r\\n...\\r\\n```\\r\\n\\r\\n- We use `var handlerName = dom.getAttribute('dragMove')` to get the `dragMove` of dom\\r\\n- We use `instance[handlerName](evt)` to execute the method\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n## More plugins\\r\\n\\r\\n* [omi-finger](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-finger) The [AlloyFinger](https://github.com/AlloyTeam/AlloyFinger) plugin for Omi, which support touch events and gustures\\r\\n* [omi-transform](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-transform) The [transformjs](http://alloyteam.github.io/AlloyTouch/transformjs/) plugin for Omi, which can easily set CSS3 Transform to DOM\\r\\n* [omi-touch](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-touch) The [AlloyTouch](https://github.com/AlloyTeam/AlloyTouch) plugin for Omi. The touch movement solution for Omi (support touch scroll, rotate, flip, select, etc.)\\r\\n* [omi-jquery-date-picker](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-jquery-date-picker) The date picker plugin for Omi, which support choose any time zone\\r\\n\""; -},function(n,e){n.exports='module.exports = "

Templates

\\r\\n\\r\\nThere are three types of Omi. omi.js and omi.lite.js is for web side.\\r\\n\\r\\n- omi.js has a built-in [mustache.js](https://github.com/janl/mustache.js) as the template engine\\r\\n- omi.lite.js doesn\'t have any template engines\\r\\n\\r\\nOmi does not force developers to use mustache.js, you can use any template engine based on business scenarios or do not use any template engines.\\r\\n\\r\\nHow to use other template engines? Let\'s see the [artTemplate](https://github.com/aui/artTemplate) example.\\r\\n\\r\\n### Use artTemplate\\r\\n\\r\\n```js\\r\\nOmi.template = function(tpl, data){\\r\\n return artTemplate.compile(tpl)(data);\\r\\n}\\r\\n```\\r\\n\\r\\nWe need to rewrite the `Omi.template` method, the `tpl` is the incoming template, the `data` is the required data for the template, and the return value is HTML.\\r\\n\\r\\nAfter rewriting, you can use the artTemplate syntax in `render`, such as:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h1 { color:red; }\\r\\n li{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `

{{title}}

\\r\\n
    \\r\\n {{each list as value i}}\\r\\n
  • # {{i + 1}} :{{value}}
  • \\r\\n {{/each}}\\r\\n
`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### Links\\r\\n\\r\\n* [Demo Link](http://alloyteam.github.io/omi/example/artTemplate/)\\r\\n* [Source Code](https://github.com/AlloyTeam/omi/tree/master/example/artTemplate)"'},function(n,e){n.exports='module.exports = "

Thinking in Omi

\\r\\n\\r\\nOmi is based on object-oriented programming, with plugin system.\\r\\n\\r\\nThe traditional one-way data flow or the event-throwing component communicating can increase the stability of the system, but it loses it\'s flexibility. To a certain extent also reduced the component reusing.\\r\\n\\r\\nObject-oriented system has an other logical layer, which let you control the instance of components. The logic between instances build the entire program.\\r\\n\\r\\nThen the issues like communication, reusing and logics between components are all solved.\\r\\n\\r\\n\\r\\nPlus, the component is also more single duty, more loosely coupled.\\r\\n\\r\\nFor functional programming, imperative programming and object-oriented programming, we can sum up the following list:\\r\\n\\r\\n- Imperative programming is well understood, we use loop and if-else condition to control processes, it emphasize the process of execution\\r\\n- Imperative programming is hardware friendly, easy to run, but hard to design complex program\\r\\n- Functional programming is all about input and output, not the process of execution\\r\\n- Functional programming advocates multiple simple execution units into complex operations\\r\\n- Object-oriented programming uses objects as the basic unit of the program, with more reusability, flexibility, and extensibility\\r\\n\\r\\nWhat kind of language is JavaScript? We have `class` in ES6+, so is JavaScript object-oriented language?\\r\\n\\r\\nJavaScript can pass a function as a argumant, so is JavaScript a functional language?\\r\\n\\r\\nThere are no right answer, it depands on how you use JavaScript.\\r\\n\\r\\nIt\'s free to chooce, you can use functional programming framework like React, or object-oriented framework like Omi. \\r\\n\\r\\n### Functional Programming VS Object-Oriented Programming\\r\\n\\r\\nIn the UI component framework scope, functional programming is represented by React, while Omi belongs to object-oriented programming.\\r\\n\\r\\nSo what are their strengths and weaknesses? The following is a comparison (in fact, functional programming and object-oriented programming comparison):\\r\\n\\r\\n| | React | Omi |\\r\\n| ------------- |:-------------:|:-----:|\\r\\n| Component communication | ★★★★☆| ★★★★★ |\\r\\n| Stability | ★★★★★ | ★★★★☆ |\\r\\n| Flexibility | ★★★★☆| ★★★★★ |\\r\\n| Scalability | ★★★★☆ | ★★★★★ |\\r\\n| Testability | ★★★★★ | ★★★★☆ |\\r\\n| File size | ★★★☆☆ | ★★★★★ |\\r\\n| Features | ★★★☆☆ | ★★★★☆ |\\r\\n| DOM performance | ★★★★★ | ★★★★☆ |\\r\\n| Animation performance | ★★★★☆ | ★★★★★ |\\r\\n| Abstract complexity | ★★★★☆ | ★★★★★ |\\r\\n| Asynchronous programming | ★★★★★ | ★★★★☆ |\\r\\n\\r\\nAs we can see, we can not have it both ways. Object-oriented programming is more reusable, flexible and scalable, the problem is more difficult to test.\\r\\n\\r\\nSpecifically, if the functional programming, the test area is state1 + state2 + ... + stateN; in object-oriented programming, the test area is state1 × event1 + state2 × event2 + ... + stateN × eventN.\\r\\n\\r\\nIn summary, it is more recommended to use the object-oriented programming to build UI component framework.\\r\\n\\r\\n
\\r\\n\\r\\n### The end. Thanks for reading. [Let\'s start the Omi journey](https://github.com/AlloyTeam/omi)!\\r\\n"'},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n @media only screen and (max-width: 768px) {\n .list{\n transform: translateX(-100%);\n background-color:white;\n\n -moz-transition: all .6s ease;\n -o-transition: all .6s ease;\n -webkit-transition: all .6s ease;\n transition: all .6s ease;\n }\n\n .list.show {\n -moz-transform: translateX(0%) translateZ(0);\n -ms-transform: translateX(0%) translateZ(0);\n -o-transform: translateX(0%) translateZ(0);\n -webkit-transform: translateX(0%) translateZ(0);\n transform: translateX(0%) translateZ(0);\n }\n }\n\n .list{\n width:200px;\n text-indent: 20px;\n border-right: 1px solid #eee;\n overflow-x: hidden;\n overflow-y: auto;\n position:fixed;\n top:45px;\n }\n .version{\n height:20px;\n }\n \n "}},{key:"render",value:function(){return'\n
\n
\n {{#items}} {{/items}}\n
'}}]),e}(d.default.Component);e.default=h},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n
  • {{title}}
  • \n {{#list}}\n
  • \n {{name}}\n
  • \n {{/list}}\n '}},{key:"style",value:function(){return"\n \n "}}]),e}(d.default.Component);e.default=c},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n .head{\n position:fixed;\n height:45px;\n line-height: 45px;\n border-bottom: 1px solid #eee;\n width:100%;\n background-color:#303030;\n z-index:100;\n\n }\n ul,li{\n display: inline-block;\n }\n .logo_box{\n width:100px;\n display: inline-block;\n text-align:center;\n line-height: 60px;\n }\n .menu a,.logo_box a{\n display: inline-block;\n height:45px;\n color:#ddd;\n }\n .menu{\n position: absolute;\n right:20px;\n }\n .menu li{\n margin-left:15px;\n }\n .logo_box a{\n font-size: 34px;\n font-weight: bold;\n color: #00bff3;\n padding: 0px 15px;\n line-height: 45px;\n cursor: pointer;\n }\n .menu a:hover{\n color: white;\n }\n\n .m_menu{\n position:fixed;\n display:none;\n }\n\n @media only screen and (max-width: 768px) {\n .menu li{\n display:none;\n }\n .menu .m_show{\n display:block;\n }\n\n .logo_box{\n display:inline-block;\n }\n\n .head{\n text-align:center;\n }\n\n .m_menu{\n\n top:0;\n left:0;\n display:block;\n width:50px;\n height:50px;\n padding-top: 6px;\n }\n .m_menu img{\n width:30px;\n }\n\n }\n \n "}},{key:"render",value:function(){return'\n
    \n \n
    \n Omi\n
    \n \n
    '}}]),e}(d.default.Component);e.default=m},function(n,e,r){var t,i,o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(){var a={},s=r(52),l=r(2),d=function(){},c=function(n,e,r){var t="on"+n.substring(0,1).toUpperCase()+n.substring(1),i=e.getAttribute(t);return null===i?d:r[i].bind(r)};a.init=function(){l.extendPlugin("omi-finger",function(n,e){e.alloyFinger&&e.alloyFinger.destroy();var r=new s(n,{touchStart:c("touchStart",n,e),touchMove:c("touchMove",n,e),touchEnd:c("touchEnd",n,e),touchCancel:c("touchCancel",n,e),multipointStart:c("multipointStart",n,e),multipointEnd:c("multipointEnd",n,e),tap:c("tap",n,e),doubleTap:c("doubleTap",n,e),longTap:c("longTap",n,e),singleTap:c("singleTap",n,e),rotate:c("rotate",n,e),pinch:c("pinch",n,e),pressMove:c("pressMove",n,e),swipe:c("swipe",n,e)});e.alloyFinger=r})},a.destroy=function(){delete l.plugins["omi-finger"]},"object"==o(e)?n.exports=a:(t=[],i=function(){return a}.apply(e,t),!(void 0!==i&&(n.exports=i)))}()},function(n,e,r){"use strict";var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(){function r(n){return Math.sqrt(n.x*n.x+n.y*n.y)}function i(n,e){return n.x*e.x+n.y*e.y}function o(n,e){var t=r(n)*r(e);if(0===t)return 0;var o=i(n,e)/t;return o>1&&(o=1),Math.acos(o)}function a(n,e){return n.x*e.y-e.x*n.y}function s(n,e){var r=o(n,e);return a(n,e)>0&&(r*=-1),180*r/Math.PI}function l(n,e){var r=new d(n);return r.add(e),r}var d=function(n){this.handlers=[],this.el=n};d.prototype.add=function(n){this.handlers.push(n)},d.prototype.del=function(n){n||(this.handlers=[]);for(var e=this.handlers.length;e>=0;e--)this.handlers[e]===n&&this.handlers.splice(e,1)},d.prototype.dispatch=function(){for(var n=0,e=this.handlers.length;n0&&this.delta<=250&&Math.abs(this.preTapPosition.x-this.x1)<30&&Math.abs(this.preTapPosition.y-this.y1)<30),this.preTapPosition.x=this.x1,this.preTapPosition.y=this.y1,this.last=this.now;var e=this.preV,t=n.touches.length;if(t>1){this._cancelLongTap(),this._cancelSingleTap();var i={x:n.touches[1].pageX-this.x1,y:n.touches[1].pageY-this.y1};e.x=i.x,e.y=i.y,this.pinchStartLen=r(e),this.multipointStart.dispatch(n)}this.longTapTimeout=setTimeout(function(){this.longTap.dispatch(n)}.bind(this),750)}},move:function(n){if(n.touches){var e=this.preV,t=n.touches.length,i=n.touches[0].pageX,o=n.touches[0].pageY;if(this.isDoubleTap=!1,t>1){var a={x:n.touches[1].pageX-i,y:n.touches[1].pageY-o};null!==e.x&&(this.pinchStartLen>0&&(n.scale=r(a)/this.pinchStartLen,this.pinch.dispatch(n)),n.angle=s(a,e),this.rotate.dispatch(n)),e.x=a.x,e.y=a.y}else null!==this.x2?(n.deltaX=i-this.x2,n.deltaY=o-this.y2):(n.deltaX=0,n.deltaY=0),this.pressMove.dispatch(n);this.touchMove.dispatch(n),this._cancelLongTap(),this.x2=i,this.y2=o,t>1&&n.preventDefault()}},end:function(n){if(n.changedTouches){this._cancelLongTap();var e=this;n.touches.length<2&&this.multipointEnd.dispatch(n),this.touchEnd.dispatch(n),this.x2&&Math.abs(this.x1-this.x2)>30||this.y2&&Math.abs(this.preV.y-this.y2)>30?(n.direction=this._swipeDirection(this.x1,this.x2,this.y1,this.y2),this.swipeTimeout=setTimeout(function(){e.swipe.dispatch(n)},0)):(this.tapTimeout=setTimeout(function(){e.tap.dispatch(n),e.isDoubleTap&&(e.doubleTap.dispatch(n),clearTimeout(e.singleTapTimeout),e.isDoubleTap=!1)},0),e.isDoubleTap||(e.singleTapTimeout=setTimeout(function(){e.singleTap.dispatch(n)},250))),this.preV.x=0,this.preV.y=0,this.scale=1,this.pinchStartLen=null,this.x1=this.x2=this.y1=this.y2=null}},cancel:function(n){clearTimeout(this.tapTimeout),clearTimeout(this.singleTapTimeout),clearTimeout(this.longTapTimeout),clearTimeout(this.swipeTimeout),this.touchCancel.dispatch(n)},_cancelLongTap:function(){clearTimeout(this.longTapTimeout)},_cancelSingleTap:function(){clearTimeout(this.singleTapTimeout)},_swipeDirection:function(n,e,r,t){return Math.abs(n-e)>=Math.abs(r-t)?n-e>0?"Left":"Right":r-t>0?"Up":"Down"},on:function(n,e){this[n]&&this[n].add(e)},off:function(n,e){this[n]&&this[n].del(e)},destroy:function(){return this.tapTimeout&&clearTimeout(this.tapTimeout),this.singleTapTimeout&&clearTimeout(this.singleTapTimeout),this.longTapTimeout&&clearTimeout(this.longTapTimeout),this.swipeTimeout&&clearTimeout(this.swipeTimeout),this.element.removeEventListener("touchstart",this.start),this.element.removeEventListener("touchmove",this.move),this.element.removeEventListener("touchend",this.end),this.element.removeEventListener("touchcancel",this.cancel),this.rotate.del(),this.touchStart.del(),this.multipointStart.del(),this.multipointEnd.del(),this.pinch.del(),this.swipe.del(),this.tap.del(),this.doubleTap.del(),this.longTap.del(),this.singleTap.del(),this.pressMove.del(),this.touchMove.del(),this.touchEnd.del(),this.touchCancel.del(),this.preV=this.pinchStartLen=this.scale=this.isDoubleTap=this.delta=this.last=this.now=this.tapTimeout=this.singleTapTimeout=this.longTapTimeout=this.swipeTimeout=this.x1=this.x2=this.y1=this.y2=this.preTapPosition=this.rotate=this.touchStart=this.multipointStart=this.multipointEnd=this.pinch=this.swipe=this.tap=this.doubleTap=this.longTap=this.singleTap=this.pressMove=this.touchMove=this.touchEnd=this.touchCancel=null,null}},"undefined"!=typeof n&&"object"===t(e)?n.exports=c:window.AlloyFinger=c}()},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n {{#preName}} ←{{preName}}{{/preName}}\n {{#nextName}} {{/nextName}}\n ':'\n
    \n {{#preName}} ←{{preName}}{{/preName}}\n {{#nextName}} {{/nextName}}\n
    '}},{key:"style",value:function(){return"\n \n "}}]),e}(d.default.Component);e.default=h}]); \ No newline at end of file +!function(r,s){"object"===a(e)&&e&&"string"!=typeof e.nodeName?s(e):(i=[e],t=s,o="function"==typeof t?t.apply(e,i):t,!(void 0!==o&&(n.exports=o)))}(void 0,function(n){function e(n){return"function"==typeof n}function r(n){return g(n)?"array":"undefined"==typeof n?"undefined":a(n)}function t(n){return n.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function i(n,e){return null!=n&&"object"===("undefined"==typeof n?"undefined":a(n))&&e in n}function o(n,e){return v.call(n,e)}function s(n){return!o(b,n)}function l(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return y[n]})}function d(e,r){function i(){if(v&&!b)for(;f.length;)delete h[f.pop()];else f=[];v=!1,b=!1}function o(n){if("string"==typeof n&&(n=n.split(w,2)),!g(n)||2!==n.length)throw new Error("Invalid tags: "+n);a=new RegExp(t(n[0])+"\\s*"),l=new RegExp("\\s*"+t(n[1])),d=new RegExp("\\s*"+t("}"+n[1]))}if(!e)return[];var a,l,d,p=[],h=[],f=[],v=!1,b=!1;o(r||n.tags);for(var y,k,j,C,S,M,H=new m(e);!H.eos();){if(y=H.pos,j=H.scanUntil(a))for(var L=0,D=j.length;L0?o[o.length-1][4]:t;break;default:i.push(e)}return t}function m(n){this.string=n,this.tail=n,this.pos=0}function p(n,e){this.view=n,this.cache={".":this.view},this.parent=e}function h(){this.cache={}}var f=Object.prototype.toString,g=Array.isArray||function(n){return"[object Array]"===f.call(n)},v=RegExp.prototype.test,b=/\S/,y={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},x=/\s*/,w=/\s+/,O=/\s*=/,_=/\s*\}/,T=/#|\^|\/|>|\{|&|=|!/;m.prototype.eos=function(){return""===this.tail},m.prototype.scan=function(n){var e=this.tail.match(n);if(!e||0!==e.index)return"";var r=e[0];return this.tail=this.tail.substring(r.length),this.pos+=r.length,r},m.prototype.scanUntil=function(n){var e,r=this.tail.search(n);switch(r){case-1:e=this.tail,this.tail="";break;case 0:e="";break;default:e=this.tail.substring(0,r),this.tail=this.tail.substring(r)}return this.pos+=e.length,e},p.prototype.push=function(n){return new p(n,this)},p.prototype.lookup=function(n){var r,t=this.cache;if(t.hasOwnProperty(n))r=t[n];else{for(var o,a,s=this,l=!1;s;){if(n.indexOf(".")>0)for(r=s.view,o=n.split("."),a=0;null!=r&&a"===o?a=this.renderPartial(i,e,r,t):"&"===o?a=this.unescapedValue(i,e):"name"===o?a=this.escapedValue(i,e):"text"===o&&(a=this.rawValue(i)),void 0!==a&&(s+=a);return s},h.prototype.renderSection=function(n,r,t,i){function o(n){return s.render(n,r,t)}var s=this,l="",d=r.lookup(n[1]);if(d){if(g(d))for(var c=0,u=d.length;c",this.HTML):(this._mergeData(n),this._generateHTMLCSS(),this._extractChildren(this),e&&this.children.forEach(function(n,e){r._omi_order[e]=e}),this.children.forEach(function(n,e){r.HTML=r.HTML.replace(n._omiChildStr,r.children[r._omi_order[e]].HTML)}),this.HTML=(0,u.default)(this.HTML,this.id),this.HTML)}},{key:"_queryElements",value:function(n){n._mixRefs(),n._execPlugins(),n.children.forEach(function(e){e.node=n.node.querySelector("["+s.default.STYLESCOPEDPREFIX+e.id+"]"),n._queryElements(e)})}},{key:"_mixRefs",value:function(){var n=this,e=s.default.$$("*[ref]",this.node);e.forEach(function(e){e.hasAttribute(n._omi_scoped_attr)&&(n.refs[e.getAttribute("ref")]=e)});var r=this.node.getAttribute("ref");r&&(this.refs[r]=this.node)}},{key:"_execPlugins",value:function(){var n=this;Object.keys(s.default.plugins).forEach(function(e){var r=s.default.$$("*["+e+"]",n.node);r.forEach(function(r){r.hasAttribute(n._omi_scoped_attr)&&s.default.plugins[e](r,n)}),n.node.hasAttribute(e)&&s.default.plugins[e](n.node,n)})}},{key:"_childrenInstalled",value:function(n){var e=this;n.children.forEach(function(n){e._childrenInstalled(n),n.installed()})}},{key:"_fixForm",value:function(){s.default.$$("input",this.node).forEach(function(n){var e=n.type.toLowerCase();""===n.getAttribute("value")&&(n.value=""),"checked"!==e&&"radio"!==e||(n.hasAttribute("checked")?n.checked="checked":n.checked=!1)}),s.default.$$("textarea",this.node).forEach(function(n){n.value=n.getAttribute("value")}),s.default.$$("select",this.node).forEach(function(n){var e=n.getAttribute("value");if(e)s.default.$$("option",n).forEach(function(n){e===n.getAttribute("value")&&n.setAttribute("selected","selected")});else{var r=s.default.$$("option",n)[0];r&&r.setAttribute("selected","selected")}})}},{key:"_replaceTags",value:function(n,e){var r=n.join("|"),t=new RegExp("<("+r+"+)((?:\\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*)\\s*(\\/?)>","g");return e.replace(t,function(n,e){var r=n.length-2;return r>=0&&n.lastIndexOf("/>")===n.length-2?n.replace("<"+e,'":n.lastIndexOf(">")===n.length-1?n.replace("<"+e,'":void 0})}},{key:"_createHiddenNode",value:function(){var n=document.createElement("input");return n.setAttribute("type","hidden"),n.setAttribute(this._omi_scoped_attr,""),n}},{key:"_mergeData",value:function(n){this.dataFirst?this.data=Object.assign({},this._getDataset(n),this.data):this.data=Object.assign({},this.data,this._getDataset(n))}},{key:"_generateHTMLCSS",value:function(){this.CSS=(this.style()||"").replace(/<\/?style>/g,""),this.CSS&&(this.CSS=d.default.scoper(this.CSS,"["+this._omi_scoped_attr+"]"),this.CSS===this._preCSS||this._omi_server_rendering||(d.default.addStyle(this.CSS,this.id),this._preCSS=this.CSS));var n=this.render();this.HTML=this._scopedAttr(s.default.template(n?n:"",this.data),this._omi_scoped_attr).trim(),this._omi_server_rendering&&(this.HTML='\r\n\r\n"+this.HTML,this.HTML+='\r\n\r\n")}},{key:"_scopedAttr",value:function(n,e){return n.replace(/<[^\/]([A-Za-z]*)[^>]*>/g,function(n){var r=n.split(" ")[0].replace(">","");return n.replace(r,r+" "+e)})}},{key:"_getDataset",value:function(n){var e=this,r=(0,f.default)(n),t=r.child[0].attr;return Object.keys(t).forEach(function(n){0===n.indexOf("data-")&&(e._dataset[e._capitalize(n.replace("data-",""))]=t[n])}),this._dataset}},{key:"_capitalize",value:function(n){return n=n.toLowerCase(),n=n.replace(/\b\w+\b/g,function(n){return n.substring(0,1).toUpperCase()+n.substring(1)}).replace(/-/g,""),n.substring(0,1).toLowerCase()+n.substring(1)}},{key:"_extractPropertyFromString",value:function(n,e){var r=n.replace(/['|"|\]]/g,"").replace(/\[/g,".").split("."),t=e;return r.forEach(function(n){t=t[n]}),r=null,t}},{key:"_extractChildren",value:function(n){var e=this;s.default.customTags.length>0&&(n.HTML=this._replaceTags(s.default.customTags,n.HTML));var r=n.HTML.match(/][\s\S]*?tag=['|"](\S*)['|"][\s\S]*?><\/child>/g);r&&r.forEach(function(r,t){var i=(0,f.default)(r),o=i.child[0].attr,a=o.tag;delete o.tag;var l=e.children[t];l&&l.___omi_constructor_name===a?l._childRender(r):!function(){var i={},d={},c={},u={},m=null,p=null;Object.keys(o).forEach(function(r){var t=o[r];if(0===r.indexOf("on")){var a=n[t];a&&(i[r]=a.bind(n))}else"omi-id"===r?m=t:"name"===r?p=t:"group-data"===r?(n._omiGroupDataCounter.hasOwnProperty(t)?n._omiGroupDataCounter[t]++:n._omiGroupDataCounter[t]=0,u=e._extractPropertyFromString(t,n)[n._omiGroupDataCounter[t]]):0===r.indexOf("data-")?d[e._capitalize(r.replace("data-",""))]=t:"data"===r&&(c=e._extractPropertyFromString(t,n))});var h=s.default.getClassFromString(a);if(!h)throw"Can't find Class called ["+a+"]";var f=new h(Object.assign(i,n.childrenData[t],d,c,u),!1);f._omiChildStr=r,f.parent=n,f.___omi_constructor_name=a,f._dataset={},f.install(),m&&(s.default.mapping[m]=f),p&&(n[p]=f),l?n.children[t]=f:n.children.push(f),f._childRender(r,!0)}()})}}]),n}();e.default=g},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){var r=new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|s*{)","g");return n=n.replace(r,function(n,r,t){return r.match(/^\s*(@media|@keyframes|to|from|@font-face)/)?r+t:(r.match(/:scope/)&&(r=r.replace(/([^\s]*):scope/,function(n,e){return""===e?"> *":"> "+e})),r=r.replace(/^(\s*)/,r.trim()+e+",$1"+e+" ").replace(/\s+/g," "),r+t)})}function o(n,e){var r=document.getElementById(s.default.STYLEPREFIX+e),t=document.getElementsByTagName("head")[0];r&&r.parentNode===t&&t.removeChild(r);var i=document.createElement("style");t.appendChild(i),i.setAttribute("type","text/css"),i.setAttribute("id",s.default.STYLEPREFIX+e),window.ActiveXObject?i.styleSheet.cssText=n:i.textContent=n}Object.defineProperty(e,"__esModule",{value:!0});var a=r(3),s=t(a);e.default={scoper:i,addStyle:o}},function(n,e){"use strict";function r(n,e,r){return n.split(e).map(function(n){return n.replace(new RegExp(r,"g"),e)}).join(r)}function t(n){return JSON.stringify(n).replace(/(^"|"$)/g,"")}function i(n){return n=r(n,"'",'"'),r(t(n),"'",'"')}function o(n){return n.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function a(n,e){return String.prototype.endsWith?String.prototype.endsWith.call(n,e):n.substr(n.length-1,1)===e}function s(n,e){return n.replace(/<[\s\S]*?[^=]>/g,function(n){return n.replace(/on(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave|Abort|Blur|Cancel|CanPlay|CanPlayThrough|Change|Click|Close|ContextMenu|CueChange|DblClick|Drag|DragEnd|DragEnter|DragLeave|DragOver|DragStart|Drop|DurationChange|Emptied|Ended|Error|Focus|Input|Invalid|KeyDown|KeyPress|KeyUp|Load|LoadedData|LoadedMetadata|LoadStart|MouseDown|MouseEnter|MouseLeave|MouseMove|MouseOut|MouseOver|MouseUp|MouseWheel|Pause|Play|Playing|Progress|RateChange|Reset|Resize|Scroll|Seeked|Seeking|Select|Show|Stalled|Submit|Suspend|TimeUpdate|Toggle|VolumeChange|Waiting|AutoComplete|AutoCompleteError|BeforeCopy|BeforeCut|BeforePaste|Copy|Cut|Paste|Search|SelectStart|Wheel|WebkitFullScreenChange|WebkitFullScreenError|TouchStart|TouchMove|TouchEnd|TouchCancel|PointerDown|PointerUp|PointerCancel|PointerMove|PointerOver|PointerOut|PointerEnter|PointerLeave)=('|"|{)([\s\S]*)('|"|})/g,function(n,r,t,s,l){if(0===s.indexOf("Omi.instances[")||0===s.indexOf("new Function("))return n;if("{"===t){var d="("+s+").bind(Omi.instances["+e+"])(event)",c="on"+r+"=\"new Function('event', '"+o(i(d))+"')(event)\"";return c.split("\n").map(function(n){return a(n,";")?n:n+";"}).join("")}return s.match(/.*?\(.*?\)/)?n.replace(/=(['|"])/,"=$1Omi.instances["+e+"]."):n})})}Object.defineProperty(e,"__esModule",{value:!0}),e.default=s},function(n,e,r){var t,i,o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(a,s){"object"===o(e)&&"undefined"!=typeof n?n.exports=s():(t=s,i="function"==typeof t?t.call(e,r,e,n):t,!(void 0!==i&&(n.exports=i)))}(void 0,function(){"use strict";function n(n){!d&&m.createRange&&(d=m.createRange(),d.selectNode(m.body));var e;return d&&d.createContextualFragment?e=d.createContextualFragment(n):(e=m.createElement("body"),e.innerHTML=n),e.childNodes[0]}function e(n,e){var r=n.nodeName,t=e.nodeName;return r===t||!!(e.actualize&&r.charCodeAt(0)<91&&t.charCodeAt(0)>90)&&r===t.toUpperCase()}function r(n,e){return e&&e!==u?m.createElementNS(e,n):m.createElement(n)}function t(n,e){for(var r=n.firstChild;r;){var t=r.nextSibling;e.appendChild(r),r=t}return e}function i(n,e){var r,t,i,o,a,s,l=e.attributes;for(r=l.length-1;r>=0;--r)t=l[r],i=t.name,o=t.namespaceURI,a=t.value,o?(i=t.localName||i,s=n.getAttributeNS(o,i),s!==a&&n.setAttributeNS(o,i,a)):(s=n.getAttribute(i),s!==a&&n.setAttribute(i,a));for(l=n.attributes,r=l.length-1;r>=0;--r)t=l[r],t.specified!==!1&&(i=t.name,o=t.namespaceURI,o?(i=t.localName||i,h(e,o,i)||n.removeAttributeNS(o,i)):h(e,null,i)||n.removeAttribute(i))}function o(n,e,r){n[r]!==e[r]&&(n[r]=e[r],n[r]?n.setAttribute(r,""):n.removeAttribute(r,""))}function a(){}function s(n){return n.id}function l(i){return function(o,l,d){function c(n){O?O.push(n):O=[n]}function u(n,e){if(n.nodeType===g)for(var r=n.firstChild;r;){var t=void 0;e&&(t=_(r))?c(t):(M(r),r.firstChild&&u(r,e)),r=r.nextSibling}}function p(n,e,r){S(n)!==!1&&(e&&e.removeChild(n),M(n),u(n,r))}function h(n){if(n.nodeType===g)for(var e=n.firstChild;e;){var r=_(e);r&&(D[r]=e),h(e),e=e.nextSibling}}function y(n){k(n);for(var r=n.firstChild;r;){var t=r.nextSibling,i=_(r);if(i){var o=D[i];o&&e(r,o)&&(r.parentNode.replaceChild(o,r),x(o,r))}y(r),r=t}}function x(n,r,t){var a,s=_(r);if(s&&delete D[s],!l.isSameNode||!l.isSameNode(o)){if(!t){if(j(n,r)===!1)return;if(i(n,r),C(n),H(n,r)===!1)return}if("TEXTAREA"!==n.nodeName){var d,u,h,w,O=r.firstChild,k=n.firstChild;n:for(;O;){for(h=O.nextSibling,d=_(O);k;){if(u=k.nextSibling,O.isSameNode&&O.isSameNode(k)){O=h,k=u;continue n}a=_(k);var S=k.nodeType,M=void 0;if(S===O.nodeType&&(S===g?(d?d!==a&&((w=D[d])?k.nextSibling===w?M=!1:(n.insertBefore(w,k),u=k.nextSibling,a?c(a):p(k,n,!0),k=w):M=!1):a&&(M=!1),M=M!==!1&&e(k,O),M&&x(k,O)):S!==v&&S!=b||(M=!0,k.nodeValue=O.nodeValue)),M){O=h,k=u;continue n}a?c(a):p(k,n,!0),k=u}if(d&&(w=D[d])&&e(w,O))n.appendChild(w),x(w,O);else{var L=T(O);L!==!1&&(L&&(O=L),O.actualize&&(O=O.actualize(n.ownerDocument||m)),n.appendChild(O),y(O))}O=h,k=u}for(;k;)u=k.nextSibling,(a=_(k))?c(a):p(k,n,!0),k=u}var A=f[n.nodeName];A&&A(n,r)}}if(d||(d={}),"string"==typeof l)if("#document"===o.nodeName||"HTML"===o.nodeName){var w=l;l=m.createElement("html"),l.innerHTML=w}else l=n(l);var O,_=d.getNodeKey||s,T=d.onBeforeNodeAdded||a,k=d.onNodeAdded||a,j=d.onBeforeElUpdated||a,C=d.onElUpdated||a,S=d.onBeforeNodeDiscarded||a,M=d.onNodeDiscarded||a,H=d.onBeforeElChildrenUpdated||a,L=d.childrenOnly===!0,D={};h(o);var A=o,E=A.nodeType,P=l.nodeType;if(!L)if(E===g)P===g?e(o,l)||(M(o),A=t(o,r(l.nodeName,l.namespaceURI))):A=l;else if(E===v||E===b){if(P===E)return A.nodeValue=l.nodeValue,A;A=l}if(A===l)M(o);else if(x(A,l,L),O)for(var I=0,X=O.length;I\s]+))?)*)\s*(\/?)>/,t=/^<\/([-A-Za-z0-9_]+)[^>]*>/,i=/([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,o=function(n,e){function o(n,r,t,o){if(r=r.toLowerCase(),o=!!o,o||c.push(r),e.start){var a=[];t.replace(i,function(n,e){var r=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:"";a.push({name:e,value:r,escaped:r.replace(/(^|[^\\])"/g,'$1\\"')})}),e.start&&e.start(r,a,o)}}function a(n,r){if(r)for(var t=c.length-1;t>=0&&c[t]!=r;t--);else var t=0;if(t>=0){for(var i=c.length-1;i>=t;i--)e.end&&e.end(c[i]);c.length=t}}var s,l,d,c=[],u=n;for(c.last=function(){return this[this.length-1]};n;){if(l=!0,c.last())n=n.replace(new RegExp("([\\s\\S]*?)]*>"),function(n,r){return e.chars&&e.chars(r),""}),a("",c.last());else if(0==n.indexOf(">>0,i=0;if(2==arguments.length)e=arguments[1];else{for(;i=t)throw new TypeError("Reduce of empty array with no initial value");e=r[i++]}for(;i640){var o=document.querySelectorAll("pre"),a=this.getHighLight();if(a){for(var s in a)o[s]&&o[s].setAttribute("data-line",a[s]);n||lineHighLight()}}}},{key:"getHighLight",value:function(){var n=this,e=null;return m.default.menus[this.data.lan].forEach(function(r){r.list.forEach(function(r){r.md===n.data.name&&(e=r.highlight)})}),e}},{key:"installed",value:function(){}},{key:"render",value:function(){return this.data.html=marked(s(this.data.name,this.data.lan)),'\n
    \n {{{html}}}\n
    \n '}},{key:"style",value:function(){return"\n \n "}}]),e}(c.default.Component);e.default=p},function(n,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r={isMobile:!1,mds:{cn:["installation","hello_world","components","communication","lifecycle","events","condition","loop","form","inherit","template","get_dom","plugin","thinking_in_omi","pr_env","pr_hello"],en:["installation","hello_world","components","communication","lifecycle","events","condition","loop","form","inherit","template","get_dom","plugin"]},menus:{cn:[{active:!0,title:"快速开始",currentIndex:0,list:[{name:"安装",md:"installation"},{name:"Hello World",md:"hello_world",highlight:{2:"6",5:"4,6"}},{name:"组件",md:"components",highlight:{2:"3,9,34"}},{name:"组件通讯",md:"communication",highlight:{0:"34",1:"5,11"}},{name:"生命周期",md:"lifecycle"},{name:"事件处理",md:"events"},{name:"条件判断",md:"condition"},{name:"循环遍历",md:"loop",highlight:{1:"9-11"}},{name:"表单",md:"form"},{name:"继承",md:"inherit"},{name:"模板切换",md:"template"},{name:"获取DOM节点",md:"get_dom"},{name:"插件体系",md:"plugin"},{name:"Omi的理念",md:"thinking_in_omi"}]}],en:[{title:"QUICK START",currentIndex:0,list:[{name:"Installation",md:"installation"},{name:"Hello World",md:"hello_world"},{name:"Components",md:"components"},{name:"Communication",md:"communication"},{name:"Lifecycle",md:"lifecycle"},{name:"Handling Events",md:"events"},{name:"Conditional Rendering",md:"condition"},{name:"Loop",md:"loop"},{name:"Forms",md:"form"},{name:"Inheritance",md:"inherit"},{name:"Templates",md:"template"},{name:"Get DOM",md:"get_dom"},{name:"Plugin",md:"plugin"},{name:"Thinking in Omi",md:"thinking_in_omi"}]}]}},t={versions:function(){var n=navigator.userAgent;navigator.appVersion;return{trident:n.indexOf("Trident")>-1,presto:n.indexOf("Presto")>-1,webKit:n.indexOf("AppleWebKit")>-1,gecko:n.indexOf("Gecko")>-1&&n.indexOf("KHTML")==-1,mobile:!!n.match(/AppleWebKit.*Mobile.*/),ios:!!n.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),android:n.indexOf("Android")>-1||n.indexOf("Linux")>-1,iPhone:n.indexOf("iPhone")>-1,iPad:n.indexOf("iPad")>-1,webApp:n.indexOf("Safari")==-1}}(),language:(navigator.browserLanguage||navigator.language).toLowerCase()};(t.versions.mobile||t.versions.ios||t.versions.android||t.versions.iPhone||t.versions.iPad)&&(r.isMobile=!0),e.default=r},function(n,e,r){function t(n){return r(i(n))}function i(n){return o[n]||function(){throw new Error("Cannot find module '"+n+"'.")}()}var o={"./README.md":13,"./cn_communication.md":14,"./cn_components.md":15,"./cn_condition.md":16,"./cn_events.md":17,"./cn_form.md":18,"./cn_get_dom.md":19,"./cn_hello_world.md":20,"./cn_inherit.md":21,"./cn_installation.md":22,"./cn_lifecycle.md":23,"./cn_loop.md":24,"./cn_plugin.md":25,"./cn_pr_nearby.md":26,"./cn_template.md":27,"./cn_thinking_in_omi.md":28,"./deep_in/README.md":29,"./deep_in/cn_env.md":30,"./deep_in/cn_hello.md":31,"./deep_in/cn_nearby.md":32,"./deep_in/cn_omi-cli.md":33,"./en_communication.md":34,"./en_components.md":35,"./en_condition.md":36,"./en_events.md":37,"./en_form.md":38,"./en_get_dom.md":39,"./en_hello_world.md":40,"./en_inherit.md":41,"./en_installation.md":42,"./en_lifecycle.md":43,"./en_loop.md":44,"./en_plugin.md":45,"./en_template.md":46,"./en_thinking_in_omi.md":47};t.keys=function(){return Object.keys(o)},t.resolve=i,n.exports=t,t.id=12; +},function(n,e){n.exports='module.exports = "## [Docs Website](https://alloyteam.github.io/omi/website/docs.html)\\r\\n\\r\\n### Usage\\r\\n* [安装](./cn_installation.md)\\r\\n* [Hello World](./cn_hello_world.md)\\r\\n* [组件](./cn_components.md)\\r\\n* [组件通讯](./cn_communication.md)\\r\\n* [生命周期](./cn_lifecycle.md)\\r\\n* [事件处理](./cn_events.md)\\r\\n* [条件判断](./cn_condition.md)\\r\\n* [循环遍历](./cn_loop.md)\\r\\n* [表单](./cn_form.md)\\r\\n* [继承](./cn_inherit.md)\\r\\n* [模板切换](./cn_template.md)\\r\\n* [获取DOM节点](./cn_get_dom.md)\\r\\n* [插件体系](./cn_plugin.md)\\r\\n* [Omi理念](./cn_thinking_in_omi.md)\\r\\n\\r\\n### Usage(en-us)\\r\\n* [installation](./en_installation.md)\\r\\n* [Hello World](./en_hello_world.md)\\r\\n* [components](./en_components.md)\\r\\n* [communication](./en_communication.md)\\r\\n* [lifecycle](./en_lifecycle.md)\\r\\n* [events](./en_events.md)\\r\\n* [condition](./en_condition.md)\\r\\n* [loop](./en_loop.md)\\r\\n* [form](./en_form.md)\\r\\n* [inherit](./en_inherit.md)\\r\\n* [template](./en_template.md)\\r\\n\\r\\n"'},function(n,e){n.exports='module.exports = "

    组件通讯

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)组建间的通讯非常遍历灵活,因为有许多可选方案进行通讯:\\r\\n\\r\\n* 通过在组件上声明 data-* 传递给子节点 \\r\\n* 通过在组件上声明 data 传递给子节点 (支持复杂数据类型的映射)\\r\\n* 父容器设置 childrenData 自动传递给子节点\\r\\n* 声明 group-data 传递(支持复杂数据类型的映射)\\r\\n* 完全面向对象,可以非常容易地拿到对象的实例,之后可以设置实例属性和调用实例的方法\\r\\n\\r\\n所以通讯变得畅通无阻,下面一一来举例说明。\\r\\n\\r\\n### data-*通讯 \\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n \\tcursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n一般data-*用来传递值类型,如string、number。值得注意的是,通过data-*接收到的数据类型都是string,需要自行转成number类型。\\r\\n通常情况下,data-*能满足我们的要求,但是遇到复杂的数据类型是没有办法通过大量data-*去表达,所以可以通过data通讯,请往下看。\\r\\n\\r\\n### data通讯 \\r\\n\\r\\n如上面代码所示,通过 data-name=\\"Omi\\"可以把name传递给子组件。下面的代码也可以达到同样的效果。\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.helloData = { name : \'Omi\' };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n使用data声明,会去组件的instance(也就是this)下找对应的属性,this下可以挂载任意复杂的对象。所以这也就突破了data-*的局限性。\\r\\n\\r\\n如果instance下面的某个属性下面的某个属性下面的某个数组的第一个元素的某个属性要作为data传递Hello怎么办?\\r\\n没关系,data声明是支持复杂类型的,使用方式如下:\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n点击这里→data映射复杂数据\\r\\n\\r\\n### childrenData通讯\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.childrenData = [{ name : \'Omi\' } , { name : \'dntzhang\' }];\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n使用this.childrenData传递data给子组件,childrenData是一个数组类型,所以支持同时给多个组件传递data,与render里面的组件会一一对应上。\\r\\n\\r\\n### group-data通讯\\r\\n\\r\\nchildrenData的方式可以批量传递数据给组件,但是有很多场景下data的来源不一定非要都从childrenData来,childrenData是个数组,会和组件的顺序一一对应,这就给不同传递方式的data必须全部集中的childrenData中,非常不方便。group-data专门为解决上面的痛点而生,专门是为了给一组组件批量传递data。\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.testData = [{name: \'Omi\'}, {name: \'dntzhang\'}, {name: \'AlloyTeam\'}];\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n只需要在声明的子组件上标记group-data,就会去当前组件的instance(也就是this)下面找对应的属性,然后根据当前的位置,和对应数组的位置会一一对应起来。\\r\\n\\r\\n运行结果如下:\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170216110701535-1698390390.png)\\r\\n\\r\\n点击这里→group-data\\r\\n\\r\\n同样group-data支持复杂数据类型的映射,需要注意的是,group-data映射的终点必须是一个数组:\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n点击这里→group-data映射复杂数据\\r\\n\\r\\n### 通过对象实例\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n this.hello.data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n### 通过omi-id\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n Omi.get(\\"hello\\").data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n通过在组件上声明omi-id,在程序任何地方拿到该对象的实例。这个可以算是跨任意组件通讯神器。\\r\\n\\r\\n### 特别强调\\r\\n\\r\\n* 通过childrenData或者data方式通讯都是一锤子买卖。后续变更只能通过组件实例下的data属性去更新组件\\r\\n* 通过data-✼通讯也是一锤子买卖。后续变更只能通过组件实例下的data属性去更新组件。\\r\\n* 关于data-✼通讯也可以不是一锤子买卖,但是要设置组件实例的dataFirst为false,这样的话data-✼就会覆盖组件实例的data对应的属性\\r\\n\\r\\n关于上面的第三条也就是这样的逻辑伪代码:\\r\\n```js\\r\\nif(this.dataFirst){\\r\\n this.data = Object.assign({},data-✼ ,this.data);\\r\\n}else{\\r\\n this.data = Object.assign({},this.data, data-✼);\\r\\n}\\r\\n```"'},function(n,e){n.exports='module.exports = "

    组件

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)完全基于组件体系设计,我们希望开发者可以像搭积木一样制作Web程序,一切皆是组件,组件也可以嵌套子组件形成新的组件,新的组件又可以当作子组件嵌套至任意组件形成新的组件...\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170210093427338-1536910080.png)\\r\\n\\r\\n## 简单组件\\r\\n\\r\\n这里使用Todo的例子来讲解Omi组件体系的使用。\\r\\n\\r\\n```js\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.data.items.push(this.data.text);\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n
      {{#items}}
    • {{.}}
    • {{/items}}
    \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Todo({ items: [] ,text : \'\' }),\\"body\\");\\r\\n```\\r\\n\\r\\n组件生成的HTML最终会插入到body中。上面的例子展示了Omi的部分特性:\\r\\n\\r\\n- data传递: new Todo(data,..)的data可以直接提供给render方法里的模板\\r\\n- 局部CSS: h3只对render里的h3生效,不会污染外面的h3;button也是同样的\\r\\n- 声明式事件绑定: onchange调用的就是组件内的handleChange,this可以拿到当然的DOM元素,还可以拿到当前的event\\r\\n- 需要手动调用update方法才能更新组件\\r\\n\\r\\n这里需要特别强调的是,为了更加的自由和灵活度。Omi没有内置数据变更的自动更新,需要开发者自己调用update方法。\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n## 组件嵌套\\r\\n\\r\\n如果页面超级简单的话,可以没有组件嵌套。但是绝大部分Web网页或者Web应用,需要嵌套定义的组件来完成所有的功能和展示。比如上面的Todo,我们也是可以抽取出List。\\r\\n这样让程序易维护、可扩展、方便复用。如,我们抽取出List:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
      {{#items}}
    • {{.}}
    • {{/items}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n怎么使用这个List?我们需要使用Omi.makeHTML把List制作成可以声明式的标签,在render方法中就能直接使用该标签。如下所示:\\r\\n\\r\\n```js\\r\\nimport List from \'./list.js\';\\r\\n\\r\\nOmi.makeHTML(\'List\', List);\\r\\n\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.data.length = this.data.items.length;\\r\\n this.listData = { items : this.data.items };\\r\\n }\\r\\n\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.list.data.items.push(this.data.text);\\r\\n this.data.length = this.list.data.items.length;\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n* 第3行,通过makeHTML方法把组件制作成可以在render中使用的标签。当然Omi.makeHTML(\'List\', List);也可以写在List组件的代码下面。\\r\\n* 第9行,在父组件上定义listData属性用来传递给子组件。\\r\\n* 第34行,在render方法中使用List组件。其中name方法可以让你在代码里通过this快速方法到该组件的实例。data=\\"listData\\"可以让你把this.listData传递给子组件。\\r\\n\\r\\n需要注意的是,父组件的this.listData会被通过Object.assign浅拷贝到子组件。\\r\\n这样做的目的主要是希望以后DOM的变更都尽量修改子组件自身的data,然后再调用其update方法,而不是去更改父组件的listData。\\r\\n\\r\\n关于Omi组件通讯其实有4种方案,这个后续教程会专门来讲。\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports="module.exports = \"

    条件判断

    \\r\\n\\r\\n我们经常需要根据不同的状态呈现不同的界面,比如有的用户是vip要显示vip的Logo。Omi有许多种方式满足你的要求。\\r\\n\\r\\n### 方式一\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `{{#isVip}}\\r\\n
    you are VIP.
    \\r\\n {{/isVip}}\\r\\n {{^isVip}}\\r\\n
    you are not VIP.
    \\r\\n {{/isVip}}`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n上面完全使用mustachejs的条件判断的语法。当然Omi不强制你使用mustachejs。你可以是omi.lite.js,然后重写Omi.template方法去使用任意你喜爱的模板引擎。\\r\\n\\r\\n### 方式二\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nrender就是提供了很好的可编程性,里面可以写任意js逻辑代码。对了,差点忘了,style方法里面也可以写js逻辑的。\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style (){\\r\\n if(this.data.isVip){\\r\\n return 'div{ color : red; }';\\r\\n }else{\\r\\n return 'div{ color : green; }';\\r\\n }\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 方式三\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n ${this.data.isVip\\r\\n ?\\\"
    you are VIP.
    \\\"\\r\\n :\\\"
    you are not VIP.
    \\\"\\r\\n \\t\\t}\\r\\n `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n当然可以使用${ }里面写javascript代码进行输出。\""},function(n,e){n.exports='module.exports = "

    事件处理

    \\r\\n\\r\\nOmi的事件分内置事件和自定义事件。在内置事件处理方面巧妙地利用了浏览器自身的管线机制,可以通过event和this轻松拿到事件实例和触发该事件的元素。\\r\\n\\r\\n### 内置事件\\r\\n\\r\\n什么算内置事件?只要下面正则能匹配到就算内置事件。\\r\\n\\r\\n```js\\r\\non(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave)\\r\\n```\\r\\n\\r\\n内置事件怎么绑定?如下所示:\\r\\n\\r\\n```js\\r\\nclass EventTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n handleClick(dom, evt){\\r\\n alert(dom.innerHTML);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Hello, Omi!
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 自定义事件\\r\\n\\r\\n开发者自己定义的组件的事件,称为自定义事件,自定义事件必须以on开头,即onXXXX的格式,不然Omi识别不到。这里拿分页作为例子:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\nimport Pagination from \'./pagination.js\';\\r\\nimport Content from \'./content.js\';\\r\\n\\r\\nOmi.makeHTML(\'Pagination\', Pagination);\\r\\nOmi.makeHTML(\'Content\', Content);\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.content.goto(this.pagination.data.currentPage+1);\\r\\n }\\r\\n handlePageChange(index){\\r\\n this.content.goto(index+1);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    Pagination Example

    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render( new Main(),\'body\');\\r\\n```\\r\\n\\r\\n如上面的onPageChange就是自定义事件,触发会执行handlePageChange。onPageChange方法是在Pagination中执行:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\n\\r\\nclass Pagination extends Omi.Component {\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n linkTo: \\"#\\",\\r\\n prevText: \\"Prev\\",\\r\\n nextText: \\"Next\\",\\r\\n ellipseText: \\"...\\",\\r\\n prevShow: true,\\r\\n nextShow: true,\\r\\n onPageChange: function () { return false; }\\r\\n }, this.data);\\r\\n\\r\\n this.pageNum = Math.ceil(this.data.total / this.data.pageSize);\\r\\n }\\r\\n goto (index,evt) {\\r\\n evt.preventDefault();\\r\\n this.data.currentPage=index;\\r\\n this.update();\\r\\n this.data.onPageChange(index);\\r\\n }\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\n这里取了Pagination组件的部分代码。高亮的就是执行onPageChange的地方。\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/pagination/)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/pagination)\\r\\n"'},function(n,e){n.exports='module.exports = "

    表单

    \\r\\n\\r\\nOmi让一些表单操控起来更加方便,特别是select!\\r\\n\\r\\n### select标签\\r\\n\\r\\n以前,我们需要像如下的方式选中一个选项:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n第三个option由于加上了selected,所有会被选中。这样带来的问题就是,开发者写的程序可能要操遍历每个option。而使用Omi,你只需要这样子:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n这样就能达到同样的效果。比如你想选择第一项:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n是不是非常方便?\\r\\n\\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass FormTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n \\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n console.log(target.value)\\r\\n this.data.value = target.value;\\r\\n }\\r\\n\\r\\n handleSubmit(evt) {\\r\\n alert(\'Your favorite flavor is: \' + this.data.value);\\r\\n evt.preventDefault();\\r\\n }\\r\\n \\r\\n render () {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new FormTest({ value: \'mango\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    获取DOM节点

    \\r\\n\\r\\n虽然绝大部分情况下,开发者不需要去查找获取DOM,但是还是有需要获取DOM的场景,所以Omi提供了方便获取DOM节点的方式。\\r\\n\\r\\n### ref和refs\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(){\\r\\n alert(this.refs.abc.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\n可以看到通过在HTML中标记ref为abc,那么就通过this.refs.abc访问到该DOM节点。\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    Hello World

    \\r\\n\\r\\n你可以使用ES6+或者ES5的方式编写Omi程序来搭建你的Web程序。\\r\\n\\r\\n### Hello World with ES6+\\r\\n\\r\\n你可以使用 [webpack](https://webpack.github.io/) 打包工具,webpack会把你的模块代码打成一个很小的包,优化加载时间。使用[babel](http://babeljs.io/),让你立刻马上使用ES6+来编写你的web程序。你只需要在webpack配置的module设置好[babel-loader](https://github.com/babel/babel-loader)便可。\\r\\n\\r\\n一个Omi的简短的例子如下所示:\\r\\n\\r\\n```js\\r\\nimport Omi from \'./omi.js\';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n //注意,return中的包裹是可选的。主要是为了识别为JSX文件可以有CSS高亮。\\r\\n return `\\r\\n \\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\n组件生成的HTML最终会插入到#container中。上面的例子展示了Omi的部分特性:\\r\\n\\r\\n- data传递: new Hello(data,..)的data可以直接提供给render方法里的模板\\r\\n- 局部CSS: h1只对render里的h1生效,不会污染外面的h1\\r\\n- 声明式事件绑定: onclick调用的就是组件内的handleClick,this可以拿到当前的DOM元素,还可以拿到当前的event\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n你可以使用Omi.makeHTML来生成组件标签用于嵌套。\\r\\n```js\\r\\n Omi.makeHTML(\'Hello\', Hello);\\r\\n```\\r\\n那么你就在其他组件中使用,如\\r\\n```js\\r\\n ...\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Test
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n ...\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### Hello World with ES5\\r\\n\\r\\n当然Omi没有抛弃ES5的用户。你可以使用ES5的方式编写Omi。如,在你的HTML中引用omi.js:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n然后:\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\", {\\r\\n style: function () {\\r\\n return \\"h1{ cursor:pointer }\\";\\r\\n },\\r\\n handleClick: function (dom) {\\r\\n alert(dom.innerHTML)\\r\\n },\\r\\n render: function () {\\r\\n return \'
    \\\\\\r\\n

    \\\\\\r\\n Hello ,{{name}}!\\\\\\r\\n

    \\\\\\r\\n
    \'\\r\\n }\\r\\n});\\r\\n\\r\\nvar Test = Omi.create(\\"Test\\", {\\r\\n render: function () {\\r\\n return \'
    \\\\\\r\\n
    Test
    \\\\\\r\\n \\\\\\r\\n
    \'\\r\\n }\\r\\n});\\r\\n\\r\\nOmi.render(new Test(),\'#container\');\\r\\n```\\r\\n当然除了在HTML引入脚本,你还可以使用AMD、CMD或者CommonJS的方式引入Omi,这里就不再一一列举。\\r\\n\\r\\n需要注意的是,Omi.create的第一个参数Hello是用来生成Tag Name的。你可以在其他地方嵌入你的组件。如:\\r\\n\\r\\n```js\\r\\n ...\\r\\n render:function() {\\r\\n return \'
    \\\\\\r\\n \\\\\\r\\n
    Test XXXX
    \\\\\\r\\n \\\\\\r\\n
    \';\\r\\n }\\r\\n ...\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports='module.exports = "

    继承

    \\r\\n\\r\\n通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。\\r\\n\\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n div{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n}\\r\\n\\r\\nclass SubHello extends Hello {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### ES5下的继承\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\",{\\r\\n render:function(){\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n})\\r\\n\\r\\nvar SubHello = Omi.create(\\"SubHello\\",Hello,{ });\\r\\n\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    安装

    \\n\\n[Omi](https://github.com/AlloyTeam/omi)(读音 / [ˈomɪ] /, 汉字类似于 欧米) 是一款用于创建用户界面的组件化框架,开放并且现代,故得名:Omi。\\n\\n### 安装 Omi\\n\\n我们推荐使用 [npm](https://www.npmjs.com/) 来管理你的前端依赖.\\n\\n通过npm安装Omi,你只需要执行下面的命令:\\n\\n``` js\\nnpm install omi\\n```\\n\\n## omi-cli\\n\\n你也可以通过omi-cli去初始化你的项目:\\n\\n``` js\\n$ npm install omi-cli -g //安装cli\\n$ omi init your_project_name //初始化项目,你也可以在一个空的文件夹下执行 omi init\\n$ cd your_project_name //如果你是在空文件夹下执行的 omi init。请无视这条命令\\n$ npm run dev //开发\\n$ npm run dist //部署发布\\n```"'},function(n,e){n.exports='module.exports = "

    生命周期

    \\r\\n\\r\\n|name |avatars |company | \\r\\n|---|---|---|\\r\\n| constructor | 构造函数 | new的时候 |\\r\\n| install | 初始化安装,这可以拿到用户传进的data进行处理 | 实例化 |\\r\\n| installed | 安装完成,HTML已经插入页面之后执行 | 实例化 |\\r\\n| uninstall | 卸载组件。执行remove方法会触发该事件 | 销毁时 |\\r\\n| beforeUpdate | 更新前 | 存在期 |\\r\\n| afterUpdate | 更新后 | 存在期 |\\r\\n\\r\\n## 示意图\\r\\n\\r\\n![lc](http://images2015.cnblogs.com/blog/105416/201701/105416-20170119153018546-1566368987.png)\\r\\n \\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass Timer extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n install () {\\r\\n this.data = {secondsElapsed: 0};\\r\\n }\\r\\n\\r\\n tick() {\\r\\n this.data.secondsElapsed++;\\r\\n this.update();\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.interval = setInterval(() => this.tick(), 1000);\\r\\n }\\r\\n\\r\\n uninstall() {\\r\\n clearInterval(this.interval);\\r\\n }\\r\\n\\r\\n\\r\\n style () {\\r\\n return `\\r\\n .num { color:red; }\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Seconds Elapsed: {{secondsElapsed}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports='module.exports = "

    循环遍历

    \\r\\n\\r\\n下面介绍mustache.js的方式和javascript遍历的方式。\\r\\n\\r\\n### 方式一\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n
      \\r\\n {{#items}} \\r\\n
    • {{text}}
    • \\r\\n {{/items}}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nmustache.js更详细的循环遍历使用可看[https://github.com/janl/mustache.js#non-empty-lists](https://github.com/janl/mustache.js#non-empty-lists)。 比如还支持:\\r\\n\\r\\n* 如果items的每一项是字符串,可以直接**{{.}}**的方式来输出每一项\\r\\n* 循环的时候调用定义好的函数\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### 方式二\\r\\n\\r\\n既然ES6+了,当然可以使用${ }以及Array的map方法: \\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `
    \\r\\n
      \\r\\n ${this.data.items.map(item =>\\r\\n `
    • ${item.text}
    • `\\r\\n ).join(\'\')}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\n你将在页面看到如下效果:\\r\\n\\r\\n![pv](http://images2015.cnblogs.com/blog/105416/201701/105416-20170122095724129-2059595233.png)\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n如果想在循环里加些判断呢?比如需要把id为偶数的隐藏起来:\\r\\n\\r\\n```js\\r\\nrender() {\\r\\n return `
    \\r\\n
      \\r\\n ${this.data.items.map(item =>\\r\\n `
    • ${item.text}
    • `\\r\\n ).join(\'\')}\\r\\n
    \\r\\n
    `;\\r\\n}\\r\\n```\\r\\n\\r\\n所以模板字符串还是非常方便,随着ES继续发展下去,模板引擎估计会慢慢消失。所以omi提供了 omi.lite.js 版本不包含任何模板引擎。"'; +},function(n,e){n.exports="module.exports = \"

    插件体系

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi)是Web组件化框架,怎么又来了个插件的概念?\\r\\n\\r\\n可以这么理解: Omi插件体系可以赋予dom元素一些能力,并且可以和组件的实例产生关联。\\r\\n\\r\\n### omi-drag\\r\\n\\r\\n且看这个例子:\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n```js\\r\\nimport OmiDrag from './omi-drag.js';\\r\\n\\r\\nOmiDrag.init();\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n\\r\\n style(){\\r\\n return `\\r\\n .test{\\r\\n width:100px;\\r\\n height:100px;\\r\\n color:white;\\r\\n line-height:90px;\\r\\n text-align:center;\\r\\n background-color:#00BFF3;\\r\\n }\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n如上面的代码所示,通过在div上标记omi-drag,这个div就能够被用户使用鼠标拖拽。我们称omi-drag.js为omi插件。\\r\\n是不是非常方便?那么这个omi-drag是怎么实现的?\\r\\n\\r\\n## Omi.extendPlugin\\r\\n\\r\\n核心方法: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n下面的代码就是展示了如何通过 Omi.extendPlugin 赋予dom拖拽的能力:\\r\\n\\r\\n```js\\r\\n;(function () {\\r\\n\\r\\n var OmiDrag = {};\\r\\n var Omi = typeof require === 'function'\\r\\n ? require('omi')\\r\\n : window.Omi;\\r\\n\\r\\n OmiDrag.init = function(){\\r\\n Omi.extendPlugin('omi-drag',function(dom, instance){\\r\\n dom.style.cursor='move';\\r\\n var isMouseDown = false,\\r\\n preX = null,\\r\\n preY = null,\\r\\n currentX = null,\\r\\n currentY = null,\\r\\n translateX = 0,\\r\\n translateY = 0;\\r\\n\\r\\n dom.addEventListener('mousedown',function(evt){\\r\\n isMouseDown = true;\\r\\n preX = evt.pageX;\\r\\n preY = evt.pageY;\\r\\n evt.stopPropagation();\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n }\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mouseup',function(){\\r\\n isMouseDown = false;\\r\\n preX = preY = currentX = currentY = null;\\r\\n },false);\\r\\n });\\r\\n }\\r\\n\\r\\n OmiDrag.destroy = function(){\\r\\n delete Omi.plugins['omi-drag'];\\r\\n };\\r\\n\\r\\n if (typeof exports == \\\"object\\\") {\\r\\n module.exports = OmiDrag;\\r\\n } else if (typeof define == \\\"function\\\" && define.amd) {\\r\\n define([], function(){ return OmiDrag });\\r\\n } else {\\r\\n window.OmiDrag = OmiDrag;\\r\\n }\\r\\n\\r\\n})();\\r\\n```\\r\\n\\r\\n方法: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n其中pluginName为插件的名称\\r\\n其中handler为处理器。handler可以拿到标记了pluginName的dom以及dom所在的组件的实例,即 dom 和 instance。\\r\\n\\r\\n通过 Omi.extendPlugin,可以赋予dom元素一些能力,也可以和组件的实例(instance)产生关联。\\r\\n但是上面的例子没有和instance产生关联,我们接下来试试:\\r\\n\\r\\n## 关联instance\\r\\n\\r\\n我们想在组件里面能够监听到move并且执行回调。如下:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandler(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n主要被拖动过程中,moveHandler就不断地被执行。插件代码需要修改:\\r\\n\\r\\n```js\\r\\n...\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance.moveHandler(evt);\\r\\n }\\r\\n},false);\\r\\n```\\r\\n\\r\\n我们在里面增加了instance.moveHandler(evt);方法,用来执行组件实例上的moveHandler方法。\\r\\n这样的话:就是组件的实例(instance)产生关联。但是还是有问题?如果标记了多个omi-drag 就会有问题!如:\\r\\n\\r\\n```js\\r\\n...\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n通常我们系统每个omi-drag都能对应一个回调函数,如:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n怎么办?怎么实现?有办法!通过dom传递数据给插件。\\r\\n\\r\\n## 传递数据\\r\\n\\r\\n先来看最后实现的效果:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nomi-drag修改的地方:\\r\\n\\r\\n```js\\r\\n...\\r\\nvar handlerName = dom.getAttribute('dragMove');\\r\\n\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance[handlerName](evt);\\r\\n }\\r\\n},false);\\r\\n...\\r\\n```\\r\\n\\r\\n* 通过 var handlerName = dom.getAttribute('dragMove') 拿到dom上声明的dragMove\\r\\n* 通过 instance[handlerName](evt) 去执行对应的方法\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n## 更多插件\\r\\n\\r\\n* [omi-finger](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-finger) Omi的[AlloyFinger](https://github.com/AlloyTeam/AlloyFinger)插件,支持各种触摸事件和手势\\r\\n* [omi-transform](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-transform) Omi的[transformjs](http://alloyteam.github.io/AlloyTouch/transformjs/)插件,快速方便地设置DOM的CSS3 Transform属性\\r\\n* [omi-touch](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-touch) Omi的[AlloyTouch](https://github.com/AlloyTeam/AlloyTouch)插件,Omi项目的触摸运动解决方案(支持触摸滚动、旋转、翻页、选择等等)\\r\\n* [omi-jquery-date-picker](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-jquery-date-picker) Omi的时间选择插件,支持各种时间或者时间区域选择\\r\\n\""},function(n,e){n.exports='module.exports = "## 写在前面\\r\\nOmi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。\\r\\n\\r\\n项目开始之前,实现选择一个脚手架。这个项目用的就是[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)\\r\\n\\r\\nGulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)\\r\\n\\r\\n\\r\\n所以,要使用Fiddler并配置Extention:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)\\r\\n\\r\\n\\r\\n## 目录\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)\\r\\n\\r\\n\\r\\n目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。\\r\\n组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。\\r\\n\\r\\n## 命令\\r\\n\\r\\n开发\\r\\n```js\\r\\nnpm run dev\\r\\n```\\r\\n\\r\\n发布\\r\\n```js\\r\\nnpm run dist\\r\\n```\\r\\n\\r\\n## 开始写码\\r\\n\\r\\n万事具备,开始写码。先写组件:\\r\\n\\r\\n```js\\r\\nimport Omi from \'omi\'\\r\\n\\r\\nclass UserList extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n install() {\\r\\n this.data.uin_info || (this.data.uin_info = [])\\r\\n this.data.uin_info.forEach(user => {\\r\\n this.prepareData(user)\\r\\n })\\r\\n }\\r\\n \\r\\n prepareData(user){\\r\\n user.desc_d = user.desc.split(\\" \\")[0]\\r\\n user.desc_t = user.desc.split(\\" \\")[1]\\r\\n user.isBoy = user.sex === \\"男\\"\\r\\n user.qlogo = user.url.replace(\\"http://\\", location.protocol + \\"//\\").replace(/&/g, \\"&\\")\\r\\n if (user.profession_desc) {\\r\\n user.hasProfession_desc = true\\r\\n }\\r\\n }\\r\\n \\r\\n appendUsers (users) {\\r\\n users.uin_info && users.uin_info.forEach(user =>{\\r\\n this.prepareData(user)\\r\\n this.data.uin_info.push(user)\\r\\n })\\r\\n this.update()\\r\\n }\\r\\n\\r\\n sendGift(uin, nick, qlogo) {\\r\\n //送礼物并关闭webview,此处省略\\r\\n //..\\r\\n //..\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n {{#uin_info}}\\r\\n
    \\r\\n
    \\r\\n \\r\\n
    \\r\\n
    \\r\\n
    {{{nick}}}
    \\r\\n
    \\r\\n {{#isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{^isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{#hasProfession_desc}} {{profession_desc}} {{/hasProfession_desc}}\\r\\n
    \\r\\n
    {{{intro}}}
    \\r\\n
    \\r\\n
    {{desc_d}} · {{desc_t}}
    \\r\\n
    \\r\\n {{/uin_info}}\\r\\n
    加载中...
    \\r\\n
    \\r\\n`\\r\\n }\\r\\n\\r\\n style() {\\r\\n return `\\r\\n\\r\\n\\r\\n.qlogo {\\r\\n overflow: hidden;\\r\\n width: 70px;\\r\\n height: 70px;\\r\\n -webkit-border-radius: 50%;\\r\\n border-radius: 50%;\\r\\n position: absolute;\\r\\n top: 10px;\\r\\n left: 12px;\\r\\n}\\r\\n...\\r\\n...\\r\\n..这里省略大量.....\\r\\n...\\r\\n...\\r\\n\\r\\n.distance_info {\\r\\n position: absolute;\\r\\n top: 15px;\\r\\n right: 9px;\\r\\n color: #7B7B84;\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nexport default UserList\\r\\n```\\r\\n\\r\\n组件里面有5个方法:\\r\\n\\r\\n* constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this\\r\\n* install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理\\r\\n* prepareData 对数据进行一些处理来满足模板的渲染\\r\\n* appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用\\r\\n* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..\\r\\n\\r\\n其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。\\r\\nrender里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;\\r\\n如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。\\r\\n\\r\\n这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)\\r\\n\\r\\n\\r\\n下面来看index.js:\\r\\n\\r\\n```js\\r\\nimport Root from \'./config.js\'\\r\\nimport Omi from \'omi\'\\r\\nimport UserList from \'../component/user_list/index.js\'\\r\\n\\r\\nOmi.makeHTML(\'UserList\', UserList)\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n installed() {\\r\\n window.onscroll = () => this.loadMore()\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n\\r\\n loadMore() {\\r\\n const body = document.body,\\r\\n html = document.documentElement,\\r\\n height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),\\r\\n vp_height = window.innerHeight\\r\\n\\r\\n if (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n }\\r\\n\\r\\n requestData(callback) {\\r\\n if (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }else{\\r\\n \\t//ajax 请求数据,这里省略\\r\\n }\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Main(),\'body\')\\r\\n```\\r\\n\\r\\n通过Omi.makeHTML(\'UserList\', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:\\r\\n\\r\\n```js\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n```\\r\\n\\r\\n下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。\\r\\n\\r\\n```js\\r\\nwindow.onscroll = () => this.loadMore()\\r\\n```\\r\\n\\r\\n通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:\\r\\n\\r\\n```js\\r\\nif (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n}\\r\\n```\\r\\n\\r\\nrequestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。\\r\\n慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:\\r\\n\\r\\n```js\\r\\n \\r\\n```\\r\\n\\r\\n上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!\\r\\n\\r\\n再来看下数据模拟:\\r\\n\\r\\n```js\\r\\nif (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }\\r\\n```\\r\\n\\r\\n这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!\\r\\n\\r\\n## 最后\\r\\n\\r\\n好了,就这么多,Omi让代码真心方便简洁~~~\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)"'},function(n,e){n.exports='module.exports = "

    模板切换

    \\r\\n\\r\\nOmi有三个版本。其中的omi.js和omi.lite.js属于Web端使用的版本。\\r\\n\\r\\n* omi.js内置了[mustache.js](https://github.com/janl/mustache.js)作为模版引擎\\r\\n* omi.lite.js不包含任何模版引擎\\r\\n\\r\\nOmi不强制开发者使用mustache.js,你可以根据业务场景使用任意模板引擎或者不使用模板引擎。\\r\\n\\r\\n那么怎么使用别的模板引擎?下面拿[artTemplate](https://github.com/aui/artTemplate)作为例子。\\r\\n\\r\\n### 使用artTemplate\\r\\n\\r\\n```js\\r\\nOmi.template = function(tpl, data){\\r\\n return artTemplate.compile(tpl)(data);\\r\\n}\\r\\n```\\r\\n重写Omi.template方法,tpl为传入的模板,data为模板所需的数据,返回值为HTML。\\r\\n重写完毕后就能在render使用artTemplate的语法,如:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h1 { color:red; }\\r\\n li{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `

    {{title}}

    \\r\\n
      \\r\\n {{each list as value i}}\\r\\n
    • 索引 {{i + 1}} :{{value}}
    • \\r\\n {{/each}}\\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/artTemplate/)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/artTemplate)"'},function(n,e){n.exports='module.exports = "

    Omi的理念

    \\r\\n\\r\\nOmi的理念是基于面向对象编程体系,内建积木系统。\\r\\n 传统的单向数据流或者抛出event的组件通讯方式增加了系统的稳定性,但是丧失了灵活性。一定程度上也降低了组建的复用。所谓鱼和熊掌不可兼得。\\r\\n 面向对象体系需要多一个逻辑层,可以自由操作所有组件的instance,instance之间的逻辑关系构建出了整个程序。这样组建间的逻辑,通信,复用就全部迎刃而解。组建也更加单一职责,更松耦合。\\r\\n\\r\\n对比函数式编程、命令式编程与面向对象编程,可以归纳总结出下面几条:\\r\\n\\r\\n- 命令式编程干脆直接,利用循环条件等控制流程,强调执行过程\\r\\n- 命令式编程对硬件执行友好,运行更容易,却阻碍了复杂程序的设计\\r\\n- 函数式强调输入和输出,并非执行过程\\r\\n- 函数式倡导多个简单执行单元组合成复杂运算程序\\r\\n- 面向对象编程将对象作为程序的基本单元,更具有重用性、灵活性和扩展性\\r\\n\\r\\nJavascript是哪种类型的语言?现在ES6+已经有了class。那么他是面向对象语言?\\r\\n但是JS可以在任意地方定义函数并且当作把函数当作值来传递。那么他是函数式编程语言?\\r\\n所以,没有精准的定义,取决于你的用法和姿势。其次,Web组件化架构层面编程模型和语言层面编程模型是非常自由的关系。意思就是,你可以用Javascript构建函数式编程框架如React,也可以基于面向对象体系搭建Omi。\\r\\n\\r\\n### 函数式编程 VS 面向对象编程\\r\\n\\r\\n在UI组件框架层面,函数式编程的代表有React,Omi属于面向对象编程体系。那么他们各有什么优缺点?下面做了个对比(其实也是函数式编程与面向对象编程的对比):\\r\\n\\r\\n| | React | Omi |\\r\\n| ------------- |:-------------:|:-----:|\\r\\n| 组件通信 | ★★★★☆| ★★★★★ |\\r\\n| 稳定性 | ★★★★★ | ★★★★☆ |\\r\\n| 灵活性 | ★★★★☆| ★★★★★ |\\r\\n| 扩展性 | ★★★★☆ | ★★★★★ |\\r\\n| 测试性 | ★★★★★ | ★★★★☆ |\\r\\n| 文件大小 | ★★★☆☆ | ★★★★★ |\\r\\n| 功能特性 | ★★★☆☆ | ★★★★☆ |\\r\\n| DOM性能 | ★★★★★ | ★★★★☆ |\\r\\n| 动画性能 | ★★★★☆ | ★★★★★ |\\r\\n| 抽象复杂度 | ★★★★☆ | ★★★★★ |\\r\\n| 异步编程 | ★★★★★ | ★★★★☆ |\\r\\n\\r\\n可以看得出,鱼和熊掌不可兼得。面向对象编程更具有重用性、灵活性和扩展性,带来的问题就是更加难测试。\\r\\n具体来说,如函数式编程,其测试面积是state1 + state2 + ... + stateN;在面向对象编程中,其测试面积是state1×event1 + state2×event2 + ... + stateN×eventN。\\r\\n\\r\\n总结来说,更加推荐使用面向对象的方式去搭建UI组件化框架。\\r\\n\\r\\n
    \\r\\n\\r\\n### 全文结束,感谢阅读。[开始Omi之旅吧!](https://github.com/AlloyTeam/omi) \\r\\n\\r\\n"'},function(n,e){n.exports='module.exports = "# 深入Omi\\r\\n\\r\\n(待续...)\\r\\n\\r\\n* [环境搭建](./cn_env.md)\\r\\n* [Hello Omi](./cn_hello.md)\\r\\n* [手Q附近Web页Omi实战](./cn_nearby.md)\\r\\n* 局部CSS揭秘\\r\\n* 组件嵌套揭秘\\r\\n* 事件处理揭秘\\r\\n* 服务器端渲染揭秘\\r\\n* 模板切换揭秘\\r\\n* 容器系统揭秘"'},function(n,e){n.exports='module.exports = "

    环境搭建

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)使用 Webpack + ES6 的方式去开发;使用karma+jasmine来作为Omi的测试工具。\\r\\n\\r\\n## Karma介绍\\r\\n\\r\\nKarma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner)。该工具可用于测试所有主流Web浏览器,也可集成到CI(Continuous integration)工具,也可和其他代码编辑器一起使用。这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行。但是集成到travis ci要把singleRun设置成true,让其只执行一遍。\\r\\n\\r\\n## Jasmine介绍\\r\\nJasmine 是一款 JavaScript BDD(行为驱动开发)测试框架,它不依赖于其他任何 JavaScript 组件。它有干净清晰的语法,让您可以很简单的写出测试代码。\\r\\n\\r\\n## 开发依赖包\\r\\n\\r\\n在package.json中,有如下配置:\\r\\n\\r\\n```js\\r\\n \\"devDependencies\\": {\\r\\n \\"babel-core\\": \\"^6.0.20\\",\\r\\n \\"babel-loader\\": \\"^6.0.1\\",\\r\\n \\"babel-preset-es2015\\": \\"^6.0.15\\",\\r\\n \\"node-libs-browser\\": \\"^0.5.3\\",\\r\\n \\"webpack\\": \\"^1.14.0\\",\\r\\n \\"jasmine-core\\": \\"^2.5.2\\",\\r\\n \\"karma\\": \\"^1.3.0\\",\\r\\n \\"karma-chrome-launcher\\": \\"^2.0.0\\",\\r\\n \\"karma-jasmine\\": \\"^1.1.0\\",\\r\\n \\"karma-webpack\\": \\"^1.8.1\\"\\r\\n }\\r\\n```\\r\\n\\r\\n* ES6+相关依赖有babel-core、babel-loader和babel-preset-es2015\\r\\n\\r\\n在webpack.config.js中配置js文件使用babel-loader编译。\\r\\n```js\\r\\nloaders: [\\r\\n {\\r\\n loader: \'babel-loader\',\\r\\n test: /\\\\.js$/,\\r\\n query: {\\r\\n presets: \'es2015\',\\r\\n }\\r\\n }\\r\\n]\\r\\n```\\r\\n\\r\\n* webpack相关依赖有node-libs-browser和webpack\\r\\n* 其余都是单元测试相关依赖\\r\\n\\r\\n 注意,这里使用了karma-webpack。因为使用Omi框架支持ES6+和ES5,使用karma-webpack是为了在单元测试里面使用ES6+的import和Class等语法。\\r\\n\\r\\n在karma.conf.js中配置webpack:\\r\\n\\r\\n```js\\r\\n webpack: webpackConfig,\\r\\n webpackMiddleware:{\\r\\n noInfo:false\\r\\n },\\r\\n plugins: [\\r\\n \'karma-webpack\',\\r\\n \'karma-jasmine\',\\r\\n \'karma-chrome-launcher\'\\r\\n ]\\r\\n```\\r\\n\\r\\n具体配置看test目录下的[karma.conf.js](https://github.com/AlloyTeam/omi/blob/master/test/karma.conf.js)和[webpack.test.config.js](https://github.com/AlloyTeam/omi/blob/master/test/webpack.test.config.js)便可。\\r\\n\\r\\n注意,karma.conf.js需要设置\\r\\n\\r\\n```js\\r\\n// if true, Karma captures browsers, runs the tests and exits\\r\\nsingleRun: true,\\r\\n```\\r\\n\\r\\n不然,travis ci脚本执行的时候不会中断导致执行超时异常。\\r\\n\\r\\n## npm 脚本\\r\\n\\r\\n```js\\r\\n \\"scripts\\": {\\r\\n \\"build\\": \\"webpack -w\\",\\r\\n \\"test\\": \\"karma start test/karma.conf.js\\",\\r\\n \\"hello\\": \\"webpack -w\\",\\r\\n \\"todo\\": \\"webpack -w\\"\\r\\n }\\r\\n```\\r\\n\\r\\n其中:\\r\\n* npm run build : 生成dist目录的omi.js文件\\r\\n* npm run test : 执行单元测试\\r\\n* npm run hello : 编译hello的demo\\r\\n* npm run todo : 编译todo的demo\\r\\n\\r\\n在webpack.config.js中,会根据 process.env.npm_lifecycle_event去设置不同的入口文件。所以同样是执行webpack -w,执行结果可以不一样。\\r\\n\\r\\n来看下build的相关webpack配置:\\r\\n\\r\\n```js\\r\\nif(ENV === \'build\'){\\r\\n config = {\\r\\n entry: {\\r\\n omi: \'./src/index.js\'\\r\\n },\\r\\n output: {\\r\\n path: \'dist/\',\\r\\n library:\'Omi\',\\r\\n libraryTarget: \'umd\',\\r\\n filename: \'[name].js\'\\r\\n },\\r\\n```\\r\\n\\r\\n这里把libraryTarget设置成了umd,webpack会帮助我们build出umd的Omi。\\r\\n\\r\\n如果是打包demo(npm run hello 和 npm run todo)的话,会进入下面的条件判断:\\r\\n\\r\\n```js\\r\\nelse {\\r\\n config.entry = \'./example/\' + ENV + \'/main.js\';\\r\\n config.output.path = \'./example/\' + ENV + \'/\';\\r\\n}\\r\\n```\\r\\n\\r\\n会去example下对应的目录查找main.js作为webpack入口文件。\\r\\n\\r\\n这里可以看到,我们不仅用webpack build出Omi框架,也使用webpack build所有demo。\\r\\n详细配置参考[webpack.config.js](https://github.com/AlloyTeam/omi/blob/master/webpack.config.js)的配置。\\r\\n\\r\\n## 参考文档\\r\\n\\r\\n* [http://www.cnblogs.com/cqhaibin/p/5867125.html](http://www.cnblogs.com/cqhaibin/p/5867125.html)\\r\\n* [https://karma-runner.github.io/latest/intro/installation.html](https://karma-runner.github.io/latest/intro/installation.html)\\r\\n* [https://karma-runner.github.io/latest/intro/configuration.html](https://karma-runner.github.io/latest/intro/configuration.html)\\r\\n\\r\\n"'},function(n,e){n.exports="module.exports = \"

    Hello Omi

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)的每个组件都继承自Omi.Component,本篇会去完成Omi的Component的基本锥形,让其能够渲染第一个组件。\\r\\n\\r\\n## omi.js实现\\r\\n\\r\\n```js\\r\\nvar Omi = {};\\r\\nOmi._instanceId = 0;\\r\\nOmi.getInstanceId = function () {\\r\\n return Omi._instanceId++;\\r\\n};\\r\\n\\r\\nOmi.render = function(component, renderTo){\\r\\n component.renderTo = typeof renderTo === \\\"string\\\" ? document.querySelector(renderTo) : renderTo;\\r\\n component._render();\\r\\n return component;\\r\\n};\\r\\n\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n* Omi.getInstanceId 用来给每个组件生成自增的ID\\r\\n* Omi.render 用来把组件渲染到页面\\r\\n\\r\\n## 基类Omi.Component实现\\r\\n\\r\\n所有的组件都是继承自Omi.Component。\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\n\\r\\nclass Component {\\r\\n constructor(data) {\\r\\n this.data = data || {};\\r\\n this.id = Omi.getInstanceId();\\r\\n this.HTML = null;\\r\\n this.renderTo = null;\\r\\n }\\r\\n\\r\\n _render() {\\r\\n this.HTML = this.render();\\r\\n this.renderTo.innerHTML = this.HTML;\\r\\n }\\r\\n}\\r\\n\\r\\nexport default Component;\\r\\n```\\r\\n\\r\\n* Omi使用完全面向对象的方式去开发组件,这里约定好带有下划线的方法是用于内部实现调用,不建议Omi框架的使用者去调用。\\r\\n* 其中,_render为私有方法用于内部实现调用,会去调用组件的真正render方法用于生成HTML,并且把生成的HTML插入到renderTo容器里面。\\r\\n* 注意,这里目前没有引入dom diff,不管第几次渲染都是无脑设置innerHTML,复杂HTML结构对浏览器的开销很大,这里后续会引入diff。\\r\\n\\r\\n## index.js整合\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi = Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n这里把Omi给直接暴露在window下,因为每个组件都生成了唯一的ID,后续实现事件作用域以及对象实例获取都要通过window下的Omi获取。\\r\\n\\r\\n## 最后使用\\r\\n\\r\\n实现完omi.js和component.js以及index.js之后,你就可以实现Hello Omi拉:\\r\\n\\r\\n```js\\r\\nimport Omi from 'index.js'; \\r\\n//或者使用webpack build之后的omi.js \\r\\n//import Omi from 'omi.js';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,`+ this.data.name +`!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : 'Omi' }),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n什么?都2017年了还在拼接字符串?!虽然ES6+的template string让多行字符串拼接更加得心应手,但是template string+模板引擎可以让更加优雅方便。既然用了template string,也可以写成这样子:\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,${this.data.name}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : 'Omi' }),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n## 引入mustachejs模板引擎\\r\\n\\r\\nOmi支持任意模板引擎。可以看到,上面是通过拼接字符串的形式生成HTML,这里当然可以使用模板引擎。\\r\\n\\r\\n修改一下index.js:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Mustache from './mustache.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.template = Mustache.render;\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi=Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n这里把Mustache.render挂载在Omi.template下。再修改一下component.js:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\n\\r\\nclass Component {\\r\\n constructor(data) {\\r\\n this.data = data || {};\\r\\n this.id = Omi.getInstanceId();\\r\\n this.HTML = null;\\r\\n }\\r\\n\\r\\n _render() {\\r\\n this.HTML = Omi.template(this.render(), this.data);\\r\\n this.renderTo.innerHTML = this.HTML;\\r\\n }\\r\\n}\\r\\n\\r\\nexport default Component;\\r\\n```\\r\\n\\r\\nOmi.template(即Mustache.render)需要接受两个参数,第一个参数是模板,第二个参数是模板使用的数据。\\r\\n\\r\\n现在,你便可以使用mustachejs模板引擎的语法了:\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n从上面的代码可以看到,你完全可以重写Omi.template方法去使用任意模板引擎。重写Omi.template的话,建议使用omi.lite.js,因为omi.lite.js是不包含任何模板引擎的。那么怎么build出两个版本的omi?且看webpack里设置的多入口:\\r\\n\\r\\n```js\\r\\n entry: {\\r\\n omi: './src/index.js',\\r\\n 'omi.lite': './src/index.lite.js'\\r\\n},\\r\\noutput: {\\r\\n path: 'dist/',\\r\\n library:'Omi',\\r\\n libraryTarget: 'umd',\\r\\n filename: '[name].js'\\r\\n},\\r\\n```\\r\\n\\r\\nindex.lite.js的代码如下:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.template = function(tpl, data){\\r\\n return tpl;\\r\\n}\\r\\n\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi=Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n可以看到Omi.template没有对tpl做任何处理直接返回,开发者可以重写该方法。\\r\\n\\r\\n## 总结\\r\\n\\r\\n到目前为止,已经实现了:\\r\\n\\r\\n* 第一个组件的渲染\\r\\n* 模板引擎的接入\\r\\n* 多入口打包omi.js和omi.lite.js\\r\\n\\r\\n下片,将介绍《Omi原理-局部CSS》,欢迎关注...\\r\\n\""},function(n,e){n.exports='module.exports = "## 写在前面\\r\\nOmi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。\\r\\n\\r\\n项目开始之前,实现选择一个脚手架。这个项目用的就是[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)\\r\\n\\r\\nGulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)\\r\\n\\r\\n\\r\\n所以,要使用Fiddler并配置Extention:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)\\r\\n\\r\\n\\r\\n## 目录\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)\\r\\n\\r\\n\\r\\n目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。\\r\\n组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。\\r\\n\\r\\n## 命令\\r\\n\\r\\n开发\\r\\n```js\\r\\nnpm run dev\\r\\n```\\r\\n\\r\\n发布\\r\\n```js\\r\\nnpm run dist\\r\\n```\\r\\n\\r\\n## 开始写码\\r\\n\\r\\n万事具备,开始写码。先写组件:\\r\\n\\r\\n```js\\r\\nimport Omi from \'omi\'\\r\\n\\r\\nclass UserList extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n install() {\\r\\n this.data.uin_info || (this.data.uin_info = [])\\r\\n this.data.uin_info.forEach(user => {\\r\\n this.prepareData(user)\\r\\n })\\r\\n }\\r\\n \\r\\n prepareData(user){\\r\\n user.desc_d = user.desc.split(\\" \\")[0]\\r\\n user.desc_t = user.desc.split(\\" \\")[1]\\r\\n user.isBoy = user.sex === \\"男\\"\\r\\n user.qlogo = user.url.replace(\\"http://\\", location.protocol + \\"//\\").replace(/&/g, \\"&\\")\\r\\n if (user.profession_desc) {\\r\\n user.hasProfession_desc = true\\r\\n }\\r\\n }\\r\\n \\r\\n appendUsers (users) {\\r\\n users.uin_info && users.uin_info.forEach(user =>{\\r\\n this.prepareData(user)\\r\\n this.data.uin_info.push(user)\\r\\n })\\r\\n this.update()\\r\\n }\\r\\n\\r\\n sendGift(uin, nick, qlogo) {\\r\\n //送礼物并关闭webview,此处省略\\r\\n //..\\r\\n //..\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n {{#uin_info}}\\r\\n
    \\r\\n
    \\r\\n \\r\\n
    \\r\\n
    \\r\\n
    {{{nick}}}
    \\r\\n
    \\r\\n {{#isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{^isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{#hasProfession_desc}} {{profession_desc}} {{/hasProfession_desc}}\\r\\n
    \\r\\n
    {{{intro}}}
    \\r\\n
    \\r\\n
    {{desc_d}} · {{desc_t}}
    \\r\\n
    \\r\\n {{/uin_info}}\\r\\n
    加载中...
    \\r\\n
    \\r\\n`\\r\\n }\\r\\n\\r\\n style() {\\r\\n return `\\r\\n\\r\\n\\r\\n.qlogo {\\r\\n overflow: hidden;\\r\\n width: 70px;\\r\\n height: 70px;\\r\\n -webkit-border-radius: 50%;\\r\\n border-radius: 50%;\\r\\n position: absolute;\\r\\n top: 10px;\\r\\n left: 12px;\\r\\n}\\r\\n...\\r\\n...\\r\\n..这里省略大量.....\\r\\n...\\r\\n...\\r\\n\\r\\n.distance_info {\\r\\n position: absolute;\\r\\n top: 15px;\\r\\n right: 9px;\\r\\n color: #7B7B84;\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nexport default UserList\\r\\n```\\r\\n\\r\\n组件里面有5个方法:\\r\\n\\r\\n* constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this\\r\\n* install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理\\r\\n* prepareData 对数据进行一些处理来满足模板的渲染\\r\\n* appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用\\r\\n* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..\\r\\n\\r\\n其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。\\r\\nrender里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;\\r\\n如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。\\r\\n\\r\\n这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)\\r\\n\\r\\n\\r\\n下面来看index.js:\\r\\n\\r\\n```js\\r\\nimport Root from \'./config.js\'\\r\\nimport Omi from \'omi\'\\r\\nimport UserList from \'../component/user_list/index.js\'\\r\\n\\r\\nOmi.makeHTML(\'UserList\', UserList)\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n installed() {\\r\\n window.onscroll = () => this.loadMore()\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n\\r\\n loadMore() {\\r\\n const body = document.body,\\r\\n html = document.documentElement,\\r\\n height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),\\r\\n vp_height = window.innerHeight\\r\\n\\r\\n if (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n }\\r\\n\\r\\n requestData(callback) {\\r\\n if (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }else{\\r\\n \\t//ajax 请求数据,这里省略\\r\\n }\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Main(),\'body\')\\r\\n```\\r\\n\\r\\n通过Omi.makeHTML(\'UserList\', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:\\r\\n\\r\\n```js\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n```\\r\\n\\r\\n下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。\\r\\n\\r\\n```js\\r\\nwindow.onscroll = () => this.loadMore()\\r\\n```\\r\\n\\r\\n通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:\\r\\n\\r\\n```js\\r\\nif (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n}\\r\\n```\\r\\n\\r\\nrequestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。\\r\\n慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:\\r\\n\\r\\n```js\\r\\n \\r\\n```\\r\\n\\r\\n上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!\\r\\n\\r\\n再来看下数据模拟:\\r\\n\\r\\n```js\\r\\nif (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }\\r\\n```\\r\\n\\r\\n这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!\\r\\n\\r\\n## 最后\\r\\n\\r\\n好了,就这么多,Omi让代码真心方便简洁~~~\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)"'; +},function(n,e){n.exports='module.exports = "# Omi命令行界面omi-cli发布\\r\\n\\r\\n通常认为,命令行界面(CLI)没有图形用户界面(GUI)那么方便用户操作。但是CLI比GUI节约资源,在熟悉命令之后,CLI会比GUI更加高效地帮你完成想要的任务。\\r\\n\\r\\n下面来介绍下[pasturn](https://github.com/pasturn)童鞋为Omi开发的CLI的两种使用姿势:\\r\\n\\r\\n## 姿势一\\r\\n\\r\\n```js\\r\\n$ npm install omi-cli -g //安装cli\\r\\n$ omi init your_project_name //初始化项目\\r\\n$ cd your_project_name //转到项目目录\\r\\n$ npm run dev //开发\\r\\n$ npm run dist //部署发布\\r\\n```\\r\\n\\r\\n## 姿势二\\r\\n\\r\\n当我们在一个空文件夹的时候,可以执行下面的命令。\\r\\n\\r\\n```js\\r\\n$ npm install omi-cli -g //安装cli\\r\\n$ omi init //初始化项目\\r\\n$ npm run dev //开发\\r\\n$ npm run dist //部署发布\\r\\n```\\r\\n\\r\\n这里不用再去跳转目录了,当前目录就是项目的目录。\\r\\n\\r\\n## 安装过程截图\\r\\n\\r\\n安装omi-cli:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100545470-696026058.png)\\r\\n\\r\\n\\r\\n安装初始化项目omi init:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100554891-1802174132.png)\\r\\n\\r\\n上面的成功的界面。注意:初始化项目会自动安装相关的npm依赖包,所以时间较长,请耐心等待。\\r\\n安装完成之后,在项目目录下你可以看到下面的目录结构:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100755845-465268116.png)\\r\\n\\r\\n开发 npm run dev:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100601235-1477801934.png)\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100608985-921528126.png)\\r\\n\\r\\n如果,你看到了上面的界面,说明一切OK了。创建出来的项目主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。Gulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n## 后续\\r\\n\\r\\n更多脚手架模板以及更多功能的命令正在开发中,如果有什么意见或者建议欢迎让我们知道。\\r\\n\\r\\n## 相关\\r\\n\\r\\n* Omi的Github地址[https://github.com/AlloyTeam/omi](https://github.com/AlloyTeam/omi)\\r\\n* 如果想体验一下Omi框架,可以访问 [Omi Playground](http://alloyteam.github.io/omi/example/playground/)\\r\\n* 如果想使用Omi框架或者开发完善Omi框架,可以访问 [Omi使用文档](https://github.com/AlloyTeam/omi/tree/master/docs#omi使用文档)\\r\\n* 如果你想获得更佳的阅读体验,可以访问 [Docs Website](http://alloyteam.github.io/omi/website/docs.html)\\r\\n* 如果你懒得搭建项目脚手架,可以试试 [omi-cli](https://github.com/AlloyTeam/omi/tree/master/cli)\\r\\n* 如果你有Omi相关的问题可以 [New issue](https://github.com/AlloyTeam/omi/issues/new)\\r\\n* 如果想更加方便的交流关于Omi的一切可以加入QQ的Omi交流群(256426170)\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170208095745213-1049686133.png)"'},function(n,e){n.exports='module.exports = "

    Component Communication

    \\r\\n\\r\\nCommunication between [Omi](https://github.com/AlloyTeam/omi) components is very flexible, there are many options:\\r\\n\\r\\n- By declaring `data-*` on the component to pass data to child node\\r\\n- By declaring `data` on the component to pass data to child node (support complex data types mapping)\\r\\n- By declaring `childrenData` on parent component to automatically pass data to child node\\r\\n- By declaring `group-data` (support complex data types mapping)\\r\\n- It\'s completely object-oriented, you can easily get the object instance, then you can set the instance of the property or call the instance of the method\\r\\n\\r\\nLet\'s see some examples.\\r\\n\\r\\n### Communicate by `data-*`\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n \\tcursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nGenerally `data-*` is used to pass value types such as string and number. It is worth noting that, through `data-*`, received data types are string. You need to manually transform it to the number type.\\r\\n\\r\\nNormally, communicate by `data-*` is enough, but sometimes we may need to use complex data types, then we can use `data` to communicate.\\r\\n\\r\\n### Communicate by `data`\\r\\n\\r\\nAs shown in the above code, name can be passed to the subcomponent by `data-name=\\"Omi\\"`. The following code can also achieve the same effect.\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.helloData = { name : \'Omi\' };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nUse the `data` tag, it will find the property from the component instance (that is, this), this can be mounted with any complex objects. This also broke the limitations of `data-*`.\\r\\n\\r\\nThen how do we pass `data` that is in a deep depth of the instance to the Hello? No worries, `data` tag can be a complex statement:\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nClick me for the complex data mapping\\r\\n\\r\\n### Communicate by `childrenData`\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.childrenData = [{ name : \'Omi\' } , { name : \'dntzhang\' }];\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nWe can use `this.childrenData` to transfer data to the sub-component. In this case, `childrenData` is an array, so it can pass data to multiple components in the same time. In the meanwhile, the data will be passed to components one by one.\\r\\n\\r\\n### Communicate by `group-data`\\r\\n\\r\\n`childrenData` can pass data to multiple components. However, there are many scenes where the source of data does not have to be from `childrenData`. `childrenData` is an array, and it should be the same order with the components, so that the data must all concentrated in `childrenData`, it\'s very inconvenient. `group-data` dedicated to solve the above pain points, specifically to pass data to a group of components.\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.testData = [{name: \'Omi\'}, {name: \'dntzhang\'}, {name: \'AlloyTeam\'}];\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nBy declaring a `group-data` tag in the sub-components, it will go to the current instance of the component (that is, `this`) to find the corresponding property. Then according to the current location, the data will pass to the positions one by one.\\r\\n\\r\\nThe results are as follows:\\r\\n\\r\\n![group-data results](http://images2015.cnblogs.com/blog/105416/201702/105416-20170216110701535-1698390390.png)\\r\\n\\r\\nClick me for the group-data example\\r\\n\\r\\nSimilarly, `group-data` supports the mapping of complex data types. It should be noted that the end of the group-data mapping must be an array:\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nClick me for the complex group-data mapping\\r\\n\\r\\n### By object instance\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n this.hello.data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n### By omi-id\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n Omi.get(\\"hello\\").data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nBy declaring `omi-id` on the component, we can get the instance of the object anywhere in the program. This can be regarded as any component communication artifacts.\\r\\n\\r\\n### Warm Tips\\r\\n\\r\\n- The data that passed by `childrenData` or `data` is shadow copied to sub-components. In order to update it, we need to update the `data` attribute of the component instance.\\r\\n- The data that passed by `data-*` is also shadow copied to sub-components. In order to update it, we need to update the `data` attribute of the component instance.\\r\\n- If we set the `dataFirst` property of the component instance to `false`, then `data-*` will override the `data` of component instance.\\r\\n\\r\\nFor the third tip, please checkout the pseudo-code:\\r\\n\\r\\n```js\\r\\nif(this.dataFirst){\\r\\n this.data = Object.assign({},data-✼ ,this.data);\\r\\n}else{\\r\\n this.data = Object.assign({},this.data, data-✼);\\r\\n}\\r\\n```"'},function(n,e){n.exports='module.exports = "

    Components

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is based entirely on component architecture, which allows developers to build web applications like building blocks. Everything is components, components can be nested to create new components.\\r\\n\\r\\n![Omi Components System](http://images2015.cnblogs.com/blog/105416/201702/105416-20170210093427338-1536910080.png)\\r\\n\\r\\n### Simple Components\\r\\n\\r\\nLet\'s explore a simple Todo example to learn the components system in Omi.\\r\\n\\r\\n```js\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.data.items.push(this.data.text);\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n
      {{#items}}
    • {{.}}
    • {{/items}}
    \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Todo({ items: [] ,text : \'\' }),\\"body\\");\\r\\n```\\r\\n\\r\\nThe HTML generated by the component will eventually be inserted into the body. The above example shows some of the features of Omi:\\r\\n\\r\\n- Data flow: `data` in `new Todo(data,..)` can be used directly in the template in render method.\\r\\n- Partial CSS: `h3` in `style()` only effect inside of render. It\'ll never pollute `h3` outside of this component. The same rule applies to `button`.\\r\\n- Declarative event binding: `onchange` will call `handleChange` that inside of the component. `this` refers to the current DOM element, `event` refers to the current DOM Event Object.\\r\\n- You need to manually call the `this.update()` method to update the component\\r\\n\\r\\nIt is important to note that, for more freedom and flexibility, Omi does not automatically update DOM while data changes. Developers need to call the `update` method manually.\\r\\n\\r\\nYou can also use [oba] (https://github.com/dntzhang/oba) or mobx to implement automatic updates.\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n## Component Nesting\\r\\n\\r\\nIt\'s ok to not use nesting component if your page is super simple. However, for most of webpages and web applications, it is a necessary to define the nesting Components to implement complex features.\\r\\n\\r\\nFor instance, we can extract a `List` component form the Todo example. This brings maintainable, scalable and reuseable to our project:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
      {{#items}}
    • {{.}}
    • {{/items}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nThen how to use this `List`? We need to use `Omi.makeHTML` to make the `List` to a tag which can be used in render method:\\r\\n\\r\\n```js\\r\\nimport List from \'./list.js\';\\r\\n\\r\\nOmi.makeHTML(\'List\', List);\\r\\n\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.data.length = this.data.items.length;\\r\\n this.listData = { items : this.data.items };\\r\\n }\\r\\n\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.list.data.items.push(this.data.text);\\r\\n this.data.length = this.list.data.items.length;\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n- In line 3, we use `makeHTML` to make the component to a tag which can be used in render method. Of course, `Omi.makeHTML(\'List\', List);` can also be written in the end of List component.\\r\\n- In line 9, the parent component defines the \'listData\' property\\r\\n- In line 34, we use List component in the render method. `name` attribute allows us easily find the instance of the component by using `this`.`data=\\"listData\\"` attribute allows us easily pass `this.listData` to the sub component from parent component.\\r\\n\\r\\nIt should be noted that the `data` passed from `data=\\"listData\\"` is cloned to the subcomponents by Object.assign(shallow copy) , which means if we want to change the DOM, we recommend that first update the `data` of the instance of subcomponent(not the parent component\'s `listData` ) and secondly call the `update` method.\\r\\n\\r\\nIn fact there are 4 way to communicate between components, it\'ll be explained later.\\r\\n\\r\\nClick me for the live demo\\r\\n"'},function(n,e){n.exports="module.exports = \"

    Conditional Rendering

    \\r\\n\\r\\nIn most case, we need to show different layouts according to different states. For example, some users are vip and we need to show vip logo for them. Omi has many ways to meet this kind of requirements.\\r\\n\\r\\n### First Option\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `{{#isVip}}\\r\\n
    you are VIP.
    \\r\\n {{/isVip}}\\r\\n {{^isVip}}\\r\\n
    you are not VIP.
    \\r\\n {{/isVip}}`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nIn the above case, we use the condition in mustachejs for rendering. Of course Omi does not force you to use mustachejs. You can use omi.lite.js and then override the `Omi.template` method to use any of your favorite template engines.\\r\\n\\r\\n### Second Option\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n`render` provides a very good programmability, which can write any js code inside. Oh, don't forget that `style` method can also have js code inside it.\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style (){\\r\\n if(this.data.isVip){\\r\\n return 'div{ color : red; }';\\r\\n }else{\\r\\n return 'div{ color : green; }';\\r\\n }\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\""},function(n,e){n.exports='module.exports = "

    Handling Events

    \\r\\n\\r\\nThere are two types of events in Omi, built-in events and custom events. Built-in events clever use of the browser\'s own pipeline mechanism, you can easily get events instance and the triggered event elements through `event` and `this`.\\r\\n\\r\\n### Built-in events\\r\\n\\r\\nWhat is the built-in event? As long as the it can match the following regular expression.\\r\\n\\r\\n```js\\r\\non(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave)\\r\\n```\\r\\n\\r\\nHow to bind built-in events? As follows:\\r\\n\\r\\n```js\\r\\nclass EventTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n handleClick(dom, evt){\\r\\n alert(dom.innerHTML);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Hello, Omi!
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### Custom events\\r\\n\\r\\nEvents that defined by developers is the custom events. Here is the pagination example:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\nimport Pagination from \'./pagination.js\';\\r\\nimport Content from \'./content.js\';\\r\\n\\r\\nOmi.makeHTML(\'Pagination\', Pagination);\\r\\nOmi.makeHTML(\'Content\', Content);\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.content.goto(this.pagination.data.currentPage+1);\\r\\n }\\r\\n handlePageChange(index){\\r\\n this.content.goto(index+1);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    Pagination Example

    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render( new Main(),\'body\');\\r\\n```\\r\\n\\r\\nAs we can see, the `onPageChange` is a custom event, `handlePageChange` will being executed when `onPageChange` is triggered. The `onPageChange` method is executed in `Pagination`:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\n\\r\\nclass Pagination extends Omi.Component {\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n linkTo: \\"#\\",\\r\\n prevText: \\"Prev\\",\\r\\n nextText: \\"Next\\",\\r\\n ellipseText: \\"...\\",\\r\\n prevShow: true,\\r\\n nextShow: true,\\r\\n onPageChange: function () { return false; }\\r\\n }, this.data);\\r\\n\\r\\n this.pageNum = Math.ceil(this.data.total / this.data.pageSize);\\r\\n }\\r\\n goto (index,evt) {\\r\\n evt.preventDefault();\\r\\n this.data.currentPage=index;\\r\\n this.update();\\r\\n this.data.onPageChange(index);\\r\\n }\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\nThis is a part of `Pagination` code. Highlight is the place to execute `onPageChange`.\\r\\n\\r\\n### Links\\r\\n\\r\\n- [Demo](http://alloyteam.github.io/omi/example/pagination/)\\r\\n- [Source](https://github.com/AlloyTeam/omi/tree/master/example/pagination)"'},function(n,e){n.exports='module.exports = "

    Forms

    \\r\\n\\r\\nIt\'s much more convenient to control forms in Omi, especially `\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n\\r\\n```\\r\\n\\r\\nThe third option is selected because it is being set to `selected` attribute. The problem is that developers need to traversed each option. While using Omi, you can write code like this:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\nThis will achieve the same effect. For example, you want to choose the first item:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\nIsn\'t it very convenient?\\r\\n\\r\\n### For Example\\r\\n\\r\\n```js\\r\\nclass FormTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n \\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n console.log(target.value)\\r\\n this.data.value = target.value;\\r\\n }\\r\\n\\r\\n handleSubmit(evt) {\\r\\n alert(\'Your favorite flavor is: \' + this.data.value);\\r\\n evt.preventDefault();\\r\\n }\\r\\n \\r\\n render () {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new FormTest({ value: \'mango\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for a live demo"'},function(n,e){n.exports='module.exports = "

    Get DOM

    \\r\\n\\r\\nWhile most of the time, developers do not need to find the DOM, but sometimes is a need to get the DOM.\\r\\n\\r\\nOmi provides a way to get the DOM node.\\r\\n\\r\\n### ref and refs\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(){\\r\\n alert(this.refs.abc.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\nAs we can see, by referencing `ref` as `abc` in HTML, the DOM node can be accessed through `this.refs.abc`.\\r\\n\\r\\nClick me for the live demo\\r\\n"'},function(n,e){n.exports='module.exports = "

    Hello World

    \\r\\n\\r\\n\\r\\n### Hello World with ES20XX \\r\\n\\r\\nWe recommend using a bundler like [webpack](https://webpack.github.io/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time.\\r\\n\\r\\nThe small Omi example looks like this:\\r\\n\\r\\n```js\\r\\nimport Omi from \'./omi.js\';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"body\\");\\r\\n\\r\\n```\\r\\n\\r\\nThis code renders into body element. \\r\\n\\r\\n\\r\\n### Hello World with ES5\\r\\n\\r\\n\\r\\n```html\\r\\n\\r\\n```"'},function(n,e){n.exports='module.exports = "

    Inheritance

    \\r\\n\\r\\nThrough the inheritance mechanism, we can define new classes base on old classes. The new classes not only have newly defined members, but also have old members at the same time.\\r\\n\\r\\nWe call the existing class the base class, also known as the parent class. And the new class derived from the existing class is called a derived class, also known as a subclass.\\r\\n\\r\\n### For Example\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n div{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n}\\r\\n\\r\\nclass SubHello extends Hello {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n### inherit in ES5\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\",{\\r\\n render:function(){\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n})\\r\\n\\r\\nvar SubHello = Omi.create(\\"SubHello\\",Hello,{ });\\r\\n\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports='module.exports = "

    Installation

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is open and modern framework for building user interfaces.\\r\\n\\r\\n### Installing Omi\\r\\n\\r\\nWe recommend using [npm](https://www.npmjs.com/) for managing front-end dependencies. If you\'re new to package managers.\\r\\n\\r\\nTo install Omi with npm, run:\\r\\n\\r\\n``` js\\r\\nnpm install omi\\r\\n```\\r\\n### omi-cli\\r\\n\\r\\n``` js\\r\\n$ npm install omi-cli -g \\r\\n$ omi init your_project_name \\r\\n$ cd your_project_name \\r\\n$ npm run dev \\r\\n$ npm run dist \\r\\n```"'; +},function(n,e){n.exports='module.exports = "

    Lifecycle

    \\r\\n\\r\\n| Name | Meaning | Occasion |\\r\\n| :-------------: | :-------------: | :-----: |\\r\\n| constructor | The constructor | When new a constructor |\\r\\n| install | The installation. We can process the data that user pass | When instantiate |\\r\\n| installed | Complete the installation. It\'ll trigger after HTML being inserted to the page. Please note that it\'ll trigger when component being removed and restored | **Instantiation and existence** |\\r\\n| uninstall | Uninstall the component. It\'ll trigger when remove is executed | When destroy |\\r\\n| beforeUpdate | Before update | When existence |\\r\\n| afterUpdate | After update | When existence |\\r\\n\\r\\n## Illustration\\r\\n\\r\\n![lc](http://images2015.cnblogs.com/blog/105416/201701/105416-20170119153018546-1566368987.png)\\r\\n\\r\\nIt should be noted that the installed will be executed during the instantiation, which is not shown above. For example, it\'ll executed when a component is removed and restored, or when the new component is being added.\\r\\n\\r\\n### Examples\\r\\n\\r\\n```js\\r\\nclass Timer extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n install () {\\r\\n this.data = {secondsElapsed: 0};\\r\\n }\\r\\n\\r\\n tick() {\\r\\n this.data.secondsElapsed++;\\r\\n this.update();\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.interval = setInterval(() => this.tick(), 1000);\\r\\n }\\r\\n\\r\\n uninstall() {\\r\\n clearInterval(this.interval);\\r\\n }\\r\\n\\r\\n\\r\\n style () {\\r\\n return `\\r\\n .num { color:red; }\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Seconds Elapsed: {{secondsElapsed}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports='module.exports = "

    Loop

    \\r\\n\\r\\nThe following describes how to traverses in mustache.js and javascript.\\r\\n\\r\\n### First Option\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n
      \\r\\n {{#items}} \\r\\n
    • {{text}}
    • \\r\\n {{/items}}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nMustache.js more detailed loop traversal use can see \\r\\n\\r\\nFor more details for traversal in mustache.js please view [https://github.com/janl/mustache.js#non-empty-lists](https://github.com/janl/mustache.js#non-empty-lists).\\r\\n\\r\\nFor example, it also support:\\r\\n\\r\\n- If each item of items is a string, you can directly use **{{.}}** to output each item\\r\\n- Call the defined function when looping\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n### Second Option\\r\\n\\r\\nOf course, you can also use template string inside the `map`:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `
    \\r\\n
      \\r\\n ${this.data.items.map(item =>\\r\\n `
    • ${item.text}
    • `\\r\\n ).join(\'\')}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nYou will see the following page:\\r\\n\\r\\n![pv](http://images2015.cnblogs.com/blog/105416/201701/105416-20170122095724129-2059595233.png)\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports="module.exports = \"

    Plugin

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is a componentized web framework. Then what is plugin?\\r\\n\\r\\nIt can be understood that the Omi plugin system can give the dom element some ability and can be associated with the instance of the components.\\r\\n\\r\\n### omi-drag\\r\\n\\r\\nLet's see this example:\\r\\n\\r\\nClick me for the live deme\\r\\n\\r\\n```js\\r\\nimport OmiDrag from './omi-drag.js';\\r\\n\\r\\nOmiDrag.init();\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n\\r\\n style(){\\r\\n return `\\r\\n .test{\\r\\n width:100px;\\r\\n height:100px;\\r\\n color:white;\\r\\n line-height:90px;\\r\\n text-align:center;\\r\\n background-color:#00BFF3;\\r\\n }\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\\"#container\\\");\\r\\n```\\r\\n\\r\\nAs shown above, by adding `omi-drag` attribute to the div, it can be dragged by the user using the mouse. We call omi-drag.js an omi plugin.\\r\\n\\r\\nIsn't it very convenient? So how did this omi-drag implement?\\r\\n\\r\\n如上面的代码所示,通过在div上标记omi-drag,这个div就能够被用户使用鼠标拖拽。我们称omi-drag.js为omi插件。\\r\\n是不是非常方便?那么这个omi-drag是怎么实现的?\\r\\n\\r\\n## Omi.extendPlugin\\r\\n\\r\\nCore method: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\nThe following code shows how to use `Omi.extendPlugin` to give dom the drap and drop ability:\\r\\n\\r\\n```js\\r\\n;(function () {\\r\\n\\r\\n var OmiDrag = {};\\r\\n var Omi = typeof require === 'function'\\r\\n ? require('omi')\\r\\n : window.Omi;\\r\\n\\r\\n OmiDrag.init = function(){\\r\\n Omi.extendPlugin('omi-drag',function(dom, instance){\\r\\n dom.style.cursor='move';\\r\\n var isMouseDown = false,\\r\\n preX = null,\\r\\n preY = null,\\r\\n currentX = null,\\r\\n currentY = null,\\r\\n translateX = 0,\\r\\n translateY = 0;\\r\\n\\r\\n dom.addEventListener('mousedown',function(evt){\\r\\n isMouseDown = true;\\r\\n preX = evt.pageX;\\r\\n preY = evt.pageY;\\r\\n evt.stopPropagation();\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n }\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mouseup',function(){\\r\\n isMouseDown = false;\\r\\n preX = preY = currentX = currentY = null;\\r\\n },false);\\r\\n });\\r\\n }\\r\\n\\r\\n OmiDrag.destroy = function(){\\r\\n delete Omi.plugins['omi-drag'];\\r\\n };\\r\\n\\r\\n if (typeof exports == \\\"object\\\") {\\r\\n module.exports = OmiDrag;\\r\\n } else if (typeof define == \\\"function\\\" && define.amd) {\\r\\n define([], function(){ return OmiDrag });\\r\\n } else {\\r\\n window.OmiDrag = OmiDrag;\\r\\n }\\r\\n\\r\\n})();\\r\\n```\\r\\n\\r\\nMethod: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n`pluginName` is the name of the plugin.\\r\\n\\r\\n`handler` is the processor. The handler can get the dom which marked as the `pluginName` and the instance of the component.\\r\\n\\r\\nWith `Omi.extendPlugin`, we can give the dom some ability, and can also be associated with the component instance.\\r\\n\\r\\nThe above example is not associated with the instance, let's try it:\\r\\n\\r\\n## Associated with instance\\r\\n\\r\\nWe want to be able to listen to the `move` inside the component and perform a callback. As follows:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandler(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nIn this case, the `moveHandler` will be continually executed while dragging. We can modify some code to solve this issue:\\r\\n\\r\\n```js\\r\\n...\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance.moveHandler(evt);\\r\\n }\\r\\n},false);\\r\\n```\\r\\n\\r\\nWe add `instance.moveHandler(evt)` method to execute the `moveHandler` method of component instance.\\r\\n\\r\\nThis is how associated with instance works.\\r\\n\\r\\nHowever, this may still have an issue if we add `omi-drag` to a list of `div`:\\r\\n\\r\\n```js\\r\\n...\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nUsually each of our `omi-drag` can correspond to a callback function, such as:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nHow to achieve this? We can pass the data to the plugin via dom.\\r\\n\\r\\n## Passing data\\r\\n\\r\\nLet's see the final code:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nWhere `omi-drag` modified:\\r\\n\\r\\n```js\\r\\n...\\r\\nvar handlerName = dom.getAttribute('dragMove');\\r\\n\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance[handlerName](evt);\\r\\n }\\r\\n},false);\\r\\n...\\r\\n```\\r\\n\\r\\n- We use `var handlerName = dom.getAttribute('dragMove')` to get the `dragMove` of dom\\r\\n- We use `instance[handlerName](evt)` to execute the method\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n## More plugins\\r\\n\\r\\n* [omi-finger](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-finger) The [AlloyFinger](https://github.com/AlloyTeam/AlloyFinger) plugin for Omi, which support touch events and gustures\\r\\n* [omi-transform](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-transform) The [transformjs](http://alloyteam.github.io/AlloyTouch/transformjs/) plugin for Omi, which can easily set CSS3 Transform to DOM\\r\\n* [omi-touch](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-touch) The [AlloyTouch](https://github.com/AlloyTeam/AlloyTouch) plugin for Omi. The touch movement solution for Omi (support touch scroll, rotate, flip, select, etc.)\\r\\n* [omi-jquery-date-picker](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-jquery-date-picker) The date picker plugin for Omi, which support choose any time zone\\r\\n\""},function(n,e){n.exports='module.exports = "

    Templates

    \\r\\n\\r\\nThere are three types of Omi. omi.js and omi.lite.js is for web side.\\r\\n\\r\\n- omi.js has a built-in [mustache.js](https://github.com/janl/mustache.js) as the template engine\\r\\n- omi.lite.js doesn\'t have any template engines\\r\\n\\r\\nOmi does not force developers to use mustache.js, you can use any template engine based on business scenarios or do not use any template engines.\\r\\n\\r\\nHow to use other template engines? Let\'s see the [artTemplate](https://github.com/aui/artTemplate) example.\\r\\n\\r\\n### Use artTemplate\\r\\n\\r\\n```js\\r\\nOmi.template = function(tpl, data){\\r\\n return artTemplate.compile(tpl)(data);\\r\\n}\\r\\n```\\r\\n\\r\\nWe need to rewrite the `Omi.template` method, the `tpl` is the incoming template, the `data` is the required data for the template, and the return value is HTML.\\r\\n\\r\\nAfter rewriting, you can use the artTemplate syntax in `render`, such as:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h1 { color:red; }\\r\\n li{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `

    {{title}}

    \\r\\n
      \\r\\n {{each list as value i}}\\r\\n
    • # {{i + 1}} :{{value}}
    • \\r\\n {{/each}}\\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### Links\\r\\n\\r\\n* [Demo Link](http://alloyteam.github.io/omi/example/artTemplate/)\\r\\n* [Source Code](https://github.com/AlloyTeam/omi/tree/master/example/artTemplate)"'},function(n,e){n.exports='module.exports = "

    Thinking in Omi

    \\r\\n\\r\\nOmi is based on object-oriented programming, with plugin system.\\r\\n\\r\\nThe traditional one-way data flow or the event-throwing component communicating can increase the stability of the system, but it loses it\'s flexibility. To a certain extent also reduced the component reusing.\\r\\n\\r\\nObject-oriented system has an other logical layer, which let you control the instance of components. The logic between instances build the entire program.\\r\\n\\r\\nThen the issues like communication, reusing and logics between components are all solved.\\r\\n\\r\\n\\r\\nPlus, the component is also more single duty, more loosely coupled.\\r\\n\\r\\nFor functional programming, imperative programming and object-oriented programming, we can sum up the following list:\\r\\n\\r\\n- Imperative programming is well understood, we use loop and if-else condition to control processes, it emphasize the process of execution\\r\\n- Imperative programming is hardware friendly, easy to run, but hard to design complex program\\r\\n- Functional programming is all about input and output, not the process of execution\\r\\n- Functional programming advocates multiple simple execution units into complex operations\\r\\n- Object-oriented programming uses objects as the basic unit of the program, with more reusability, flexibility, and extensibility\\r\\n\\r\\nWhat kind of language is JavaScript? We have `class` in ES6+, so is JavaScript object-oriented language?\\r\\n\\r\\nJavaScript can pass a function as a argumant, so is JavaScript a functional language?\\r\\n\\r\\nThere are no right answer, it depands on how you use JavaScript.\\r\\n\\r\\nIt\'s free to chooce, you can use functional programming framework like React, or object-oriented framework like Omi. \\r\\n\\r\\n### Functional Programming VS Object-Oriented Programming\\r\\n\\r\\nIn the UI component framework scope, functional programming is represented by React, while Omi belongs to object-oriented programming.\\r\\n\\r\\nSo what are their strengths and weaknesses? The following is a comparison (in fact, functional programming and object-oriented programming comparison):\\r\\n\\r\\n| | React | Omi |\\r\\n| ------------- |:-------------:|:-----:|\\r\\n| Component communication | ★★★★☆| ★★★★★ |\\r\\n| Stability | ★★★★★ | ★★★★☆ |\\r\\n| Flexibility | ★★★★☆| ★★★★★ |\\r\\n| Scalability | ★★★★☆ | ★★★★★ |\\r\\n| Testability | ★★★★★ | ★★★★☆ |\\r\\n| File size | ★★★☆☆ | ★★★★★ |\\r\\n| Features | ★★★☆☆ | ★★★★☆ |\\r\\n| DOM performance | ★★★★★ | ★★★★☆ |\\r\\n| Animation performance | ★★★★☆ | ★★★★★ |\\r\\n| Abstract complexity | ★★★★☆ | ★★★★★ |\\r\\n| Asynchronous programming | ★★★★★ | ★★★★☆ |\\r\\n\\r\\nAs we can see, we can not have it both ways. Object-oriented programming is more reusable, flexible and scalable, the problem is more difficult to test.\\r\\n\\r\\nSpecifically, if the functional programming, the test area is state1 + state2 + ... + stateN; in object-oriented programming, the test area is state1 × event1 + state2 × event2 + ... + stateN × eventN.\\r\\n\\r\\nIn summary, it is more recommended to use the object-oriented programming to build UI component framework.\\r\\n\\r\\n
    \\r\\n\\r\\n### The end. Thanks for reading. [Let\'s start the Omi journey](https://github.com/AlloyTeam/omi)!\\r\\n"'},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n @media only screen and (max-width: 768px) {\n .list{\n transform: translateX(-100%);\n background-color:white;\n\n -moz-transition: all .6s ease;\n -o-transition: all .6s ease;\n -webkit-transition: all .6s ease;\n transition: all .6s ease;\n }\n\n .list.show {\n -moz-transform: translateX(0%) translateZ(0);\n -ms-transform: translateX(0%) translateZ(0);\n -o-transform: translateX(0%) translateZ(0);\n -webkit-transform: translateX(0%) translateZ(0);\n transform: translateX(0%) translateZ(0);\n }\n }\n\n .list{\n width:200px;\n text-indent: 20px;\n border-right: 1px solid #eee;\n overflow-x: hidden;\n overflow-y: auto;\n position:fixed;\n top:45px;\n }\n .version{\n height:20px;\n }\n \n "}},{key:"render",value:function(){return'\n
    \n
    \n {{#items}} {{/items}}\n
    '}}]),e}(d.default.Component);e.default=h},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n
  • {{title}}
  • \n {{#list}}\n
  • \n {{name}}\n
  • \n {{/list}}\n '}},{key:"style",value:function(){return"\n \n "}}]),e}(d.default.Component);e.default=c},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n .head{\n position:fixed;\n height:45px;\n line-height: 45px;\n border-bottom: 1px solid #eee;\n width:100%;\n background-color:#303030;\n z-index:100;\n\n }\n ul,li{\n display: inline-block;\n }\n .logo_box{\n width:100px;\n display: inline-block;\n text-align:center;\n line-height: 60px;\n }\n .menu a,.logo_box a{\n display: inline-block;\n height:45px;\n color:#ddd;\n }\n .menu{\n position: absolute;\n right:20px;\n }\n .menu li{\n margin-left:15px;\n }\n .logo_box a{\n font-size: 34px;\n font-weight: bold;\n color: #00bff3;\n padding: 0px 15px;\n line-height: 45px;\n cursor: pointer;\n }\n .menu a:hover{\n color: white;\n }\n\n .m_menu{\n position:fixed;\n display:none;\n }\n\n @media only screen and (max-width: 768px) {\n .menu li{\n display:none;\n }\n .menu .m_show{\n display:block;\n }\n\n .logo_box{\n display:inline-block;\n }\n\n .head{\n text-align:center;\n }\n\n .m_menu{\n\n top:0;\n left:0;\n display:block;\n width:50px;\n height:50px;\n padding-top: 6px;\n }\n .m_menu img{\n width:30px;\n }\n\n }\n \n "}},{key:"render",value:function(){return'\n
    \n \n
    \n Omi\n
    \n \n
    '}}]),e}(d.default.Component);e.default=m},function(n,e,r){var t,i,o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(){var a={},s=r(52),l=r(2),d=function(){},c=function(n,e,r){var t="on"+n.substring(0,1).toUpperCase()+n.substring(1),i=e.getAttribute(t);return null===i?d:r[i].bind(r)};a.init=function(){l.extendPlugin("omi-finger",function(n,e){e.alloyFinger&&e.alloyFinger.destroy();var r=new s(n,{touchStart:c("touchStart",n,e),touchMove:c("touchMove",n,e),touchEnd:c("touchEnd",n,e),touchCancel:c("touchCancel",n,e),multipointStart:c("multipointStart",n,e),multipointEnd:c("multipointEnd",n,e),tap:c("tap",n,e),doubleTap:c("doubleTap",n,e),longTap:c("longTap",n,e),singleTap:c("singleTap",n,e),rotate:c("rotate",n,e),pinch:c("pinch",n,e),pressMove:c("pressMove",n,e),swipe:c("swipe",n,e)});e.alloyFinger=r})},a.destroy=function(){delete l.plugins["omi-finger"]},"object"==o(e)?n.exports=a:(t=[],i=function(){return a}.apply(e,t),!(void 0!==i&&(n.exports=i)))}()},function(n,e,r){"use strict";var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(){function r(n){return Math.sqrt(n.x*n.x+n.y*n.y)}function i(n,e){return n.x*e.x+n.y*e.y}function o(n,e){var t=r(n)*r(e);if(0===t)return 0;var o=i(n,e)/t;return o>1&&(o=1),Math.acos(o)}function a(n,e){return n.x*e.y-e.x*n.y}function s(n,e){var r=o(n,e);return a(n,e)>0&&(r*=-1),180*r/Math.PI}function l(n,e){var r=new d(n);return r.add(e),r}var d=function(n){this.handlers=[],this.el=n};d.prototype.add=function(n){this.handlers.push(n)},d.prototype.del=function(n){n||(this.handlers=[]);for(var e=this.handlers.length;e>=0;e--)this.handlers[e]===n&&this.handlers.splice(e,1)},d.prototype.dispatch=function(){for(var n=0,e=this.handlers.length;n0&&this.delta<=250&&Math.abs(this.preTapPosition.x-this.x1)<30&&Math.abs(this.preTapPosition.y-this.y1)<30),this.preTapPosition.x=this.x1,this.preTapPosition.y=this.y1,this.last=this.now;var e=this.preV,t=n.touches.length;if(t>1){this._cancelLongTap(),this._cancelSingleTap();var i={x:n.touches[1].pageX-this.x1,y:n.touches[1].pageY-this.y1};e.x=i.x,e.y=i.y,this.pinchStartLen=r(e),this.multipointStart.dispatch(n)}this.longTapTimeout=setTimeout(function(){this.longTap.dispatch(n)}.bind(this),750)}},move:function(n){if(n.touches){var e=this.preV,t=n.touches.length,i=n.touches[0].pageX,o=n.touches[0].pageY;if(this.isDoubleTap=!1,t>1){var a={x:n.touches[1].pageX-i,y:n.touches[1].pageY-o};null!==e.x&&(this.pinchStartLen>0&&(n.scale=r(a)/this.pinchStartLen,this.pinch.dispatch(n)),n.angle=s(a,e),this.rotate.dispatch(n)),e.x=a.x,e.y=a.y}else null!==this.x2?(n.deltaX=i-this.x2,n.deltaY=o-this.y2):(n.deltaX=0,n.deltaY=0),this.pressMove.dispatch(n);this.touchMove.dispatch(n),this._cancelLongTap(),this.x2=i,this.y2=o,t>1&&n.preventDefault()}},end:function(n){if(n.changedTouches){this._cancelLongTap();var e=this;n.touches.length<2&&this.multipointEnd.dispatch(n),this.touchEnd.dispatch(n),this.x2&&Math.abs(this.x1-this.x2)>30||this.y2&&Math.abs(this.preV.y-this.y2)>30?(n.direction=this._swipeDirection(this.x1,this.x2,this.y1,this.y2),this.swipeTimeout=setTimeout(function(){e.swipe.dispatch(n)},0)):(this.tapTimeout=setTimeout(function(){e.tap.dispatch(n),e.isDoubleTap&&(e.doubleTap.dispatch(n),clearTimeout(e.singleTapTimeout),e.isDoubleTap=!1)},0),e.isDoubleTap||(e.singleTapTimeout=setTimeout(function(){e.singleTap.dispatch(n)},250))),this.preV.x=0,this.preV.y=0,this.scale=1,this.pinchStartLen=null,this.x1=this.x2=this.y1=this.y2=null}},cancel:function(n){clearTimeout(this.tapTimeout),clearTimeout(this.singleTapTimeout),clearTimeout(this.longTapTimeout),clearTimeout(this.swipeTimeout),this.touchCancel.dispatch(n)},_cancelLongTap:function(){clearTimeout(this.longTapTimeout)},_cancelSingleTap:function(){clearTimeout(this.singleTapTimeout)},_swipeDirection:function(n,e,r,t){return Math.abs(n-e)>=Math.abs(r-t)?n-e>0?"Left":"Right":r-t>0?"Up":"Down"},on:function(n,e){this[n]&&this[n].add(e)},off:function(n,e){this[n]&&this[n].del(e)},destroy:function(){return this.tapTimeout&&clearTimeout(this.tapTimeout),this.singleTapTimeout&&clearTimeout(this.singleTapTimeout),this.longTapTimeout&&clearTimeout(this.longTapTimeout),this.swipeTimeout&&clearTimeout(this.swipeTimeout),this.element.removeEventListener("touchstart",this.start),this.element.removeEventListener("touchmove",this.move),this.element.removeEventListener("touchend",this.end),this.element.removeEventListener("touchcancel",this.cancel),this.rotate.del(),this.touchStart.del(),this.multipointStart.del(),this.multipointEnd.del(),this.pinch.del(),this.swipe.del(),this.tap.del(),this.doubleTap.del(),this.longTap.del(),this.singleTap.del(),this.pressMove.del(),this.touchMove.del(),this.touchEnd.del(),this.touchCancel.del(),this.preV=this.pinchStartLen=this.scale=this.isDoubleTap=this.delta=this.last=this.now=this.tapTimeout=this.singleTapTimeout=this.longTapTimeout=this.swipeTimeout=this.x1=this.x2=this.y1=this.y2=this.preTapPosition=this.rotate=this.touchStart=this.multipointStart=this.multipointEnd=this.pinch=this.swipe=this.tap=this.doubleTap=this.longTap=this.singleTap=this.pressMove=this.touchMove=this.touchEnd=this.touchCancel=null,null}},"undefined"!=typeof n&&"object"===t(e)?n.exports=c:window.AlloyFinger=c}()},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n {{#preName}} ←{{preName}}{{/preName}}\n {{#nextName}} {{/nextName}}\n ':'\n
    \n {{#preName}} ←{{preName}}{{/preName}}\n {{#nextName}} {{/nextName}}\n
    '}},{key:"style",value:function(){return"\n \n "}}]),e}(d.default.Component);e.default=h}]); \ No newline at end of file diff --git a/website/dist/bundler_en.js b/website/dist/bundler_en.js index 854bb9b45..127fd235b 100644 --- a/website/dist/bundler_en.js +++ b/website/dist/bundler_en.js @@ -2,8 +2,9 @@ * mustache.js - Logic-less {{mustache}} templates with JavaScript * http://github.com/janl/mustache.js */ -!function(r,s){"object"===a(e)&&e&&"string"!=typeof e.nodeName?s(e):(i=[e],t=s,o="function"==typeof t?t.apply(e,i):t,!(void 0!==o&&(n.exports=o)))}(void 0,function(n){function e(n){return"function"==typeof n}function r(n){return g(n)?"array":"undefined"==typeof n?"undefined":a(n)}function t(n){return n.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function i(n,e){return null!=n&&"object"===("undefined"==typeof n?"undefined":a(n))&&e in n}function o(n,e){return v.call(n,e)}function s(n){return!o(b,n)}function l(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return y[n]})}function d(e,r){function i(){if(v&&!b)for(;f.length;)delete h[f.pop()];else f=[];v=!1,b=!1}function o(n){if("string"==typeof n&&(n=n.split(w,2)),!g(n)||2!==n.length)throw new Error("Invalid tags: "+n);a=new RegExp(t(n[0])+"\\s*"),l=new RegExp("\\s*"+t(n[1])),d=new RegExp("\\s*"+t("}"+n[1]))}if(!e)return[];var a,l,d,p=[],h=[],f=[],v=!1,b=!1;o(r||n.tags);for(var y,k,j,C,S,M,H=new m(e);!H.eos();){if(y=H.pos,j=H.scanUntil(a))for(var L=0,D=j.length;L0?o[o.length-1][4]:t;break;default:i.push(e)}return t}function m(n){this.string=n,this.tail=n,this.pos=0}function p(n,e){this.view=n,this.cache={".":this.view},this.parent=e}function h(){this.cache={}}var f=Object.prototype.toString,g=Array.isArray||function(n){return"[object Array]"===f.call(n)},v=RegExp.prototype.test,b=/\S/,y={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},x=/\s*/,w=/\s+/,O=/\s*=/,_=/\s*\}/,T=/#|\^|\/|>|\{|&|=|!/;m.prototype.eos=function(){return""===this.tail},m.prototype.scan=function(n){var e=this.tail.match(n);if(!e||0!==e.index)return"";var r=e[0];return this.tail=this.tail.substring(r.length),this.pos+=r.length,r},m.prototype.scanUntil=function(n){var e,r=this.tail.search(n);switch(r){case-1:e=this.tail,this.tail="";break;case 0:e="";break;default:e=this.tail.substring(0,r),this.tail=this.tail.substring(r)}return this.pos+=e.length,e},p.prototype.push=function(n){return new p(n,this)},p.prototype.lookup=function(n){var r,t=this.cache;if(t.hasOwnProperty(n))r=t[n];else{for(var o,a,s=this,l=!1;s;){if(n.indexOf(".")>0)for(r=s.view,o=n.split("."),a=0;null!=r&&a"===o?a=this.renderPartial(i,e,r,t):"&"===o?a=this.unescapedValue(i,e):"name"===o?a=this.escapedValue(i,e):"text"===o&&(a=this.rawValue(i)),void 0!==a&&(s+=a);return s},h.prototype.renderSection=function(n,r,t,i){function o(n){return s.render(n,r,t)}var s=this,l="",d=r.lookup(n[1]);if(d){if(g(d))for(var c=0,u=d.length;c",this.HTML):(this._mergeData(n),this._generateHTMLCSS(),this._extractChildren(this),e&&this.children.forEach(function(n,e){r._omi_order[e]=e}),this.children.forEach(function(n,e){r.HTML=r.HTML.replace(n._omiChildStr,r.children[r._omi_order[e]].HTML)}),this.HTML=(0,u.default)(this.HTML,this.id),this.HTML)}},{key:"_queryElements",value:function(n){n._mixRefs(),n._execPlugins(),n.children.forEach(function(e){e.node=n.node.querySelector("["+s.default.STYLESCOPEDPREFIX+e.id+"]"),n._queryElements(e)})}},{key:"_mixRefs",value:function(){var n=this,e=s.default.$$("*[ref]",this.node);e.forEach(function(e){e.hasAttribute(n._omi_scoped_attr)&&(n.refs[e.getAttribute("ref")]=e)});var r=this.node.getAttribute("ref");r&&(this.refs[r]=this.node)}},{key:"_execPlugins",value:function(){var n=this;Object.keys(s.default.plugins).forEach(function(e){var r=s.default.$$("*["+e+"]",n.node);r.forEach(function(r){r.hasAttribute(n._omi_scoped_attr)&&s.default.plugins[e](r,n)}),n.node.hasAttribute(e)&&s.default.plugins[e](n.node,n)})}},{key:"_childrenInstalled",value:function(n){var e=this;n.children.forEach(function(n){e._childrenInstalled(n),n.installed()})}},{key:"_fixForm",value:function(){s.default.$$("input",this.node).forEach(function(n){var e=n.type.toLowerCase();""===n.getAttribute("value")&&(n.value=""),"checked"!==e&&"radio"!==e||(n.hasAttribute("checked")?n.checked="checked":n.checked=!1)}),s.default.$$("textarea",this.node).forEach(function(n){n.value=n.getAttribute("value")}),s.default.$$("select",this.node).forEach(function(n){var e=n.getAttribute("value");if(e)s.default.$$("option",n).forEach(function(n){e===n.getAttribute("value")&&n.setAttribute("selected","selected")});else{var r=s.default.$$("option",n)[0];r&&r.setAttribute("selected","selected")}})}},{key:"_replaceTags",value:function(n,e){var r=n.join("|"),t=new RegExp("<("+r+"+)((?:\\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*)\\s*(\\/?)>","g");return e.replace(t,function(n,e){var r=n.length-2;return r>=0&&n.lastIndexOf("/>")===n.length-2?n.replace("<"+e,'":n.lastIndexOf(">")===n.length-1?n.replace("<"+e,'":void 0})}},{key:"_createHiddenNode",value:function(){var n=document.createElement("input");return n.setAttribute("type","hidden"),n.setAttribute(this._omi_scoped_attr,""),n}},{key:"_mergeData",value:function(n){this.dataFirst?this.data=Object.assign({},this._getDataset(n),this.data):this.data=Object.assign({},this.data,this._getDataset(n))}},{key:"_generateHTMLCSS",value:function(){this.CSS=(this.style()||"").replace(/<\/?style>/g,""),this.CSS&&(this.CSS=d.default.scoper(this.CSS,"["+this._omi_scoped_attr+"]"),this.CSS===this._preCSS||this._omi_server_rendering||(d.default.addStyle(this.CSS,this.id),this._preCSS=this.CSS));var n=this.render();this.HTML=this._scopedAttr(s.default.template(n?n:"",this.data),this._omi_scoped_attr).trim(),this._omi_server_rendering&&(this.HTML='\r\n\r\n"+this.HTML,this.HTML+='\r\n\r\n")}},{key:"_scopedAttr",value:function(n,e){return n.replace(/<[^\/]([A-Za-z]*)[^>]*>/g,function(n){var r=n.split(" ")[0].replace(">","");return n.replace(r,r+" "+e)})}},{key:"_getDataset",value:function(n){var e=this,r=(0,f.default)(n),t=r.child[0].attr;return Object.keys(t).forEach(function(n){0===n.indexOf("data-")&&(e._dataset[e._capitalize(n.replace("data-",""))]=t[n])}),this._dataset}},{key:"_capitalize",value:function(n){return n=n.toLowerCase(),n=n.replace(/\b\w+\b/g,function(n){return n.substring(0,1).toUpperCase()+n.substring(1)}).replace(/-/g,""),n.substring(0,1).toLowerCase()+n.substring(1)}},{key:"_extractPropertyFromString",value:function(n,e){var r=n.replace(/['|"|\]]/g,"").replace(/\[/g,".").split("."),t=e;return r.forEach(function(n){t=t[n]}),r=null,t}},{key:"_extractChildren",value:function(n){var e=this;s.default.customTags.length>0&&(n.HTML=this._replaceTags(s.default.customTags,n.HTML));var r=n.HTML.match(/][\s\S]*?tag=['|"](\S*)['|"][\s\S]*?><\/child>/g);r&&r.forEach(function(r,t){var i=(0,f.default)(r),o=i.child[0].attr,a=o.tag;delete o.tag;var l=e.children[t];l&&l.___omi_constructor_name===a?l._childRender(r):!function(){var i={},d={},c={},u={},m=null,p=null;Object.keys(o).forEach(function(r){var t=o[r];if(0===r.indexOf("on")){var a=n[t];a&&(i[r]=a.bind(n))}else"omi-id"===r?m=t:"name"===r?p=t:"group-data"===r?(n._omiGroupDataCounter.hasOwnProperty(t)?n._omiGroupDataCounter[t]++:n._omiGroupDataCounter[t]=0,u=e._extractPropertyFromString(t,n)[n._omiGroupDataCounter[t]]):0===r.indexOf("data-")?d[e._capitalize(r.replace("data-",""))]=t:"data"===r&&(c=e._extractPropertyFromString(t,n))});var h=s.default.getClassFromString(a);if(!h)throw"Can't find Class called ["+a+"]";var f=new h(Object.assign(i,n.childrenData[t],d,c,u),!1);f._omiChildStr=r,f.parent=n,f.___omi_constructor_name=a,f._dataset={},f.install(),m&&(s.default.mapping[m]=f),p&&(n[p]=f),l?n.children[t]=f:n.children.push(f),f._childRender(r,!0)}()})}}]),n}();e.default=g},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){var r=new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|s*{)","g");return n=n.replace(r,function(n,r,t){return r.match(/^\s*(@media|@keyframes|to|from|@font-face)/)?r+t:(r.match(/:scope/)&&(r=r.replace(/([^\s]*):scope/,function(n,e){return""===e?"> *":"> "+e})),r=r.replace(/^(\s*)/,r.trim()+e+",$1"+e+" ").replace(/\s+/g," "),r+t)})}function o(n,e){var r=document.getElementById(s.default.STYLEPREFIX+e),t=document.getElementsByTagName("head")[0];r&&r.parentNode===t&&t.removeChild(r);var i=document.createElement("style");t.appendChild(i),i.setAttribute("type","text/css"),i.setAttribute("id",s.default.STYLEPREFIX+e),window.ActiveXObject?i.styleSheet.cssText=n:i.textContent=n}Object.defineProperty(e,"__esModule",{value:!0});var a=r(3),s=t(a);e.default={scoper:i,addStyle:o}},function(n,e){"use strict";function r(n,e,r){return n.split(e).map(function(n){return n.replace(new RegExp(r,"g"),e)}).join(r)}function t(n){return JSON.stringify(n).replace(/(^"|"$)/g,"")}function i(n){return n=r(n,"'",'"'),r(t(n),"'",'"')}function o(n){return n.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function a(n,e){return String.prototype.endsWith?String.prototype.endsWith.call(n,e):n.substr(n.length-1,1)===e}function s(n,e){return n.replace(/<[\s\S]*?[^=]>/g,function(n){return n.replace(/on(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave|Abort|Blur|Cancel|CanPlay|CanPlayThrough|Change|Click|Close|ContextMenu|CueChange|DblClick|Drag|DragEnd|DragEnter|DragLeave|DragOver|DragStart|Drop|DurationChange|Emptied|Ended|Error|Focus|Input|Invalid|KeyDown|KeyPress|KeyUp|Load|LoadedData|LoadedMetadata|LoadStart|MouseDown|MouseEnter|MouseLeave|MouseMove|MouseOut|MouseOver|MouseUp|MouseWheel|Pause|Play|Playing|Progress|RateChange|Reset|Resize|Scroll|Seeked|Seeking|Select|Show|Stalled|Submit|Suspend|TimeUpdate|Toggle|VolumeChange|Waiting|AutoComplete|AutoCompleteError|BeforeCopy|BeforeCut|BeforePaste|Copy|Cut|Paste|Search|SelectStart|Wheel|WebkitFullScreenChange|WebkitFullScreenError|TouchStart|TouchMove|TouchEnd|TouchCancel|PointerDown|PointerUp|PointerCancel|PointerMove|PointerOver|PointerOut|PointerEnter|PointerLeave)=('|"|{)([\s\S]*)('|"|})/g,function(n,r,t,s,l){if(0===s.indexOf("Omi.instances[")||0===s.indexOf("new Function("))return n;if("{"===t){var d="("+s+").bind(Omi.instances["+e+"])(event)",c="on"+r+"=\"new Function('event', '"+o(i(d))+"')(event)\"";return c.split("\n").map(function(n){return a(n,";")?n:n+";"}).join("")}return s.match(/.*?\(.*?\)/)?n.replace(/=(['|"])/,"=$1Omi.instances["+e+"]."):n})})}Object.defineProperty(e,"__esModule",{value:!0}),e.default=s},function(n,e,r){var t,i,o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(a,s){"object"===o(e)&&"undefined"!=typeof n?n.exports=s():(t=s,i="function"==typeof t?t.call(e,r,e,n):t,!(void 0!==i&&(n.exports=i)))}(void 0,function(){"use strict";function n(n){!d&&m.createRange&&(d=m.createRange(),d.selectNode(m.body));var e;return d&&d.createContextualFragment?e=d.createContextualFragment(n):(e=m.createElement("body"),e.innerHTML=n),e.childNodes[0]}function e(n,e){var r=n.nodeName,t=e.nodeName;return r===t||!!(e.actualize&&r.charCodeAt(0)<91&&t.charCodeAt(0)>90)&&r===t.toUpperCase()}function r(n,e){return e&&e!==u?m.createElementNS(e,n):m.createElement(n)}function t(n,e){for(var r=n.firstChild;r;){var t=r.nextSibling;e.appendChild(r),r=t}return e}function i(n,e){var r,t,i,o,a,s,l=e.attributes;for(r=l.length-1;r>=0;--r)t=l[r],i=t.name,o=t.namespaceURI,a=t.value,o?(i=t.localName||i,s=n.getAttributeNS(o,i),s!==a&&n.setAttributeNS(o,i,a)):(s=n.getAttribute(i),s!==a&&n.setAttribute(i,a));for(l=n.attributes,r=l.length-1;r>=0;--r)t=l[r],t.specified!==!1&&(i=t.name,o=t.namespaceURI,o?(i=t.localName||i,h(e,o,i)||n.removeAttributeNS(o,i)):h(e,null,i)||n.removeAttribute(i))}function o(n,e,r){n[r]!==e[r]&&(n[r]=e[r],n[r]?n.setAttribute(r,""):n.removeAttribute(r,""))}function a(){}function s(n){return n.id}function l(i){return function(o,l,d){function c(n){O?O.push(n):O=[n]}function u(n,e){if(n.nodeType===g)for(var r=n.firstChild;r;){var t=void 0;e&&(t=_(r))?c(t):(M(r),r.firstChild&&u(r,e)),r=r.nextSibling}}function p(n,e,r){S(n)!==!1&&(e&&e.removeChild(n),M(n),u(n,r))}function h(n){if(n.nodeType===g)for(var e=n.firstChild;e;){var r=_(e);r&&(D[r]=e),h(e),e=e.nextSibling}}function y(n){k(n);for(var r=n.firstChild;r;){var t=r.nextSibling,i=_(r);if(i){var o=D[i];o&&e(r,o)&&(r.parentNode.replaceChild(o,r),x(o,r))}y(r),r=t}}function x(n,r,t){var a,s=_(r);if(s&&delete D[s],!l.isSameNode||!l.isSameNode(o)){if(!t){if(j(n,r)===!1)return;if(i(n,r),C(n),H(n,r)===!1)return}if("TEXTAREA"!==n.nodeName){var d,u,h,w,O=r.firstChild,k=n.firstChild;n:for(;O;){for(h=O.nextSibling,d=_(O);k;){if(u=k.nextSibling,O.isSameNode&&O.isSameNode(k)){O=h,k=u;continue n}a=_(k);var S=k.nodeType,M=void 0;if(S===O.nodeType&&(S===g?(d?d!==a&&((w=D[d])?k.nextSibling===w?M=!1:(n.insertBefore(w,k),u=k.nextSibling,a?c(a):p(k,n,!0),k=w):M=!1):a&&(M=!1),M=M!==!1&&e(k,O),M&&x(k,O)):S!==v&&S!=b||(M=!0,k.nodeValue=O.nodeValue)),M){O=h,k=u;continue n}a?c(a):p(k,n,!0),k=u}if(d&&(w=D[d])&&e(w,O))n.appendChild(w),x(w,O);else{var L=T(O);L!==!1&&(L&&(O=L),O.actualize&&(O=O.actualize(n.ownerDocument||m)),n.appendChild(O),y(O))}O=h,k=u}for(;k;)u=k.nextSibling,(a=_(k))?c(a):p(k,n,!0),k=u}var A=f[n.nodeName];A&&A(n,r)}}if(d||(d={}),"string"==typeof l)if("#document"===o.nodeName||"HTML"===o.nodeName){var w=l;l=m.createElement("html"),l.innerHTML=w}else l=n(l);var O,_=d.getNodeKey||s,T=d.onBeforeNodeAdded||a,k=d.onNodeAdded||a,j=d.onBeforeElUpdated||a,C=d.onElUpdated||a,S=d.onBeforeNodeDiscarded||a,M=d.onNodeDiscarded||a,H=d.onBeforeElChildrenUpdated||a,L=d.childrenOnly===!0,D={};h(o);var A=o,E=A.nodeType,P=l.nodeType;if(!L)if(E===g)P===g?e(o,l)||(M(o),A=t(o,r(l.nodeName,l.namespaceURI))):A=l;else if(E===v||E===b){if(P===E)return A.nodeValue=l.nodeValue,A;A=l}if(A===l)M(o);else if(x(A,l,L),O)for(var I=0,X=O.length;I\s]+))?)*)\s*(\/?)>/,t=/^<\/([-A-Za-z0-9_]+)[^>]*>/,i=/([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,o=function(n,e){function o(n,r,t,o){if(r=r.toLowerCase(),o=!!o,o||c.push(r),e.start){var a=[];t.replace(i,function(n,e){var r=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:"";a.push({name:e,value:r,escaped:r.replace(/(^|[^\\])"/g,'$1\\"')})}),e.start&&e.start(r,a,o)}}function a(n,r){if(r)for(var t=c.length-1;t>=0&&c[t]!=r;t--);else var t=0;if(t>=0){for(var i=c.length-1;i>=t;i--)e.end&&e.end(c[i]);c.length=t}}var s,l,d,c=[],u=n;for(c.last=function(){return this[this.length-1]};n;){if(l=!0,c.last())n=n.replace(new RegExp("([\\s\\S]*?)]*>"),function(n,r){return e.chars&&e.chars(r),""}),a("",c.last());else if(0==n.indexOf(">>0,i=0;if(2==arguments.length)e=arguments[1];else{for(;i=t)throw new TypeError("Reduce of empty array with no initial value");e=r[i++]}for(;i640){var o=document.querySelectorAll("pre"),a=this.getHighLight();if(a){for(var s in a)o[s]&&o[s].setAttribute("data-line",a[s]);n||lineHighLight()}}}},{key:"getHighLight",value:function(){var n=this,e=null;return m.default.menus[this.data.lan].forEach(function(r){r.list.forEach(function(r){r.md===n.data.name&&(e=r.highlight)})}),e}},{key:"installed",value:function(){}},{key:"render",value:function(){return this.data.html=marked(s(this.data.name,this.data.lan)),'\n
    \n {{{html}}}\n
    \n '}},{key:"style",value:function(){return"\n \n "}}]),e}(c.default.Component);e.default=p},function(n,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r={isMobile:!1,mds:{cn:["installation","hello_world","components","communication","lifecycle","events","condition","loop","form","inherit","template","get_dom","plugin","thinking_in_omi","pr_env","pr_hello"],en:["installation","hello_world","components","communication","lifecycle","events","condition","loop","form","inherit","template","get_dom","plugin"]},menus:{cn:[{active:!0,title:"快速开始",currentIndex:0,list:[{name:"安装",md:"installation"},{name:"Hello World",md:"hello_world",highlight:{2:"6",5:"4,6"}},{name:"组件",md:"components",highlight:{2:"3,9,34"}},{name:"组件通讯",md:"communication",highlight:{0:"34",1:"5,11"}},{name:"生命周期",md:"lifecycle"},{name:"事件处理",md:"events"},{name:"条件判断",md:"condition"},{name:"循环遍历",md:"loop",highlight:{1:"9-11"}},{name:"表单",md:"form"},{name:"继承",md:"inherit"},{name:"模板切换",md:"template"},{name:"获取DOM节点",md:"get_dom"},{name:"插件体系",md:"plugin"},{name:"Omi的理念",md:"thinking_in_omi"}]}],en:[{title:"QUICK START",currentIndex:0,list:[{name:"Installation",md:"installation"},{name:"Hello World",md:"hello_world"},{name:"Components",md:"components"},{name:"Communication",md:"communication"},{name:"Lifecycle",md:"lifecycle"},{name:"Handling Events",md:"events"},{name:"Conditional Rendering",md:"condition"},{name:"Loop",md:"loop"},{name:"Forms",md:"form"},{name:"Inheritance",md:"inherit"},{name:"Templates",md:"template"},{name:"Get DOM",md:"get_dom"},{name:"Plugin",md:"plugin"},{name:"Thinking in Omi",md:"thinking_in_omi"}]}]}},t={versions:function(){var n=navigator.userAgent;navigator.appVersion;return{trident:n.indexOf("Trident")>-1,presto:n.indexOf("Presto")>-1,webKit:n.indexOf("AppleWebKit")>-1,gecko:n.indexOf("Gecko")>-1&&n.indexOf("KHTML")==-1,mobile:!!n.match(/AppleWebKit.*Mobile.*/),ios:!!n.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),android:n.indexOf("Android")>-1||n.indexOf("Linux")>-1,iPhone:n.indexOf("iPhone")>-1,iPad:n.indexOf("iPad")>-1,webApp:n.indexOf("Safari")==-1}}(),language:(navigator.browserLanguage||navigator.language).toLowerCase()};(t.versions.mobile||t.versions.ios||t.versions.android||t.versions.iPhone||t.versions.iPad)&&(r.isMobile=!0),e.default=r},function(n,e,r){function t(n){return r(i(n))}function i(n){return o[n]||function(){throw new Error("Cannot find module '"+n+"'.")}()}var o={"./README.md":13,"./cn_communication.md":14,"./cn_components.md":15,"./cn_condition.md":16,"./cn_events.md":17,"./cn_form.md":18,"./cn_get_dom.md":19,"./cn_hello_world.md":20,"./cn_inherit.md":21,"./cn_installation.md":22,"./cn_lifecycle.md":23,"./cn_loop.md":24,"./cn_plugin.md":25,"./cn_pr_nearby.md":26,"./cn_template.md":27,"./cn_thinking_in_omi.md":28,"./deep_in/README.md":29,"./deep_in/cn_env.md":30,"./deep_in/cn_hello.md":31,"./deep_in/cn_nearby.md":32,"./deep_in/cn_omi-cli.md":33,"./en_communication.md":34,"./en_components.md":35,"./en_condition.md":36,"./en_events.md":37,"./en_form.md":38,"./en_get_dom.md":39,"./en_hello_world.md":40,"./en_inherit.md":41,"./en_installation.md":42,"./en_lifecycle.md":43,"./en_loop.md":44,"./en_plugin.md":45,"./en_template.md":46,"./en_thinking_in_omi.md":47};t.keys=function(){return Object.keys(o)},t.resolve=i,n.exports=t,t.id=12},function(n,e){n.exports='module.exports = "## [Docs Website](https://alloyteam.github.io/omi/website/docs.html)\\r\\n\\r\\n### Usage\\r\\n* [安装](./cn_installation.md)\\r\\n* [Hello World](./cn_hello_world.md)\\r\\n* [组件](./cn_components.md)\\r\\n* [组件通讯](./cn_communication.md)\\r\\n* [生命周期](./cn_lifecycle.md)\\r\\n* [事件处理](./cn_events.md)\\r\\n* [条件判断](./cn_condition.md)\\r\\n* [循环遍历](./cn_loop.md)\\r\\n* [表单](./cn_form.md)\\r\\n* [继承](./cn_inherit.md)\\r\\n* [模板切换](./cn_template.md)\\r\\n* [获取DOM节点](./cn_get_dom.md)\\r\\n* [插件体系](./cn_plugin.md)\\r\\n* [Omi理念](./cn_thinking_in_omi.md)\\r\\n\\r\\n### Usage(en-us)\\r\\n* [installation](./en_installation.md)\\r\\n* [Hello World](./en_hello_world.md)\\r\\n* [components](./en_components.md)\\r\\n* [communication](./en_communication.md)\\r\\n* [lifecycle](./en_lifecycle.md)\\r\\n* [events](./en_events.md)\\r\\n* [condition](./en_condition.md)\\r\\n* [loop](./en_loop.md)\\r\\n* [form](./en_form.md)\\r\\n* [inherit](./en_inherit.md)\\r\\n* [template](./en_template.md)\\r\\n\\r\\n"'; -},function(n,e){n.exports='module.exports = "

    组件通讯

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)组建间的通讯非常遍历灵活,因为有许多可选方案进行通讯:\\r\\n\\r\\n* 通过在组件上声明 data-* 传递给子节点 \\r\\n* 通过在组件上声明 data 传递给子节点 (支持复杂数据类型的映射)\\r\\n* 父容器设置 childrenData 自动传递给子节点\\r\\n* 声明 group-data 传递(支持复杂数据类型的映射)\\r\\n* 完全面向对象,可以非常容易地拿到对象的实例,之后可以设置实例属性和调用实例的方法\\r\\n\\r\\n所以通讯变得畅通无阻,下面一一来举例说明。\\r\\n\\r\\n### data-*通讯 \\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n \\tcursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n一般data-*用来传递值类型,如string、number。值得注意的是,通过data-*接收到的数据类型都是string,需要自行转成number类型。\\r\\n通常情况下,data-*能满足我们的要求,但是遇到复杂的数据类型是没有办法通过大量data-*去表达,所以可以通过data通讯,请往下看。\\r\\n\\r\\n### data通讯 \\r\\n\\r\\n如上面代码所示,通过 data-name=\\"Omi\\"可以把name传递给子组件。下面的代码也可以达到同样的效果。\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.helloData = { name : \'Omi\' };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n使用data声明,会去组件的instance(也就是this)下找对应的属性,this下可以挂载任意复杂的对象。所以这也就突破了data-*的局限性。\\r\\n\\r\\n如果instance下面的某个属性下面的某个属性下面的某个数组的第一个元素的某个属性要作为data传递Hello怎么办?\\r\\n没关系,data声明是支持复杂类型的,使用方式如下:\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n点击这里→data映射复杂数据\\r\\n\\r\\n### childrenData通讯\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.childrenData = [{ name : \'Omi\' } , { name : \'dntzhang\' }];\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n使用this.childrenData传递data给子组件,childrenData是一个数组类型,所以支持同时给多个组件传递data,与render里面的组件会一一对应上。\\r\\n\\r\\n### group-data通讯\\r\\n\\r\\nchildrenData的方式可以批量传递数据给组件,但是有很多场景下data的来源不一定非要都从childrenData来,childrenData是个数组,会和组件的顺序一一对应,这就给不同传递方式的data必须全部集中的childrenData中,非常不方便。group-data专门为解决上面的痛点而生,专门是为了给一组组件批量传递data。\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.testData = [{name: \'Omi\'}, {name: \'dntzhang\'}, {name: \'AlloyTeam\'}];\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n只需要在声明的子组件上标记group-data,就会去当前组件的instance(也就是this)下面找对应的属性,然后根据当前的位置,和对应数组的位置会一一对应起来。\\r\\n\\r\\n运行结果如下:\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170216110701535-1698390390.png)\\r\\n\\r\\n点击这里→group-data\\r\\n\\r\\n同样group-data支持复杂数据类型的映射,需要注意的是,group-data映射的终点必须是一个数组:\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n点击这里→group-data映射复杂数据\\r\\n\\r\\n### 通过对象实例\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n this.hello.data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n### 通过omi-id\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n Omi.get(\\"hello\\").data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n通过在组件上声明omi-id,在程序任何地方拿到该对象的实例。这个可以算是跨任意组件通讯神器。\\r\\n\\r\\n### 特别强调\\r\\n\\r\\n* 通过childrenData或者data方式通讯都是一锤子买卖。后续变更只能通过组件实例下的data属性去更新组件\\r\\n* 通过data-✼通讯也是一锤子买卖。后续变更只能通过组件实例下的data属性去更新组件。\\r\\n* 关于data-✼通讯也可以不是一锤子买卖,但是要设置组件实例的dataFirst为false,这样的话data-✼就会覆盖组件实例的data对应的属性\\r\\n\\r\\n关于上面的第三条也就是这样的逻辑伪代码:\\r\\n```js\\r\\nif(this.dataFirst){\\r\\n this.data = Object.assign({},data-✼ ,this.data);\\r\\n}else{\\r\\n this.data = Object.assign({},this.data, data-✼);\\r\\n}\\r\\n```"'},function(n,e){n.exports='module.exports = "

    组件

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)完全基于组件体系设计,我们希望开发者可以像搭积木一样制作Web程序,一切皆是组件,组件也可以嵌套子组件形成新的组件,新的组件又可以当作子组件嵌套至任意组件形成新的组件...\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170210093427338-1536910080.png)\\r\\n\\r\\n## 简单组件\\r\\n\\r\\n这里使用Todo的例子来讲解Omi组件体系的使用。\\r\\n\\r\\n```js\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.data.items.push(this.data.text);\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n
      {{#items}}
    • {{.}}
    • {{/items}}
    \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Todo({ items: [] ,text : \'\' }),\\"body\\");\\r\\n```\\r\\n\\r\\n组件生成的HTML最终会插入到body中。上面的例子展示了Omi的部分特性:\\r\\n\\r\\n- data传递: new Todo(data,..)的data可以直接提供给render方法里的模板\\r\\n- 局部CSS: h3只对render里的h3生效,不会污染外面的h3;button也是同样的\\r\\n- 声明式事件绑定: onchange调用的就是组件内的handleChange,this可以拿到当然的DOM元素,还可以拿到当前的event\\r\\n- 需要手动调用update方法才能更新组件\\r\\n\\r\\n这里需要特别强调的是,为了更加的自由和灵活度。Omi没有内置数据变更的自动更新,需要开发者自己调用update方法。\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n## 组件嵌套\\r\\n\\r\\n如果页面超级简单的话,可以没有组件嵌套。但是绝大部分Web网页或者Web应用,需要嵌套定义的组件来完成所有的功能和展示。比如上面的Todo,我们也是可以抽取出List。\\r\\n这样让程序易维护、可扩展、方便复用。如,我们抽取出List:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
      {{#items}}
    • {{.}}
    • {{/items}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n怎么使用这个List?我们需要使用Omi.makeHTML把List制作成可以声明式的标签,在render方法中就能直接使用该标签。如下所示:\\r\\n\\r\\n```js\\r\\nimport List from \'./list.js\';\\r\\n\\r\\nOmi.makeHTML(\'List\', List);\\r\\n\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.data.length = this.data.items.length;\\r\\n this.listData = { items : this.data.items };\\r\\n }\\r\\n\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.list.data.items.push(this.data.text);\\r\\n this.data.length = this.list.data.items.length;\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n* 第3行,通过makeHTML方法把组件制作成可以在render中使用的标签。当然Omi.makeHTML(\'List\', List);也可以写在List组件的代码下面。\\r\\n* 第9行,在父组件上定义listData属性用来传递给子组件。\\r\\n* 第34行,在render方法中使用List组件。其中name方法可以让你在代码里通过this快速方法到该组件的实例。data=\\"listData\\"可以让你把this.listData传递给子组件。\\r\\n\\r\\n需要注意的是,父组件的this.listData会被通过Object.assign浅拷贝到子组件。\\r\\n这样做的目的主要是希望以后DOM的变更都尽量修改子组件自身的data,然后再调用其update方法,而不是去更改父组件的listData。\\r\\n\\r\\n关于Omi组件通讯其实有4种方案,这个后续教程会专门来讲。\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports="module.exports = \"

    条件判断

    \\r\\n\\r\\n我们经常需要根据不同的状态呈现不同的界面,比如有的用户是vip要显示vip的Logo。Omi有许多种方式满足你的要求。\\r\\n\\r\\n### 方式一\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `{{#isVip}}\\r\\n
    you are VIP.
    \\r\\n {{/isVip}}\\r\\n {{^isVip}}\\r\\n
    you are not VIP.
    \\r\\n {{/isVip}}`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n上面完全使用mustachejs的条件判断的语法。当然Omi不强制你使用mustachejs。你可以是omi.lite.js,然后重写Omi.template方法去使用任意你喜爱的模板引擎。\\r\\n\\r\\n### 方式二\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nrender就是提供了很好的可编程性,里面可以写任意js逻辑代码。对了,差点忘了,style方法里面也可以写js逻辑的。\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style (){\\r\\n if(this.data.isVip){\\r\\n return 'div{ color : red; }';\\r\\n }else{\\r\\n return 'div{ color : green; }';\\r\\n }\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\""},function(n,e){n.exports='module.exports = "

    事件处理

    \\r\\n\\r\\nOmi的事件分内置事件和自定义事件。在内置事件处理方面巧妙地利用了浏览器自身的管线机制,可以通过event和this轻松拿到事件实例和触发该事件的元素。\\r\\n\\r\\n### 内置事件\\r\\n\\r\\n什么算内置事件?只要下面正则能匹配到就算内置事件。\\r\\n\\r\\n```js\\r\\non(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave)\\r\\n```\\r\\n\\r\\n内置事件怎么绑定?如下所示:\\r\\n\\r\\n```js\\r\\nclass EventTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n handleClick(dom, evt){\\r\\n alert(dom.innerHTML);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Hello, Omi!
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 自定义事件\\r\\n\\r\\n开发者自己定义的组件的事件,称为自定义事件,自定义事件必须以on开头,即onXXXX的格式,不然Omi识别不到。这里拿分页作为例子:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\nimport Pagination from \'./pagination.js\';\\r\\nimport Content from \'./content.js\';\\r\\n\\r\\nOmi.makeHTML(\'Pagination\', Pagination);\\r\\nOmi.makeHTML(\'Content\', Content);\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.content.goto(this.pagination.data.currentPage+1);\\r\\n }\\r\\n handlePageChange(index){\\r\\n this.content.goto(index+1);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    Pagination Example

    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render( new Main(),\'body\');\\r\\n```\\r\\n\\r\\n如上面的onPageChange就是自定义事件,触发会执行handlePageChange。onPageChange方法是在Pagination中执行:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\n\\r\\nclass Pagination extends Omi.Component {\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n linkTo: \\"#\\",\\r\\n prevText: \\"Prev\\",\\r\\n nextText: \\"Next\\",\\r\\n ellipseText: \\"...\\",\\r\\n prevShow: true,\\r\\n nextShow: true,\\r\\n onPageChange: function () { return false; }\\r\\n }, this.data);\\r\\n\\r\\n this.pageNum = Math.ceil(this.data.total / this.data.pageSize);\\r\\n }\\r\\n goto (index,evt) {\\r\\n evt.preventDefault();\\r\\n this.data.currentPage=index;\\r\\n this.update();\\r\\n this.data.onPageChange(index);\\r\\n }\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\n这里取了Pagination组件的部分代码。高亮的就是执行onPageChange的地方。\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/pagination/)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/pagination)\\r\\n"'},function(n,e){n.exports='module.exports = "

    表单

    \\r\\n\\r\\nOmi让一些表单操控起来更加方便,特别是select!\\r\\n\\r\\n### select标签\\r\\n\\r\\n以前,我们需要像如下的方式选中一个选项:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n第三个option由于加上了selected,所有会被选中。这样带来的问题就是,开发者写的程序可能要操遍历每个option。而使用Omi,你只需要这样子:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n这样就能达到同样的效果。比如你想选择第一项:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n是不是非常方便?\\r\\n\\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass FormTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n \\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n console.log(target.value)\\r\\n this.data.value = target.value;\\r\\n }\\r\\n\\r\\n handleSubmit(evt) {\\r\\n alert(\'Your favorite flavor is: \' + this.data.value);\\r\\n evt.preventDefault();\\r\\n }\\r\\n \\r\\n render () {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new FormTest({ value: \'mango\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    获取DOM节点

    \\r\\n\\r\\n虽然绝大部分情况下,开发者不需要去查找获取DOM,但是还是有需要获取DOM的场景,所以Omi提供了方便获取DOM节点的方式。\\r\\n\\r\\n### ref和refs\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(){\\r\\n alert(this.refs.abc.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\n可以看到通过在HTML中标记ref为abc,那么就通过this.refs.abc访问到该DOM节点。\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    Hello World

    \\r\\n\\r\\n你可以使用ES6+或者ES5的方式编写Omi程序来搭建你的Web程序。\\r\\n\\r\\n### Hello World with ES6+\\r\\n\\r\\n你可以使用 [webpack](https://webpack.github.io/) 打包工具,webpack会把你的模块代码打成一个很小的包,优化加载时间。使用[babel](http://babeljs.io/),让你立刻马上使用ES6+来编写你的web程序。你只需要在webpack配置的module设置好[babel-loader](https://github.com/babel/babel-loader)便可。\\r\\n\\r\\n一个Omi的简短的例子如下所示:\\r\\n\\r\\n```js\\r\\nimport Omi from \'./omi.js\';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\n组件生成的HTML最终会插入到#container中。上面的例子展示了Omi的部分特性:\\r\\n\\r\\n- data传递: new Hello(data,..)的data可以直接提供给render方法里的模板\\r\\n- 局部CSS: h1只对render里的h1生效,不会污染外面的h1\\r\\n- 声明式事件绑定: onclick调用的就是组件内的handleClick,this可以拿到当前的DOM元素,还可以拿到当前的event\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n你可以使用Omi.makeHTML来生成组件标签用于嵌套。\\r\\n```js\\r\\n Omi.makeHTML(\'Hello\', Hello);\\r\\n```\\r\\n那么你就在其他组件中使用,如\\r\\n```js\\r\\n ...\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Test
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n ...\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### Hello World with ES5\\r\\n\\r\\n当然Omi没有抛弃ES5的用户。你可以使用ES5的方式编写Omi。如,在你的HTML中引用omi.js:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n然后:\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\", {\\r\\n style: function () {\\r\\n return \\"h1{ cursor:pointer }\\";\\r\\n },\\r\\n handleClick: function (dom) {\\r\\n alert(dom.innerHTML)\\r\\n },\\r\\n render: function () {\\r\\n return \'
    \\\\\\r\\n

    \\\\\\r\\n Hello ,{{name}}!\\\\\\r\\n

    \\\\\\r\\n
    \'\\r\\n }\\r\\n});\\r\\n\\r\\nvar Test = Omi.create(\\"Test\\", {\\r\\n render: function () {\\r\\n return \'
    \\\\\\r\\n
    Test
    \\\\\\r\\n \\\\\\r\\n
    \'\\r\\n }\\r\\n});\\r\\n\\r\\nOmi.render(new Test(),\'#container\');\\r\\n```\\r\\n当然除了在HTML引入脚本,你还可以使用AMD、CMD或者CommonJS的方式引入Omi,这里就不再一一列举。\\r\\n\\r\\n需要注意的是,Omi.create的第一个参数Hello是用来生成Tag Name的。你可以在其他地方嵌入你的组件。如:\\r\\n\\r\\n```js\\r\\n ...\\r\\n render:function() {\\r\\n return \'
    \\\\\\r\\n \\\\\\r\\n
    Test XXXX
    \\\\\\r\\n \\\\\\r\\n
    \';\\r\\n }\\r\\n ...\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports='module.exports = "

    继承

    \\r\\n\\r\\n通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。\\r\\n\\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n div{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n}\\r\\n\\r\\nclass SubHello extends Hello {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### ES5下的继承\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\",{\\r\\n render:function(){\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n})\\r\\n\\r\\nvar SubHello = Omi.create(\\"SubHello\\",Hello,{ });\\r\\n\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    安装

    \\n\\n[Omi](https://github.com/AlloyTeam/omi)(读音 / [ˈomɪ] /, 汉字类似于 欧米) 是一款用于创建用户界面的组件化框架,开放并且现代,故得名:Omi。\\n\\n### 安装 Omi\\n\\n我们推荐使用 [npm](https://www.npmjs.com/) 来管理你的前端依赖.\\n\\n通过npm安装Omi,你只需要执行下面的命令:\\n\\n``` js\\nnpm install omi\\n```\\n\\n## omi-cli\\n\\n你也可以通过omi-cli去初始化你的项目:\\n\\n``` js\\n$ npm install omi-cli -g //安装cli\\n$ omi init your_project_name //初始化项目,你也可以在一个空的文件夹下执行 omi init\\n$ cd your_project_name //如果你是在空文件夹下执行的 omi init。请无视这条命令\\n$ npm run dev //开发\\n$ npm run dist //部署发布\\n```"'},function(n,e){n.exports='module.exports = "

    生命周期

    \\r\\n\\r\\n|name |avatars |company | \\r\\n|---|---|---|\\r\\n| constructor | 构造函数 | new的时候 |\\r\\n| install | 初始化安装,这可以拿到用户传进的data进行处理 | 实例化 |\\r\\n| installed | 安装完成,HTML已经插入页面之后执行 | 实例化 |\\r\\n| uninstall | 卸载组件。执行remove方法会触发该事件 | 销毁时 |\\r\\n| beforeUpdate | 更新前 | 存在期 |\\r\\n| afterUpdate | 更新后 | 存在期 |\\r\\n\\r\\n## 示意图\\r\\n\\r\\n![lc](http://images2015.cnblogs.com/blog/105416/201701/105416-20170119153018546-1566368987.png)\\r\\n \\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass Timer extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n install () {\\r\\n this.data = {secondsElapsed: 0};\\r\\n }\\r\\n\\r\\n tick() {\\r\\n this.data.secondsElapsed++;\\r\\n this.update();\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.interval = setInterval(() => this.tick(), 1000);\\r\\n }\\r\\n\\r\\n uninstall() {\\r\\n clearInterval(this.interval);\\r\\n }\\r\\n\\r\\n\\r\\n style () {\\r\\n return `\\r\\n .num { color:red; }\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Seconds Elapsed: {{secondsElapsed}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports='module.exports = "

    循环遍历

    \\r\\n\\r\\n下面介绍mustache.js的方式和javascript遍历的方式。\\r\\n\\r\\n### 方式一\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n
      \\r\\n {{#items}} \\r\\n
    • {{text}}
    • \\r\\n {{/items}}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nmustache.js更详细的循环遍历使用可看[https://github.com/janl/mustache.js#non-empty-lists](https://github.com/janl/mustache.js#non-empty-lists)。 比如还支持:\\r\\n\\r\\n* 如果items的每一项是字符串,可以直接**{{.}}**的方式来输出每一项\\r\\n* 循环的时候调用定义好的函数\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### 方式二\\r\\n\\r\\n既然ES6+了,当然可以使用${ }以及Array的map方法: \\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `
    \\r\\n
      \\r\\n ${this.data.items.map(item =>\\r\\n `
    • ${item.text}
    • `\\r\\n ).join(\'\')}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\n你将在页面看到如下效果:\\r\\n\\r\\n![pv](http://images2015.cnblogs.com/blog/105416/201701/105416-20170122095724129-2059595233.png)\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports="module.exports = \"

    插件体系

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi)是Web组件化框架,怎么又来了个插件的概念?\\r\\n\\r\\n可以这么理解: Omi插件体系可以赋予dom元素一些能力,并且可以和组件的实例产生关联。\\r\\n\\r\\n### omi-drag\\r\\n\\r\\n且看这个例子:\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n```js\\r\\nimport OmiDrag from './omi-drag.js';\\r\\n\\r\\nOmiDrag.init();\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n\\r\\n style(){\\r\\n return `\\r\\n .test{\\r\\n width:100px;\\r\\n height:100px;\\r\\n color:white;\\r\\n line-height:90px;\\r\\n text-align:center;\\r\\n background-color:#00BFF3;\\r\\n }\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n如上面的代码所示,通过在div上标记omi-drag,这个div就能够被用户使用鼠标拖拽。我们称omi-drag.js为omi插件。\\r\\n是不是非常方便?那么这个omi-drag是怎么实现的?\\r\\n\\r\\n## Omi.extendPlugin\\r\\n\\r\\n核心方法: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n下面的代码就是展示了如何通过 Omi.extendPlugin 赋予dom拖拽的能力:\\r\\n\\r\\n```js\\r\\n;(function () {\\r\\n\\r\\n var OmiDrag = {};\\r\\n var Omi = typeof require === 'function'\\r\\n ? require('omi')\\r\\n : window.Omi;\\r\\n\\r\\n OmiDrag.init = function(){\\r\\n Omi.extendPlugin('omi-drag',function(dom, instance){\\r\\n dom.style.cursor='move';\\r\\n var isMouseDown = false,\\r\\n preX = null,\\r\\n preY = null,\\r\\n currentX = null,\\r\\n currentY = null,\\r\\n translateX = 0,\\r\\n translateY = 0;\\r\\n\\r\\n dom.addEventListener('mousedown',function(evt){\\r\\n isMouseDown = true;\\r\\n preX = evt.pageX;\\r\\n preY = evt.pageY;\\r\\n evt.stopPropagation();\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n }\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mouseup',function(){\\r\\n isMouseDown = false;\\r\\n preX = preY = currentX = currentY = null;\\r\\n },false);\\r\\n });\\r\\n }\\r\\n\\r\\n OmiDrag.destroy = function(){\\r\\n delete Omi.plugins['omi-drag'];\\r\\n };\\r\\n\\r\\n if (typeof exports == \\\"object\\\") {\\r\\n module.exports = OmiDrag;\\r\\n } else if (typeof define == \\\"function\\\" && define.amd) {\\r\\n define([], function(){ return OmiDrag });\\r\\n } else {\\r\\n window.OmiDrag = OmiDrag;\\r\\n }\\r\\n\\r\\n})();\\r\\n```\\r\\n\\r\\n方法: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n其中pluginName为插件的名称\\r\\n其中handler为处理器。handler可以拿到标记了pluginName的dom以及dom所在的组件的实例,即 dom 和 instance。\\r\\n\\r\\n通过 Omi.extendPlugin,可以赋予dom元素一些能力,也可以和组件的实例(instance)产生关联。\\r\\n但是上面的例子没有和instance产生关联,我们接下来试试:\\r\\n\\r\\n## 关联instance\\r\\n\\r\\n我们想在组件里面能够监听到move并且执行回调。如下:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandler(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n主要被拖动过程中,moveHandler就不断地被执行。插件代码需要修改:\\r\\n\\r\\n```js\\r\\n...\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance.moveHandler(evt);\\r\\n }\\r\\n},false);\\r\\n```\\r\\n\\r\\n我们在里面增加了instance.moveHandler(evt);方法,用来执行组件实例上的moveHandler方法。\\r\\n这样的话:就是组件的实例(instance)产生关联。但是还是有问题?如果标记了多个omi-drag 就会有问题!如:\\r\\n\\r\\n```js\\r\\n...\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n通常我们系统每个omi-drag都能对应一个回调函数,如:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n怎么办?怎么实现?有办法!通过dom传递数据给插件。\\r\\n\\r\\n## 传递数据\\r\\n\\r\\n先来看最后实现的效果:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nomi-drag修改的地方:\\r\\n\\r\\n```js\\r\\n...\\r\\nvar handlerName = dom.getAttribute('dragMove');\\r\\n\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance[handlerName](evt);\\r\\n }\\r\\n},false);\\r\\n...\\r\\n```\\r\\n\\r\\n* 通过 var handlerName = dom.getAttribute('dragMove') 拿到dom上声明的dragMove\\r\\n* 通过 instance[handlerName](evt) 去执行对应的方法\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n## 更多插件\\r\\n\\r\\n* [omi-finger](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-finger) Omi的[AlloyFinger](https://github.com/AlloyTeam/AlloyFinger)插件,支持各种触摸事件和手势\\r\\n* [omi-transform](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-transform) Omi的[transformjs](http://alloyteam.github.io/AlloyTouch/transformjs/)插件,快速方便地设置DOM的CSS3 Transform属性\\r\\n* [omi-touch](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-touch) Omi的[AlloyTouch](https://github.com/AlloyTeam/AlloyTouch)插件,Omi项目的触摸运动解决方案(支持触摸滚动、旋转、翻页、选择等等)\\r\\n* [omi-jquery-date-picker](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-jquery-date-picker) Omi的时间选择插件,支持各种时间或者时间区域选择\\r\\n\""; -},function(n,e){n.exports='module.exports = "## 写在前面\\r\\nOmi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。\\r\\n\\r\\n项目开始之前,实现选择一个脚手架。这个项目用的就是[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)\\r\\n\\r\\nGulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)\\r\\n\\r\\n\\r\\n所以,要使用Fiddler并配置Extention:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)\\r\\n\\r\\n\\r\\n## 目录\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)\\r\\n\\r\\n\\r\\n目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。\\r\\n组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。\\r\\n\\r\\n## 命令\\r\\n\\r\\n开发\\r\\n```js\\r\\nnpm run dev\\r\\n```\\r\\n\\r\\n发布\\r\\n```js\\r\\nnpm run dist\\r\\n```\\r\\n\\r\\n## 开始写码\\r\\n\\r\\n万事具备,开始写码。先写组件:\\r\\n\\r\\n```js\\r\\nimport Omi from \'omi\'\\r\\n\\r\\nclass UserList extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n install() {\\r\\n this.data.uin_info || (this.data.uin_info = [])\\r\\n this.data.uin_info.forEach(user => {\\r\\n this.prepareData(user)\\r\\n })\\r\\n }\\r\\n \\r\\n prepareData(user){\\r\\n user.desc_d = user.desc.split(\\" \\")[0]\\r\\n user.desc_t = user.desc.split(\\" \\")[1]\\r\\n user.isBoy = user.sex === \\"男\\"\\r\\n user.qlogo = user.url.replace(\\"http://\\", location.protocol + \\"//\\").replace(/&/g, \\"&\\")\\r\\n if (user.profession_desc) {\\r\\n user.hasProfession_desc = true\\r\\n }\\r\\n }\\r\\n \\r\\n appendUsers (users) {\\r\\n users.uin_info && users.uin_info.forEach(user =>{\\r\\n this.prepareData(user)\\r\\n this.data.uin_info.push(user)\\r\\n })\\r\\n this.update()\\r\\n }\\r\\n\\r\\n sendGift(uin, nick, qlogo) {\\r\\n //送礼物并关闭webview,此处省略\\r\\n //..\\r\\n //..\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n {{#uin_info}}\\r\\n
    \\r\\n
    \\r\\n \\r\\n
    \\r\\n
    \\r\\n
    {{{nick}}}
    \\r\\n
    \\r\\n {{#isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{^isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{#hasProfession_desc}} {{profession_desc}} {{/hasProfession_desc}}\\r\\n
    \\r\\n
    {{{intro}}}
    \\r\\n
    \\r\\n
    {{desc_d}} · {{desc_t}}
    \\r\\n
    \\r\\n {{/uin_info}}\\r\\n
    加载中...
    \\r\\n
    \\r\\n`\\r\\n }\\r\\n\\r\\n style() {\\r\\n return `\\r\\n\\r\\n\\r\\n.qlogo {\\r\\n overflow: hidden;\\r\\n width: 70px;\\r\\n height: 70px;\\r\\n -webkit-border-radius: 50%;\\r\\n border-radius: 50%;\\r\\n position: absolute;\\r\\n top: 10px;\\r\\n left: 12px;\\r\\n}\\r\\n...\\r\\n...\\r\\n..这里省略大量.....\\r\\n...\\r\\n...\\r\\n\\r\\n.distance_info {\\r\\n position: absolute;\\r\\n top: 15px;\\r\\n right: 9px;\\r\\n color: #7B7B84;\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nexport default UserList\\r\\n```\\r\\n\\r\\n组件里面有5个方法:\\r\\n\\r\\n* constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this\\r\\n* install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理\\r\\n* prepareData 对数据进行一些处理来满足模板的渲染\\r\\n* appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用\\r\\n* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..\\r\\n\\r\\n其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。\\r\\nrender里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;\\r\\n如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。\\r\\n\\r\\n这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)\\r\\n\\r\\n\\r\\n下面来看index.js:\\r\\n\\r\\n```js\\r\\nimport Root from \'./config.js\'\\r\\nimport Omi from \'omi\'\\r\\nimport UserList from \'../component/user_list/index.js\'\\r\\n\\r\\nOmi.makeHTML(\'UserList\', UserList)\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n installed() {\\r\\n window.onscroll = () => this.loadMore()\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n\\r\\n loadMore() {\\r\\n const body = document.body,\\r\\n html = document.documentElement,\\r\\n height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),\\r\\n vp_height = window.innerHeight\\r\\n\\r\\n if (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n }\\r\\n\\r\\n requestData(callback) {\\r\\n if (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }else{\\r\\n \\t//ajax 请求数据,这里省略\\r\\n }\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Main(),\'body\')\\r\\n```\\r\\n\\r\\n通过Omi.makeHTML(\'UserList\', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:\\r\\n\\r\\n```js\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n```\\r\\n\\r\\n下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。\\r\\n\\r\\n```js\\r\\nwindow.onscroll = () => this.loadMore()\\r\\n```\\r\\n\\r\\n通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:\\r\\n\\r\\n```js\\r\\nif (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n}\\r\\n```\\r\\n\\r\\nrequestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。\\r\\n慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:\\r\\n\\r\\n```js\\r\\n \\r\\n```\\r\\n\\r\\n上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!\\r\\n\\r\\n再来看下数据模拟:\\r\\n\\r\\n```js\\r\\nif (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }\\r\\n```\\r\\n\\r\\n这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!\\r\\n\\r\\n## 最后\\r\\n\\r\\n好了,就这么多,Omi让代码真心方便简洁~~~\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)"'},function(n,e){n.exports='module.exports = "

    模板切换

    \\r\\n\\r\\nOmi有三个版本。其中的omi.js和omi.lite.js属于Web端使用的版本。\\r\\n\\r\\n* omi.js内置了[mustache.js](https://github.com/janl/mustache.js)作为模版引擎\\r\\n* omi.lite.js不包含任何模版引擎\\r\\n\\r\\nOmi不强制开发者使用mustache.js,你可以根据业务场景使用任意模板引擎或者不使用模板引擎。\\r\\n\\r\\n那么怎么使用别的模板引擎?下面拿[artTemplate](https://github.com/aui/artTemplate)作为例子。\\r\\n\\r\\n### 使用artTemplate\\r\\n\\r\\n```js\\r\\nOmi.template = function(tpl, data){\\r\\n return artTemplate.compile(tpl)(data);\\r\\n}\\r\\n```\\r\\n重写Omi.template方法,tpl为传入的模板,data为模板所需的数据,返回值为HTML。\\r\\n重写完毕后就能在render使用artTemplate的语法,如:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h1 { color:red; }\\r\\n li{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `

    {{title}}

    \\r\\n
      \\r\\n {{each list as value i}}\\r\\n
    • 索引 {{i + 1}} :{{value}}
    • \\r\\n {{/each}}\\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/artTemplate/)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/artTemplate)"'},function(n,e){n.exports='module.exports = "

    Omi的理念

    \\r\\n\\r\\nOmi的理念是基于面向对象编程体系,内建积木系统。\\r\\n 传统的单向数据流或者抛出event的组件通讯方式增加了系统的稳定性,但是丧失了灵活性。一定程度上也降低了组建的复用。所谓鱼和熊掌不可兼得。\\r\\n 面向对象体系需要多一个逻辑层,可以自由操作所有组件的instance,instance之间的逻辑关系构建出了整个程序。这样组建间的逻辑,通信,复用就全部迎刃而解。组建也更加单一职责,更松耦合。\\r\\n\\r\\n对比函数式编程、命令式编程与面向对象编程,可以归纳总结出下面几条:\\r\\n\\r\\n- 命令式编程干脆直接,利用循环条件等控制流程,强调执行过程\\r\\n- 命令式编程对硬件执行友好,运行更容易,却阻碍了复杂程序的设计\\r\\n- 函数式强调输入和输出,并非执行过程\\r\\n- 函数式倡导多个简单执行单元组合成复杂运算程序\\r\\n- 面向对象编程将对象作为程序的基本单元,更具有重用性、灵活性和扩展性\\r\\n\\r\\nJavascript是哪种类型的语言?现在ES6+已经有了class。那么他是面向对象语言?\\r\\n但是JS可以在任意地方定义函数并且当作把函数当作值来传递。那么他是函数式编程语言?\\r\\n所以,没有精准的定义,取决于你的用法和姿势。其次,Web组件化架构层面编程模型和语言层面编程模型是非常自由的关系。意思就是,你可以用Javascript构建函数式编程框架如React,也可以基于面向对象体系搭建Omi。\\r\\n\\r\\n### 函数式编程 VS 面向对象编程\\r\\n\\r\\n在UI组件框架层面,函数式编程的代表有React,Omi属于面向对象编程体系。那么他们各有什么优缺点?下面做了个对比(其实也是函数式编程与面向对象编程的对比):\\r\\n\\r\\n| | React | Omi |\\r\\n| ------------- |:-------------:|:-----:|\\r\\n| 组件通信 | ★★★★☆| ★★★★★ |\\r\\n| 稳定性 | ★★★★★ | ★★★★☆ |\\r\\n| 灵活性 | ★★★★☆| ★★★★★ |\\r\\n| 扩展性 | ★★★★☆ | ★★★★★ |\\r\\n| 测试性 | ★★★★★ | ★★★★☆ |\\r\\n| 文件大小 | ★★★☆☆ | ★★★★★ |\\r\\n| 功能特性 | ★★★☆☆ | ★★★★☆ |\\r\\n| DOM性能 | ★★★★★ | ★★★★☆ |\\r\\n| 动画性能 | ★★★★☆ | ★★★★★ |\\r\\n| 抽象复杂度 | ★★★★☆ | ★★★★★ |\\r\\n| 异步编程 | ★★★★★ | ★★★★☆ |\\r\\n\\r\\n可以看得出,鱼和熊掌不可兼得。面向对象编程更具有重用性、灵活性和扩展性,带来的问题就是更加难测试。\\r\\n具体来说,如函数式编程,其测试面积是state1 + state2 + ... + stateN;在面向对象编程中,其测试面积是state1×event1 + state2×event2 + ... + stateN×eventN。\\r\\n\\r\\n总结来说,更加推荐使用面向对象的方式去搭建UI组件化框架。\\r\\n\\r\\n
    \\r\\n\\r\\n### 全文结束,感谢阅读。[开始Omi之旅吧!](https://github.com/AlloyTeam/omi) \\r\\n\\r\\n"'},function(n,e){n.exports='module.exports = "# 深入Omi\\r\\n\\r\\n(待续...)\\r\\n\\r\\n* [环境搭建](./cn_env.md)\\r\\n* [Hello Omi](./cn_hello.md)\\r\\n* [手Q附近Web页Omi实战](./cn_nearby.md)\\r\\n* 局部CSS揭秘\\r\\n* 组件嵌套揭秘\\r\\n* 事件处理揭秘\\r\\n* 服务器端渲染揭秘\\r\\n* 模板切换揭秘\\r\\n* 容器系统揭秘"'},function(n,e){n.exports='module.exports = "

    环境搭建

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)使用 Webpack + ES6 的方式去开发;使用karma+jasmine来作为Omi的测试工具。\\r\\n\\r\\n## Karma介绍\\r\\n\\r\\nKarma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner)。该工具可用于测试所有主流Web浏览器,也可集成到CI(Continuous integration)工具,也可和其他代码编辑器一起使用。这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行。但是集成到travis ci要把singleRun设置成true,让其只执行一遍。\\r\\n\\r\\n## Jasmine介绍\\r\\nJasmine 是一款 JavaScript BDD(行为驱动开发)测试框架,它不依赖于其他任何 JavaScript 组件。它有干净清晰的语法,让您可以很简单的写出测试代码。\\r\\n\\r\\n## 开发依赖包\\r\\n\\r\\n在package.json中,有如下配置:\\r\\n\\r\\n```js\\r\\n \\"devDependencies\\": {\\r\\n \\"babel-core\\": \\"^6.0.20\\",\\r\\n \\"babel-loader\\": \\"^6.0.1\\",\\r\\n \\"babel-preset-es2015\\": \\"^6.0.15\\",\\r\\n \\"node-libs-browser\\": \\"^0.5.3\\",\\r\\n \\"webpack\\": \\"^1.14.0\\",\\r\\n \\"jasmine-core\\": \\"^2.5.2\\",\\r\\n \\"karma\\": \\"^1.3.0\\",\\r\\n \\"karma-chrome-launcher\\": \\"^2.0.0\\",\\r\\n \\"karma-jasmine\\": \\"^1.1.0\\",\\r\\n \\"karma-webpack\\": \\"^1.8.1\\"\\r\\n }\\r\\n```\\r\\n\\r\\n* ES6+相关依赖有babel-core、babel-loader和babel-preset-es2015\\r\\n\\r\\n在webpack.config.js中配置js文件使用babel-loader编译。\\r\\n```js\\r\\nloaders: [\\r\\n {\\r\\n loader: \'babel-loader\',\\r\\n test: /\\\\.js$/,\\r\\n query: {\\r\\n presets: \'es2015\',\\r\\n }\\r\\n }\\r\\n]\\r\\n```\\r\\n\\r\\n* webpack相关依赖有node-libs-browser和webpack\\r\\n* 其余都是单元测试相关依赖\\r\\n\\r\\n 注意,这里使用了karma-webpack。因为使用Omi框架支持ES6+和ES5,使用karma-webpack是为了在单元测试里面使用ES6+的import和Class等语法。\\r\\n\\r\\n在karma.conf.js中配置webpack:\\r\\n\\r\\n```js\\r\\n webpack: webpackConfig,\\r\\n webpackMiddleware:{\\r\\n noInfo:false\\r\\n },\\r\\n plugins: [\\r\\n \'karma-webpack\',\\r\\n \'karma-jasmine\',\\r\\n \'karma-chrome-launcher\'\\r\\n ]\\r\\n```\\r\\n\\r\\n具体配置看test目录下的[karma.conf.js](https://github.com/AlloyTeam/omi/blob/master/test/karma.conf.js)和[webpack.test.config.js](https://github.com/AlloyTeam/omi/blob/master/test/webpack.test.config.js)便可。\\r\\n\\r\\n注意,karma.conf.js需要设置\\r\\n\\r\\n```js\\r\\n// if true, Karma captures browsers, runs the tests and exits\\r\\nsingleRun: true,\\r\\n```\\r\\n\\r\\n不然,travis ci脚本执行的时候不会中断导致执行超时异常。\\r\\n\\r\\n## npm 脚本\\r\\n\\r\\n```js\\r\\n \\"scripts\\": {\\r\\n \\"build\\": \\"webpack -w\\",\\r\\n \\"test\\": \\"karma start test/karma.conf.js\\",\\r\\n \\"hello\\": \\"webpack -w\\",\\r\\n \\"todo\\": \\"webpack -w\\"\\r\\n }\\r\\n```\\r\\n\\r\\n其中:\\r\\n* npm run build : 生成dist目录的omi.js文件\\r\\n* npm run test : 执行单元测试\\r\\n* npm run hello : 编译hello的demo\\r\\n* npm run todo : 编译todo的demo\\r\\n\\r\\n在webpack.config.js中,会根据 process.env.npm_lifecycle_event去设置不同的入口文件。所以同样是执行webpack -w,执行结果可以不一样。\\r\\n\\r\\n来看下build的相关webpack配置:\\r\\n\\r\\n```js\\r\\nif(ENV === \'build\'){\\r\\n config = {\\r\\n entry: {\\r\\n omi: \'./src/index.js\'\\r\\n },\\r\\n output: {\\r\\n path: \'dist/\',\\r\\n library:\'Omi\',\\r\\n libraryTarget: \'umd\',\\r\\n filename: \'[name].js\'\\r\\n },\\r\\n```\\r\\n\\r\\n这里把libraryTarget设置成了umd,webpack会帮助我们build出umd的Omi。\\r\\n\\r\\n如果是打包demo(npm run hello 和 npm run todo)的话,会进入下面的条件判断:\\r\\n\\r\\n```js\\r\\nelse {\\r\\n config.entry = \'./example/\' + ENV + \'/main.js\';\\r\\n config.output.path = \'./example/\' + ENV + \'/\';\\r\\n}\\r\\n```\\r\\n\\r\\n会去example下对应的目录查找main.js作为webpack入口文件。\\r\\n\\r\\n这里可以看到,我们不仅用webpack build出Omi框架,也使用webpack build所有demo。\\r\\n详细配置参考[webpack.config.js](https://github.com/AlloyTeam/omi/blob/master/webpack.config.js)的配置。\\r\\n\\r\\n## 参考文档\\r\\n\\r\\n* [http://www.cnblogs.com/cqhaibin/p/5867125.html](http://www.cnblogs.com/cqhaibin/p/5867125.html)\\r\\n* [https://karma-runner.github.io/latest/intro/installation.html](https://karma-runner.github.io/latest/intro/installation.html)\\r\\n* [https://karma-runner.github.io/latest/intro/configuration.html](https://karma-runner.github.io/latest/intro/configuration.html)\\r\\n\\r\\n"'},function(n,e){n.exports="module.exports = \"

    Hello Omi

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)的每个组件都继承自Omi.Component,本篇会去完成Omi的Component的基本锥形,让其能够渲染第一个组件。\\r\\n\\r\\n## omi.js实现\\r\\n\\r\\n```js\\r\\nvar Omi = {};\\r\\nOmi._instanceId = 0;\\r\\nOmi.getInstanceId = function () {\\r\\n return Omi._instanceId++;\\r\\n};\\r\\n\\r\\nOmi.render = function(component, renderTo){\\r\\n component.renderTo = typeof renderTo === \\\"string\\\" ? document.querySelector(renderTo) : renderTo;\\r\\n component._render();\\r\\n return component;\\r\\n};\\r\\n\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n* Omi.getInstanceId 用来给每个组件生成自增的ID\\r\\n* Omi.render 用来把组件渲染到页面\\r\\n\\r\\n## 基类Omi.Component实现\\r\\n\\r\\n所有的组件都是继承自Omi.Component。\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\n\\r\\nclass Component {\\r\\n constructor(data) {\\r\\n this.data = data || {};\\r\\n this.id = Omi.getInstanceId();\\r\\n this.HTML = null;\\r\\n this.renderTo = null;\\r\\n }\\r\\n\\r\\n _render() {\\r\\n this.HTML = this.render();\\r\\n this.renderTo.innerHTML = this.HTML;\\r\\n }\\r\\n}\\r\\n\\r\\nexport default Component;\\r\\n```\\r\\n\\r\\n* Omi使用完全面向对象的方式去开发组件,这里约定好带有下划线的方法是用于内部实现调用,不建议Omi框架的使用者去调用。\\r\\n* 其中,_render为私有方法用于内部实现调用,会去调用组件的真正render方法用于生成HTML,并且把生成的HTML插入到renderTo容器里面。\\r\\n* 注意,这里目前没有引入dom diff,不管第几次渲染都是无脑设置innerHTML,复杂HTML结构对浏览器的开销很大,这里后续会引入diff。\\r\\n\\r\\n## index.js整合\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi = Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n这里把Omi给直接暴露在window下,因为每个组件都生成了唯一的ID,后续实现事件作用域以及对象实例获取都要通过window下的Omi获取。\\r\\n\\r\\n## 最后使用\\r\\n\\r\\n实现完omi.js和component.js以及index.js之后,你就可以实现Hello Omi拉:\\r\\n\\r\\n```js\\r\\nimport Omi from 'index.js'; \\r\\n//或者使用webpack build之后的omi.js \\r\\n//import Omi from 'omi.js';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,`+ this.data.name +`!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : 'Omi' }),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n什么?都2017年了还在拼接字符串?!虽然ES6+的template string让多行字符串拼接更加得心应手,但是template string+模板引擎可以让更加优雅方便。既然用了template string,也可以写成这样子:\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,${this.data.name}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : 'Omi' }),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n## 引入mustachejs模板引擎\\r\\n\\r\\nOmi支持任意模板引擎。可以看到,上面是通过拼接字符串的形式生成HTML,这里当然可以使用模板引擎。\\r\\n\\r\\n修改一下index.js:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Mustache from './mustache.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.template = Mustache.render;\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi=Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n这里把Mustache.render挂载在Omi.template下。再修改一下component.js:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\n\\r\\nclass Component {\\r\\n constructor(data) {\\r\\n this.data = data || {};\\r\\n this.id = Omi.getInstanceId();\\r\\n this.HTML = null;\\r\\n }\\r\\n\\r\\n _render() {\\r\\n this.HTML = Omi.template(this.render(), this.data);\\r\\n this.renderTo.innerHTML = this.HTML;\\r\\n }\\r\\n}\\r\\n\\r\\nexport default Component;\\r\\n```\\r\\n\\r\\nOmi.template(即Mustache.render)需要接受两个参数,第一个参数是模板,第二个参数是模板使用的数据。\\r\\n\\r\\n现在,你便可以使用mustachejs模板引擎的语法了:\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n从上面的代码可以看到,你完全可以重写Omi.template方法去使用任意模板引擎。重写Omi.template的话,建议使用omi.lite.js,因为omi.lite.js是不包含任何模板引擎的。那么怎么build出两个版本的omi?且看webpack里设置的多入口:\\r\\n\\r\\n```js\\r\\n entry: {\\r\\n omi: './src/index.js',\\r\\n 'omi.lite': './src/index.lite.js'\\r\\n},\\r\\noutput: {\\r\\n path: 'dist/',\\r\\n library:'Omi',\\r\\n libraryTarget: 'umd',\\r\\n filename: '[name].js'\\r\\n},\\r\\n```\\r\\n\\r\\nindex.lite.js的代码如下:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.template = function(tpl, data){\\r\\n return tpl;\\r\\n}\\r\\n\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi=Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n可以看到Omi.template没有对tpl做任何处理直接返回,开发者可以重写该方法。\\r\\n\\r\\n## 总结\\r\\n\\r\\n到目前为止,已经实现了:\\r\\n\\r\\n* 第一个组件的渲染\\r\\n* 模板引擎的接入\\r\\n* 多入口打包omi.js和omi.lite.js\\r\\n\\r\\n下片,将介绍《Omi原理-局部CSS》,欢迎关注...\\r\\n\""},function(n,e){n.exports='module.exports = "## 写在前面\\r\\nOmi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。\\r\\n\\r\\n项目开始之前,实现选择一个脚手架。这个项目用的就是[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)\\r\\n\\r\\nGulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)\\r\\n\\r\\n\\r\\n所以,要使用Fiddler并配置Extention:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)\\r\\n\\r\\n\\r\\n## 目录\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)\\r\\n\\r\\n\\r\\n目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。\\r\\n组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。\\r\\n\\r\\n## 命令\\r\\n\\r\\n开发\\r\\n```js\\r\\nnpm run dev\\r\\n```\\r\\n\\r\\n发布\\r\\n```js\\r\\nnpm run dist\\r\\n```\\r\\n\\r\\n## 开始写码\\r\\n\\r\\n万事具备,开始写码。先写组件:\\r\\n\\r\\n```js\\r\\nimport Omi from \'omi\'\\r\\n\\r\\nclass UserList extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n install() {\\r\\n this.data.uin_info || (this.data.uin_info = [])\\r\\n this.data.uin_info.forEach(user => {\\r\\n this.prepareData(user)\\r\\n })\\r\\n }\\r\\n \\r\\n prepareData(user){\\r\\n user.desc_d = user.desc.split(\\" \\")[0]\\r\\n user.desc_t = user.desc.split(\\" \\")[1]\\r\\n user.isBoy = user.sex === \\"男\\"\\r\\n user.qlogo = user.url.replace(\\"http://\\", location.protocol + \\"//\\").replace(/&/g, \\"&\\")\\r\\n if (user.profession_desc) {\\r\\n user.hasProfession_desc = true\\r\\n }\\r\\n }\\r\\n \\r\\n appendUsers (users) {\\r\\n users.uin_info && users.uin_info.forEach(user =>{\\r\\n this.prepareData(user)\\r\\n this.data.uin_info.push(user)\\r\\n })\\r\\n this.update()\\r\\n }\\r\\n\\r\\n sendGift(uin, nick, qlogo) {\\r\\n //送礼物并关闭webview,此处省略\\r\\n //..\\r\\n //..\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n {{#uin_info}}\\r\\n
    \\r\\n
    \\r\\n \\r\\n
    \\r\\n
    \\r\\n
    {{{nick}}}
    \\r\\n
    \\r\\n {{#isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{^isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{#hasProfession_desc}} {{profession_desc}} {{/hasProfession_desc}}\\r\\n
    \\r\\n
    {{{intro}}}
    \\r\\n
    \\r\\n
    {{desc_d}} · {{desc_t}}
    \\r\\n
    \\r\\n {{/uin_info}}\\r\\n
    加载中...
    \\r\\n
    \\r\\n`\\r\\n }\\r\\n\\r\\n style() {\\r\\n return `\\r\\n\\r\\n\\r\\n.qlogo {\\r\\n overflow: hidden;\\r\\n width: 70px;\\r\\n height: 70px;\\r\\n -webkit-border-radius: 50%;\\r\\n border-radius: 50%;\\r\\n position: absolute;\\r\\n top: 10px;\\r\\n left: 12px;\\r\\n}\\r\\n...\\r\\n...\\r\\n..这里省略大量.....\\r\\n...\\r\\n...\\r\\n\\r\\n.distance_info {\\r\\n position: absolute;\\r\\n top: 15px;\\r\\n right: 9px;\\r\\n color: #7B7B84;\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nexport default UserList\\r\\n```\\r\\n\\r\\n组件里面有5个方法:\\r\\n\\r\\n* constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this\\r\\n* install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理\\r\\n* prepareData 对数据进行一些处理来满足模板的渲染\\r\\n* appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用\\r\\n* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..\\r\\n\\r\\n其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。\\r\\nrender里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;\\r\\n如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。\\r\\n\\r\\n这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)\\r\\n\\r\\n\\r\\n下面来看index.js:\\r\\n\\r\\n```js\\r\\nimport Root from \'./config.js\'\\r\\nimport Omi from \'omi\'\\r\\nimport UserList from \'../component/user_list/index.js\'\\r\\n\\r\\nOmi.makeHTML(\'UserList\', UserList)\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n installed() {\\r\\n window.onscroll = () => this.loadMore()\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n\\r\\n loadMore() {\\r\\n const body = document.body,\\r\\n html = document.documentElement,\\r\\n height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),\\r\\n vp_height = window.innerHeight\\r\\n\\r\\n if (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n }\\r\\n\\r\\n requestData(callback) {\\r\\n if (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }else{\\r\\n \\t//ajax 请求数据,这里省略\\r\\n }\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Main(),\'body\')\\r\\n```\\r\\n\\r\\n通过Omi.makeHTML(\'UserList\', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:\\r\\n\\r\\n```js\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n```\\r\\n\\r\\n下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。\\r\\n\\r\\n```js\\r\\nwindow.onscroll = () => this.loadMore()\\r\\n```\\r\\n\\r\\n通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:\\r\\n\\r\\n```js\\r\\nif (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n}\\r\\n```\\r\\n\\r\\nrequestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。\\r\\n慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:\\r\\n\\r\\n```js\\r\\n \\r\\n```\\r\\n\\r\\n上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!\\r\\n\\r\\n再来看下数据模拟:\\r\\n\\r\\n```js\\r\\nif (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }\\r\\n```\\r\\n\\r\\n这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!\\r\\n\\r\\n## 最后\\r\\n\\r\\n好了,就这么多,Omi让代码真心方便简洁~~~\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)"'},function(n,e){n.exports='module.exports = "# Omi命令行界面omi-cli发布\\r\\n\\r\\n通常认为,命令行界面(CLI)没有图形用户界面(GUI)那么方便用户操作。但是CLI比GUI节约资源,在熟悉命令之后,CLI会比GUI更加高效地帮你完成想要的任务。\\r\\n\\r\\n下面来介绍下[pasturn](https://github.com/pasturn)童鞋为Omi开发的CLI的两种使用姿势:\\r\\n\\r\\n## 姿势一\\r\\n\\r\\n```js\\r\\n$ npm install omi-cli -g //安装cli\\r\\n$ omi init your_project_name //初始化项目\\r\\n$ cd your_project_name //转到项目目录\\r\\n$ npm run dev //开发\\r\\n$ npm run dist //部署发布\\r\\n```\\r\\n\\r\\n## 姿势二\\r\\n\\r\\n当我们在一个空文件夹的时候,可以执行下面的命令。\\r\\n\\r\\n```js\\r\\n$ npm install omi-cli -g //安装cli\\r\\n$ omi init //初始化项目\\r\\n$ npm run dev //开发\\r\\n$ npm run dist //部署发布\\r\\n```\\r\\n\\r\\n这里不用再去跳转目录了,当前目录就是项目的目录。\\r\\n\\r\\n## 安装过程截图\\r\\n\\r\\n安装omi-cli:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100545470-696026058.png)\\r\\n\\r\\n\\r\\n安装初始化项目omi init:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100554891-1802174132.png)\\r\\n\\r\\n上面的成功的界面。注意:初始化项目会自动安装相关的npm依赖包,所以时间较长,请耐心等待。\\r\\n安装完成之后,在项目目录下你可以看到下面的目录结构:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100755845-465268116.png)\\r\\n\\r\\n开发 npm run dev:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100601235-1477801934.png)\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100608985-921528126.png)\\r\\n\\r\\n如果,你看到了上面的界面,说明一切OK了。创建出来的项目主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。Gulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n## 后续\\r\\n\\r\\n更多脚手架模板以及更多功能的命令正在开发中,如果有什么意见或者建议欢迎让我们知道。\\r\\n\\r\\n## 相关\\r\\n\\r\\n* Omi的Github地址[https://github.com/AlloyTeam/omi](https://github.com/AlloyTeam/omi)\\r\\n* 如果想体验一下Omi框架,可以访问 [Omi Playground](http://alloyteam.github.io/omi/example/playground/)\\r\\n* 如果想使用Omi框架或者开发完善Omi框架,可以访问 [Omi使用文档](https://github.com/AlloyTeam/omi/tree/master/docs#omi使用文档)\\r\\n* 如果你想获得更佳的阅读体验,可以访问 [Docs Website](http://alloyteam.github.io/omi/website/docs.html)\\r\\n* 如果你懒得搭建项目脚手架,可以试试 [omi-cli](https://github.com/AlloyTeam/omi/tree/master/cli)\\r\\n* 如果你有Omi相关的问题可以 [New issue](https://github.com/AlloyTeam/omi/issues/new)\\r\\n* 如果想更加方便的交流关于Omi的一切可以加入QQ的Omi交流群(256426170)\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170208095745213-1049686133.png)"'},function(n,e){n.exports='module.exports = "

    Component Communication

    \\r\\n\\r\\nCommunication between [Omi](https://github.com/AlloyTeam/omi) components is very flexible, there are many options:\\r\\n\\r\\n- By declaring `data-*` on the component to pass data to child node\\r\\n- By declaring `data` on the component to pass data to child node (support complex data types mapping)\\r\\n- By declaring `childrenData` on parent component to automatically pass data to child node\\r\\n- By declaring `group-data` (support complex data types mapping)\\r\\n- It\'s completely object-oriented, you can easily get the object instance, then you can set the instance of the property or call the instance of the method\\r\\n\\r\\nLet\'s see some examples.\\r\\n\\r\\n### Communicate by `data-*`\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n \\tcursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nGenerally `data-*` is used to pass value types such as string and number. It is worth noting that, through `data-*`, received data types are string. You need to manually transform it to the number type.\\r\\n\\r\\nNormally, communicate by `data-*` is enough, but sometimes we may need to use complex data types, then we can use `data` to communicate.\\r\\n\\r\\n### Communicate by `data`\\r\\n\\r\\nAs shown in the above code, name can be passed to the subcomponent by `data-name=\\"Omi\\"`. The following code can also achieve the same effect.\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.helloData = { name : \'Omi\' };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nUse the `data` tag, it will find the property from the component instance (that is, this), this can be mounted with any complex objects. This also broke the limitations of `data-*`.\\r\\n\\r\\nThen how do we pass `data` that is in a deep depth of the instance to the Hello? No worries, `data` tag can be a complex statement:\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nClick me for the complex data mapping\\r\\n\\r\\n### Communicate by `childrenData`\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.childrenData = [{ name : \'Omi\' } , { name : \'dntzhang\' }];\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nWe can use `this.childrenData` to transfer data to the sub-component. In this case, `childrenData` is an array, so it can pass data to multiple components in the same time. In the meanwhile, the data will be passed to components one by one.\\r\\n\\r\\n### Communicate by `group-data`\\r\\n\\r\\n`childrenData` can pass data to multiple components. However, there are many scenes where the source of data does not have to be from `childrenData`. `childrenData` is an array, and it should be the same order with the components, so that the data must all concentrated in `childrenData`, it\'s very inconvenient. `group-data` dedicated to solve the above pain points, specifically to pass data to a group of components.\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.testData = [{name: \'Omi\'}, {name: \'dntzhang\'}, {name: \'AlloyTeam\'}];\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nBy declaring a `group-data` tag in the sub-components, it will go to the current instance of the component (that is, `this`) to find the corresponding property. Then according to the current location, the data will pass to the positions one by one.\\r\\n\\r\\nThe results are as follows:\\r\\n\\r\\n![group-data results](http://images2015.cnblogs.com/blog/105416/201702/105416-20170216110701535-1698390390.png)\\r\\n\\r\\nClick me for the group-data example\\r\\n\\r\\nSimilarly, `group-data` supports the mapping of complex data types. It should be noted that the end of the group-data mapping must be an array:\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nClick me for the complex group-data mapping\\r\\n\\r\\n### By object instance\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n this.hello.data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n### By omi-id\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n Omi.get(\\"hello\\").data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nBy declaring `omi-id` on the component, we can get the instance of the object anywhere in the program. This can be regarded as any component communication artifacts.\\r\\n\\r\\n### Warm Tips\\r\\n\\r\\n- The data that passed by `childrenData` or `data` is shadow copied to sub-components. In order to update it, we need to update the `data` attribute of the component instance.\\r\\n- The data that passed by `data-*` is also shadow copied to sub-components. In order to update it, we need to update the `data` attribute of the component instance.\\r\\n- If we set the `dataFirst` property of the component instance to `false`, then `data-*` will override the `data` of component instance.\\r\\n\\r\\nFor the third tip, please checkout the pseudo-code:\\r\\n\\r\\n```js\\r\\nif(this.dataFirst){\\r\\n this.data = Object.assign({},data-✼ ,this.data);\\r\\n}else{\\r\\n this.data = Object.assign({},this.data, data-✼);\\r\\n}\\r\\n```"'; -},function(n,e){n.exports='module.exports = "

    Components

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is based entirely on component architecture, which allows developers to build web applications like building blocks. Everything is components, components can be nested to create new components.\\r\\n\\r\\n![Omi Components System](http://images2015.cnblogs.com/blog/105416/201702/105416-20170210093427338-1536910080.png)\\r\\n\\r\\n### Simple Components\\r\\n\\r\\nLet\'s explore a simple Todo example to learn the components system in Omi.\\r\\n\\r\\n```js\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.data.items.push(this.data.text);\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n
      {{#items}}
    • {{.}}
    • {{/items}}
    \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Todo({ items: [] ,text : \'\' }),\\"body\\");\\r\\n```\\r\\n\\r\\nThe HTML generated by the component will eventually be inserted into the body. The above example shows some of the features of Omi:\\r\\n\\r\\n- Data flow: `data` in `new Todo(data,..)` can be used directly in the template in render method.\\r\\n- Partial CSS: `h3` in `style()` only effect inside of render. It\'ll never pollute `h3` outside of this component. The same rule applies to `button`.\\r\\n- Declarative event binding: `onchange` will call `handleChange` that inside of the component. `this` refers to the current DOM element, `event` refers to the current DOM Event Object.\\r\\n- You need to manually call the `this.update()` method to update the component\\r\\n\\r\\nIt is important to note that, for more freedom and flexibility, Omi does not automatically update DOM while data changes. Developers need to call the `update` method manually.\\r\\n\\r\\nYou can also use [oba] (https://github.com/dntzhang/oba) or mobx to implement automatic updates.\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n## Component Nesting\\r\\n\\r\\nIt\'s ok to not use nesting component if your page is super simple. However, for most of webpages and web applications, it is a necessary to define the nesting Components to implement complex features.\\r\\n\\r\\nFor instance, we can extract a `List` component form the Todo example. This brings maintainable, scalable and reuseable to our project:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
      {{#items}}
    • {{.}}
    • {{/items}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nThen how to use this `List`? We need to use `Omi.makeHTML` to make the `List` to a tag which can be used in render method:\\r\\n\\r\\n```js\\r\\nimport List from \'./list.js\';\\r\\n\\r\\nOmi.makeHTML(\'List\', List);\\r\\n\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.data.length = this.data.items.length;\\r\\n this.listData = { items : this.data.items };\\r\\n }\\r\\n\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.list.data.items.push(this.data.text);\\r\\n this.data.length = this.list.data.items.length;\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n- In line 3, we use `makeHTML` to make the component to a tag which can be used in render method. Of course, `Omi.makeHTML(\'List\', List);` can also be written in the end of List component.\\r\\n- In line 9, the parent component defines the \'listData\' property\\r\\n- In line 34, we use List component in the render method. `name` attribute allows us easily find the instance of the component by using `this`.`data=\\"listData\\"` attribute allows us easily pass `this.listData` to the sub component from parent component.\\r\\n\\r\\nIt should be noted that the `data` passed from `data=\\"listData\\"` is cloned to the subcomponents by Object.assign(shallow copy) , which means if we want to change the DOM, we recommend that first update the `data` of the instance of subcomponent(not the parent component\'s `listData` ) and secondly call the `update` method.\\r\\n\\r\\nIn fact there are 4 way to communicate between components, it\'ll be explained later.\\r\\n\\r\\nClick me for the live demo\\r\\n"'},function(n,e){n.exports="module.exports = \"

    Conditional Rendering

    \\r\\n\\r\\nIn most case, we need to show different layouts according to different states. For example, some users are vip and we need to show vip logo for them. Omi has many ways to meet this kind of requirements.\\r\\n\\r\\n### First Option\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `{{#isVip}}\\r\\n
    you are VIP.
    \\r\\n {{/isVip}}\\r\\n {{^isVip}}\\r\\n
    you are not VIP.
    \\r\\n {{/isVip}}`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nIn the above case, we use the condition in mustachejs for rendering. Of course Omi does not force you to use mustachejs. You can use omi.lite.js and then override the `Omi.template` method to use any of your favorite template engines.\\r\\n\\r\\n### Second Option\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n`render` provides a very good programmability, which can write any js code inside. Oh, don't forget that `style` method can also have js code inside it.\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style (){\\r\\n if(this.data.isVip){\\r\\n return 'div{ color : red; }';\\r\\n }else{\\r\\n return 'div{ color : green; }';\\r\\n }\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\""},function(n,e){n.exports='module.exports = "

    Handling Events

    \\r\\n\\r\\nThere are two types of events in Omi, built-in events and custom events. Built-in events clever use of the browser\'s own pipeline mechanism, you can easily get events instance and the triggered event elements through `event` and `this`.\\r\\n\\r\\n### Built-in events\\r\\n\\r\\nWhat is the built-in event? As long as the it can match the following regular expression.\\r\\n\\r\\n```js\\r\\non(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave)\\r\\n```\\r\\n\\r\\nHow to bind built-in events? As follows:\\r\\n\\r\\n```js\\r\\nclass EventTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n handleClick(dom, evt){\\r\\n alert(dom.innerHTML);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Hello, Omi!
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### Custom events\\r\\n\\r\\nEvents that defined by developers is the custom events. Here is the pagination example:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\nimport Pagination from \'./pagination.js\';\\r\\nimport Content from \'./content.js\';\\r\\n\\r\\nOmi.makeHTML(\'Pagination\', Pagination);\\r\\nOmi.makeHTML(\'Content\', Content);\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.content.goto(this.pagination.data.currentPage+1);\\r\\n }\\r\\n handlePageChange(index){\\r\\n this.content.goto(index+1);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    Pagination Example

    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render( new Main(),\'body\');\\r\\n```\\r\\n\\r\\nAs we can see, the `onPageChange` is a custom event, `handlePageChange` will being executed when `onPageChange` is triggered. The `onPageChange` method is executed in `Pagination`:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\n\\r\\nclass Pagination extends Omi.Component {\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n linkTo: \\"#\\",\\r\\n prevText: \\"Prev\\",\\r\\n nextText: \\"Next\\",\\r\\n ellipseText: \\"...\\",\\r\\n prevShow: true,\\r\\n nextShow: true,\\r\\n onPageChange: function () { return false; }\\r\\n }, this.data);\\r\\n\\r\\n this.pageNum = Math.ceil(this.data.total / this.data.pageSize);\\r\\n }\\r\\n goto (index,evt) {\\r\\n evt.preventDefault();\\r\\n this.data.currentPage=index;\\r\\n this.update();\\r\\n this.data.onPageChange(index);\\r\\n }\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\nThis is a part of `Pagination` code. Highlight is the place to execute `onPageChange`.\\r\\n\\r\\n### Links\\r\\n\\r\\n- [Demo](http://alloyteam.github.io/omi/example/pagination/)\\r\\n- [Source](https://github.com/AlloyTeam/omi/tree/master/example/pagination)"'},function(n,e){n.exports='module.exports = "

    Forms

    \\r\\n\\r\\nIt\'s much more convenient to control forms in Omi, especially `\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n\\r\\n```\\r\\n\\r\\nThe third option is selected because it is being set to `selected` attribute. The problem is that developers need to traversed each option. While using Omi, you can write code like this:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\nThis will achieve the same effect. For example, you want to choose the first item:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\nIsn\'t it very convenient?\\r\\n\\r\\n### For Example\\r\\n\\r\\n```js\\r\\nclass FormTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n \\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n console.log(target.value)\\r\\n this.data.value = target.value;\\r\\n }\\r\\n\\r\\n handleSubmit(evt) {\\r\\n alert(\'Your favorite flavor is: \' + this.data.value);\\r\\n evt.preventDefault();\\r\\n }\\r\\n \\r\\n render () {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new FormTest({ value: \'mango\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for a live demo"'},function(n,e){n.exports='module.exports = "

    Get DOM

    \\r\\n\\r\\nWhile most of the time, developers do not need to find the DOM, but sometimes is a need to get the DOM.\\r\\n\\r\\nOmi provides a way to get the DOM node.\\r\\n\\r\\n### ref and refs\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(){\\r\\n alert(this.refs.abc.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\nAs we can see, by referencing `ref` as `abc` in HTML, the DOM node can be accessed through `this.refs.abc`.\\r\\n\\r\\nClick me for the live demo\\r\\n"'},function(n,e){n.exports='module.exports = "

    Hello World

    \\r\\n\\r\\n\\r\\n### Hello World with ES20XX \\r\\n\\r\\nWe recommend using a bundler like [webpack](https://webpack.github.io/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time.\\r\\n\\r\\nThe small Omi example looks like this:\\r\\n\\r\\n```js\\r\\nimport Omi from \'./omi.js\';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"body\\");\\r\\n\\r\\n```\\r\\n\\r\\nThis code renders into body element. \\r\\n\\r\\n\\r\\n### Hello World with ES5\\r\\n\\r\\n\\r\\n```html\\r\\n\\r\\n```"'},function(n,e){n.exports='module.exports = "

    Inheritance

    \\r\\n\\r\\nThrough the inheritance mechanism, we can define new classes base on old classes. The new classes not only have newly defined members, but also have old members at the same time.\\r\\n\\r\\nWe call the existing class the base class, also known as the parent class. And the new class derived from the existing class is called a derived class, also known as a subclass.\\r\\n\\r\\n### For Example\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n div{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n}\\r\\n\\r\\nclass SubHello extends Hello {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n### inherit in ES5\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\",{\\r\\n render:function(){\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n})\\r\\n\\r\\nvar SubHello = Omi.create(\\"SubHello\\",Hello,{ });\\r\\n\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports='module.exports = "

    Installation

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is open and modern framework for building user interfaces.\\r\\n\\r\\n### Installing Omi\\r\\n\\r\\nWe recommend using [npm](https://www.npmjs.com/) for managing front-end dependencies. If you\'re new to package managers.\\r\\n\\r\\nTo install Omi with npm, run:\\r\\n\\r\\n``` js\\r\\nnpm install omi\\r\\n```\\r\\n### omi-cli\\r\\n\\r\\n``` js\\r\\n$ npm install omi-cli -g \\r\\n$ omi init your_project_name \\r\\n$ cd your_project_name \\r\\n$ npm run dev \\r\\n$ npm run dist \\r\\n```"'},function(n,e){n.exports='module.exports = "

    Lifecycle

    \\r\\n\\r\\n| Name | Meaning | Occasion |\\r\\n| :-------------: | :-------------: | :-----: |\\r\\n| constructor | The constructor | When new a constructor |\\r\\n| install | The installation. We can process the data that user pass | When instantiate |\\r\\n| installed | Complete the installation. It\'ll trigger after HTML being inserted to the page. Please note that it\'ll trigger when component being removed and restored | **Instantiation and existence** |\\r\\n| uninstall | Uninstall the component. It\'ll trigger when remove is executed | When destroy |\\r\\n| beforeUpdate | Before update | When existence |\\r\\n| afterUpdate | After update | When existence |\\r\\n\\r\\n## Illustration\\r\\n\\r\\n![lc](http://images2015.cnblogs.com/blog/105416/201701/105416-20170119153018546-1566368987.png)\\r\\n\\r\\nIt should be noted that the installed will be executed during the instantiation, which is not shown above. For example, it\'ll executed when a component is removed and restored, or when the new component is being added.\\r\\n\\r\\n### Examples\\r\\n\\r\\n```js\\r\\nclass Timer extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n install () {\\r\\n this.data = {secondsElapsed: 0};\\r\\n }\\r\\n\\r\\n tick() {\\r\\n this.data.secondsElapsed++;\\r\\n this.update();\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.interval = setInterval(() => this.tick(), 1000);\\r\\n }\\r\\n\\r\\n uninstall() {\\r\\n clearInterval(this.interval);\\r\\n }\\r\\n\\r\\n\\r\\n style () {\\r\\n return `\\r\\n .num { color:red; }\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Seconds Elapsed: {{secondsElapsed}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports='module.exports = "

    Loop

    \\r\\n\\r\\nThe following describes how to traverses in mustache.js and javascript.\\r\\n\\r\\n### First Option\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n
      \\r\\n {{#items}} \\r\\n
    • {{text}}
    • \\r\\n {{/items}}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nMustache.js more detailed loop traversal use can see \\r\\n\\r\\nFor more details for traversal in mustache.js please view [https://github.com/janl/mustache.js#non-empty-lists](https://github.com/janl/mustache.js#non-empty-lists).\\r\\n\\r\\nFor example, it also support:\\r\\n\\r\\n- If each item of items is a string, you can directly use **{{.}}** to output each item\\r\\n- Call the defined function when looping\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n### Second Option\\r\\n\\r\\nOf course, you can also use template string inside the `map`:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `
    \\r\\n
      \\r\\n ${this.data.items.map(item =>\\r\\n `
    • ${item.text}
    • `\\r\\n ).join(\'\')}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nYou will see the following page:\\r\\n\\r\\n![pv](http://images2015.cnblogs.com/blog/105416/201701/105416-20170122095724129-2059595233.png)\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports="module.exports = \"

    Plugin

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is a componentized web framework. Then what is plugin?\\r\\n\\r\\nIt can be understood that the Omi plugin system can give the dom element some ability and can be associated with the instance of the components.\\r\\n\\r\\n### omi-drag\\r\\n\\r\\nLet's see this example:\\r\\n\\r\\nClick me for the live deme\\r\\n\\r\\n```js\\r\\nimport OmiDrag from './omi-drag.js';\\r\\n\\r\\nOmiDrag.init();\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n\\r\\n style(){\\r\\n return `\\r\\n .test{\\r\\n width:100px;\\r\\n height:100px;\\r\\n color:white;\\r\\n line-height:90px;\\r\\n text-align:center;\\r\\n background-color:#00BFF3;\\r\\n }\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\\"#container\\\");\\r\\n```\\r\\n\\r\\nAs shown above, by adding `omi-drag` attribute to the div, it can be dragged by the user using the mouse. We call omi-drag.js an omi plugin.\\r\\n\\r\\nIsn't it very convenient? So how did this omi-drag implement?\\r\\n\\r\\n如上面的代码所示,通过在div上标记omi-drag,这个div就能够被用户使用鼠标拖拽。我们称omi-drag.js为omi插件。\\r\\n是不是非常方便?那么这个omi-drag是怎么实现的?\\r\\n\\r\\n## Omi.extendPlugin\\r\\n\\r\\nCore method: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\nThe following code shows how to use `Omi.extendPlugin` to give dom the drap and drop ability:\\r\\n\\r\\n```js\\r\\n;(function () {\\r\\n\\r\\n var OmiDrag = {};\\r\\n var Omi = typeof require === 'function'\\r\\n ? require('omi')\\r\\n : window.Omi;\\r\\n\\r\\n OmiDrag.init = function(){\\r\\n Omi.extendPlugin('omi-drag',function(dom, instance){\\r\\n dom.style.cursor='move';\\r\\n var isMouseDown = false,\\r\\n preX = null,\\r\\n preY = null,\\r\\n currentX = null,\\r\\n currentY = null,\\r\\n translateX = 0,\\r\\n translateY = 0;\\r\\n\\r\\n dom.addEventListener('mousedown',function(evt){\\r\\n isMouseDown = true;\\r\\n preX = evt.pageX;\\r\\n preY = evt.pageY;\\r\\n evt.stopPropagation();\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n }\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mouseup',function(){\\r\\n isMouseDown = false;\\r\\n preX = preY = currentX = currentY = null;\\r\\n },false);\\r\\n });\\r\\n }\\r\\n\\r\\n OmiDrag.destroy = function(){\\r\\n delete Omi.plugins['omi-drag'];\\r\\n };\\r\\n\\r\\n if (typeof exports == \\\"object\\\") {\\r\\n module.exports = OmiDrag;\\r\\n } else if (typeof define == \\\"function\\\" && define.amd) {\\r\\n define([], function(){ return OmiDrag });\\r\\n } else {\\r\\n window.OmiDrag = OmiDrag;\\r\\n }\\r\\n\\r\\n})();\\r\\n```\\r\\n\\r\\nMethod: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n`pluginName` is the name of the plugin.\\r\\n\\r\\n`handler` is the processor. The handler can get the dom which marked as the `pluginName` and the instance of the component.\\r\\n\\r\\nWith `Omi.extendPlugin`, we can give the dom some ability, and can also be associated with the component instance.\\r\\n\\r\\nThe above example is not associated with the instance, let's try it:\\r\\n\\r\\n## Associated with instance\\r\\n\\r\\nWe want to be able to listen to the `move` inside the component and perform a callback. As follows:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandler(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nIn this case, the `moveHandler` will be continually executed while dragging. We can modify some code to solve this issue:\\r\\n\\r\\n```js\\r\\n...\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance.moveHandler(evt);\\r\\n }\\r\\n},false);\\r\\n```\\r\\n\\r\\nWe add `instance.moveHandler(evt)` method to execute the `moveHandler` method of component instance.\\r\\n\\r\\nThis is how associated with instance works.\\r\\n\\r\\nHowever, this may still have an issue if we add `omi-drag` to a list of `div`:\\r\\n\\r\\n```js\\r\\n...\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nUsually each of our `omi-drag` can correspond to a callback function, such as:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nHow to achieve this? We can pass the data to the plugin via dom.\\r\\n\\r\\n## Passing data\\r\\n\\r\\nLet's see the final code:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nWhere `omi-drag` modified:\\r\\n\\r\\n```js\\r\\n...\\r\\nvar handlerName = dom.getAttribute('dragMove');\\r\\n\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance[handlerName](evt);\\r\\n }\\r\\n},false);\\r\\n...\\r\\n```\\r\\n\\r\\n- We use `var handlerName = dom.getAttribute('dragMove')` to get the `dragMove` of dom\\r\\n- We use `instance[handlerName](evt)` to execute the method\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n## More plugins\\r\\n\\r\\n* [omi-finger](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-finger) The [AlloyFinger](https://github.com/AlloyTeam/AlloyFinger) plugin for Omi, which support touch events and gustures\\r\\n* [omi-transform](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-transform) The [transformjs](http://alloyteam.github.io/AlloyTouch/transformjs/) plugin for Omi, which can easily set CSS3 Transform to DOM\\r\\n* [omi-touch](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-touch) The [AlloyTouch](https://github.com/AlloyTeam/AlloyTouch) plugin for Omi. The touch movement solution for Omi (support touch scroll, rotate, flip, select, etc.)\\r\\n* [omi-jquery-date-picker](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-jquery-date-picker) The date picker plugin for Omi, which support choose any time zone\\r\\n\""; -},function(n,e){n.exports='module.exports = "

    Templates

    \\r\\n\\r\\nThere are three types of Omi. omi.js and omi.lite.js is for web side.\\r\\n\\r\\n- omi.js has a built-in [mustache.js](https://github.com/janl/mustache.js) as the template engine\\r\\n- omi.lite.js doesn\'t have any template engines\\r\\n\\r\\nOmi does not force developers to use mustache.js, you can use any template engine based on business scenarios or do not use any template engines.\\r\\n\\r\\nHow to use other template engines? Let\'s see the [artTemplate](https://github.com/aui/artTemplate) example.\\r\\n\\r\\n### Use artTemplate\\r\\n\\r\\n```js\\r\\nOmi.template = function(tpl, data){\\r\\n return artTemplate.compile(tpl)(data);\\r\\n}\\r\\n```\\r\\n\\r\\nWe need to rewrite the `Omi.template` method, the `tpl` is the incoming template, the `data` is the required data for the template, and the return value is HTML.\\r\\n\\r\\nAfter rewriting, you can use the artTemplate syntax in `render`, such as:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h1 { color:red; }\\r\\n li{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `

    {{title}}

    \\r\\n
      \\r\\n {{each list as value i}}\\r\\n
    • # {{i + 1}} :{{value}}
    • \\r\\n {{/each}}\\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### Links\\r\\n\\r\\n* [Demo Link](http://alloyteam.github.io/omi/example/artTemplate/)\\r\\n* [Source Code](https://github.com/AlloyTeam/omi/tree/master/example/artTemplate)"'},function(n,e){n.exports='module.exports = "

    Thinking in Omi

    \\r\\n\\r\\nOmi is based on object-oriented programming, with plugin system.\\r\\n\\r\\nThe traditional one-way data flow or the event-throwing component communicating can increase the stability of the system, but it loses it\'s flexibility. To a certain extent also reduced the component reusing.\\r\\n\\r\\nObject-oriented system has an other logical layer, which let you control the instance of components. The logic between instances build the entire program.\\r\\n\\r\\nThen the issues like communication, reusing and logics between components are all solved.\\r\\n\\r\\n\\r\\nPlus, the component is also more single duty, more loosely coupled.\\r\\n\\r\\nFor functional programming, imperative programming and object-oriented programming, we can sum up the following list:\\r\\n\\r\\n- Imperative programming is well understood, we use loop and if-else condition to control processes, it emphasize the process of execution\\r\\n- Imperative programming is hardware friendly, easy to run, but hard to design complex program\\r\\n- Functional programming is all about input and output, not the process of execution\\r\\n- Functional programming advocates multiple simple execution units into complex operations\\r\\n- Object-oriented programming uses objects as the basic unit of the program, with more reusability, flexibility, and extensibility\\r\\n\\r\\nWhat kind of language is JavaScript? We have `class` in ES6+, so is JavaScript object-oriented language?\\r\\n\\r\\nJavaScript can pass a function as a argumant, so is JavaScript a functional language?\\r\\n\\r\\nThere are no right answer, it depands on how you use JavaScript.\\r\\n\\r\\nIt\'s free to chooce, you can use functional programming framework like React, or object-oriented framework like Omi. \\r\\n\\r\\n### Functional Programming VS Object-Oriented Programming\\r\\n\\r\\nIn the UI component framework scope, functional programming is represented by React, while Omi belongs to object-oriented programming.\\r\\n\\r\\nSo what are their strengths and weaknesses? The following is a comparison (in fact, functional programming and object-oriented programming comparison):\\r\\n\\r\\n| | React | Omi |\\r\\n| ------------- |:-------------:|:-----:|\\r\\n| Component communication | ★★★★☆| ★★★★★ |\\r\\n| Stability | ★★★★★ | ★★★★☆ |\\r\\n| Flexibility | ★★★★☆| ★★★★★ |\\r\\n| Scalability | ★★★★☆ | ★★★★★ |\\r\\n| Testability | ★★★★★ | ★★★★☆ |\\r\\n| File size | ★★★☆☆ | ★★★★★ |\\r\\n| Features | ★★★☆☆ | ★★★★☆ |\\r\\n| DOM performance | ★★★★★ | ★★★★☆ |\\r\\n| Animation performance | ★★★★☆ | ★★★★★ |\\r\\n| Abstract complexity | ★★★★☆ | ★★★★★ |\\r\\n| Asynchronous programming | ★★★★★ | ★★★★☆ |\\r\\n\\r\\nAs we can see, we can not have it both ways. Object-oriented programming is more reusable, flexible and scalable, the problem is more difficult to test.\\r\\n\\r\\nSpecifically, if the functional programming, the test area is state1 + state2 + ... + stateN; in object-oriented programming, the test area is state1 × event1 + state2 × event2 + ... + stateN × eventN.\\r\\n\\r\\nIn summary, it is more recommended to use the object-oriented programming to build UI component framework.\\r\\n\\r\\n
    \\r\\n\\r\\n### The end. Thanks for reading. [Let\'s start the Omi journey](https://github.com/AlloyTeam/omi)!\\r\\n"'},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n @media only screen and (max-width: 768px) {\n .list{\n transform: translateX(-100%);\n background-color:white;\n\n -moz-transition: all .6s ease;\n -o-transition: all .6s ease;\n -webkit-transition: all .6s ease;\n transition: all .6s ease;\n }\n\n .list.show {\n -moz-transform: translateX(0%) translateZ(0);\n -ms-transform: translateX(0%) translateZ(0);\n -o-transform: translateX(0%) translateZ(0);\n -webkit-transform: translateX(0%) translateZ(0);\n transform: translateX(0%) translateZ(0);\n }\n }\n\n .list{\n width:200px;\n text-indent: 20px;\n border-right: 1px solid #eee;\n overflow-x: hidden;\n overflow-y: auto;\n position:fixed;\n top:45px;\n }\n .version{\n height:20px;\n }\n \n "}},{key:"render",value:function(){return'\n
    \n
    \n {{#items}} {{/items}}\n
    '}}]),e}(d.default.Component);e.default=h},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n
  • {{title}}
  • \n {{#list}}\n
  • \n {{name}}\n
  • \n {{/list}}\n '}},{key:"style",value:function(){return"\n \n "}}]),e}(d.default.Component);e.default=c},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n .head{\n position:fixed;\n height:45px;\n line-height: 45px;\n border-bottom: 1px solid #eee;\n width:100%;\n background-color:#303030;\n z-index:100;\n\n }\n ul,li{\n display: inline-block;\n }\n .logo_box{\n width:100px;\n display: inline-block;\n text-align:center;\n line-height: 60px;\n }\n .menu a,.logo_box a{\n display: inline-block;\n height:45px;\n color:#ddd;\n }\n .menu{\n position: absolute;\n right:20px;\n }\n .menu li{\n margin-left:15px;\n }\n .logo_box a{\n font-size: 34px;\n font-weight: bold;\n color: #00bff3;\n padding: 0px 15px;\n line-height: 45px;\n cursor: pointer;\n }\n .menu a:hover{\n color: white;\n }\n\n .m_menu{\n position:fixed;\n display:none;\n }\n\n @media only screen and (max-width: 768px) {\n .menu li{\n display:none;\n }\n .menu .m_show{\n display:block;\n }\n\n .logo_box{\n display:inline-block;\n }\n\n .head{\n text-align:center;\n }\n\n .m_menu{\n\n top:0;\n left:0;\n display:block;\n width:50px;\n height:50px;\n padding-top: 6px;\n }\n .m_menu img{\n width:30px;\n }\n\n }\n \n "}},{key:"render",value:function(){return'\n
    \n \n
    \n Omi\n
    \n \n
    '}}]),e}(d.default.Component);e.default=m},function(n,e,r){var t,i,o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(){var a={},s=r(52),l=r(2),d=function(){},c=function(n,e,r){var t="on"+n.substring(0,1).toUpperCase()+n.substring(1),i=e.getAttribute(t);return null===i?d:r[i].bind(r)};a.init=function(){l.extendPlugin("omi-finger",function(n,e){e.alloyFinger&&e.alloyFinger.destroy();var r=new s(n,{touchStart:c("touchStart",n,e),touchMove:c("touchMove",n,e),touchEnd:c("touchEnd",n,e),touchCancel:c("touchCancel",n,e),multipointStart:c("multipointStart",n,e),multipointEnd:c("multipointEnd",n,e),tap:c("tap",n,e),doubleTap:c("doubleTap",n,e),longTap:c("longTap",n,e),singleTap:c("singleTap",n,e),rotate:c("rotate",n,e),pinch:c("pinch",n,e),pressMove:c("pressMove",n,e),swipe:c("swipe",n,e)});e.alloyFinger=r})},a.destroy=function(){delete l.plugins["omi-finger"]},"object"==o(e)?n.exports=a:(t=[],i=function(){return a}.apply(e,t),!(void 0!==i&&(n.exports=i)))}()},function(n,e,r){"use strict";var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(){function r(n){return Math.sqrt(n.x*n.x+n.y*n.y)}function i(n,e){return n.x*e.x+n.y*e.y}function o(n,e){var t=r(n)*r(e);if(0===t)return 0;var o=i(n,e)/t;return o>1&&(o=1),Math.acos(o)}function a(n,e){return n.x*e.y-e.x*n.y}function s(n,e){var r=o(n,e);return a(n,e)>0&&(r*=-1),180*r/Math.PI}function l(n,e){var r=new d(n);return r.add(e),r}var d=function(n){this.handlers=[],this.el=n};d.prototype.add=function(n){this.handlers.push(n)},d.prototype.del=function(n){n||(this.handlers=[]);for(var e=this.handlers.length;e>=0;e--)this.handlers[e]===n&&this.handlers.splice(e,1)},d.prototype.dispatch=function(){for(var n=0,e=this.handlers.length;n0&&this.delta<=250&&Math.abs(this.preTapPosition.x-this.x1)<30&&Math.abs(this.preTapPosition.y-this.y1)<30),this.preTapPosition.x=this.x1,this.preTapPosition.y=this.y1,this.last=this.now;var e=this.preV,t=n.touches.length;if(t>1){this._cancelLongTap(),this._cancelSingleTap();var i={x:n.touches[1].pageX-this.x1,y:n.touches[1].pageY-this.y1};e.x=i.x,e.y=i.y,this.pinchStartLen=r(e),this.multipointStart.dispatch(n)}this.longTapTimeout=setTimeout(function(){this.longTap.dispatch(n)}.bind(this),750)}},move:function(n){if(n.touches){var e=this.preV,t=n.touches.length,i=n.touches[0].pageX,o=n.touches[0].pageY;if(this.isDoubleTap=!1,t>1){var a={x:n.touches[1].pageX-i,y:n.touches[1].pageY-o};null!==e.x&&(this.pinchStartLen>0&&(n.scale=r(a)/this.pinchStartLen,this.pinch.dispatch(n)),n.angle=s(a,e),this.rotate.dispatch(n)),e.x=a.x,e.y=a.y}else null!==this.x2?(n.deltaX=i-this.x2,n.deltaY=o-this.y2):(n.deltaX=0,n.deltaY=0),this.pressMove.dispatch(n);this.touchMove.dispatch(n),this._cancelLongTap(),this.x2=i,this.y2=o,t>1&&n.preventDefault()}},end:function(n){if(n.changedTouches){this._cancelLongTap();var e=this;n.touches.length<2&&this.multipointEnd.dispatch(n),this.touchEnd.dispatch(n),this.x2&&Math.abs(this.x1-this.x2)>30||this.y2&&Math.abs(this.preV.y-this.y2)>30?(n.direction=this._swipeDirection(this.x1,this.x2,this.y1,this.y2),this.swipeTimeout=setTimeout(function(){e.swipe.dispatch(n)},0)):(this.tapTimeout=setTimeout(function(){e.tap.dispatch(n),e.isDoubleTap&&(e.doubleTap.dispatch(n),clearTimeout(e.singleTapTimeout),e.isDoubleTap=!1)},0),e.isDoubleTap||(e.singleTapTimeout=setTimeout(function(){e.singleTap.dispatch(n)},250))),this.preV.x=0,this.preV.y=0,this.scale=1,this.pinchStartLen=null,this.x1=this.x2=this.y1=this.y2=null}},cancel:function(n){clearTimeout(this.tapTimeout),clearTimeout(this.singleTapTimeout),clearTimeout(this.longTapTimeout),clearTimeout(this.swipeTimeout),this.touchCancel.dispatch(n)},_cancelLongTap:function(){clearTimeout(this.longTapTimeout)},_cancelSingleTap:function(){clearTimeout(this.singleTapTimeout)},_swipeDirection:function(n,e,r,t){return Math.abs(n-e)>=Math.abs(r-t)?n-e>0?"Left":"Right":r-t>0?"Up":"Down"},on:function(n,e){this[n]&&this[n].add(e)},off:function(n,e){this[n]&&this[n].del(e)},destroy:function(){return this.tapTimeout&&clearTimeout(this.tapTimeout),this.singleTapTimeout&&clearTimeout(this.singleTapTimeout),this.longTapTimeout&&clearTimeout(this.longTapTimeout),this.swipeTimeout&&clearTimeout(this.swipeTimeout),this.element.removeEventListener("touchstart",this.start),this.element.removeEventListener("touchmove",this.move),this.element.removeEventListener("touchend",this.end),this.element.removeEventListener("touchcancel",this.cancel),this.rotate.del(),this.touchStart.del(),this.multipointStart.del(),this.multipointEnd.del(),this.pinch.del(),this.swipe.del(),this.tap.del(),this.doubleTap.del(),this.longTap.del(),this.singleTap.del(),this.pressMove.del(),this.touchMove.del(),this.touchEnd.del(),this.touchCancel.del(),this.preV=this.pinchStartLen=this.scale=this.isDoubleTap=this.delta=this.last=this.now=this.tapTimeout=this.singleTapTimeout=this.longTapTimeout=this.swipeTimeout=this.x1=this.x2=this.y1=this.y2=this.preTapPosition=this.rotate=this.touchStart=this.multipointStart=this.multipointEnd=this.pinch=this.swipe=this.tap=this.doubleTap=this.longTap=this.singleTap=this.pressMove=this.touchMove=this.touchEnd=this.touchCancel=null,null}},"undefined"!=typeof n&&"object"===t(e)?n.exports=c:window.AlloyFinger=c}()},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n {{#preName}} ←{{preName}}{{/preName}}\n {{#nextName}} {{/nextName}}\n ':'\n
    \n {{#preName}} ←{{preName}}{{/preName}}\n {{#nextName}} {{/nextName}}\n
    '}},{key:"style",value:function(){return"\n \n "}}]),e}(d.default.Component);e.default=h}]); \ No newline at end of file +!function(r,s){"object"===a(e)&&e&&"string"!=typeof e.nodeName?s(e):(i=[e],t=s,o="function"==typeof t?t.apply(e,i):t,!(void 0!==o&&(n.exports=o)))}(void 0,function(n){function e(n){return"function"==typeof n}function r(n){return g(n)?"array":"undefined"==typeof n?"undefined":a(n)}function t(n){return n.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function i(n,e){return null!=n&&"object"===("undefined"==typeof n?"undefined":a(n))&&e in n}function o(n,e){return v.call(n,e)}function s(n){return!o(b,n)}function l(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return y[n]})}function d(e,r){function i(){if(v&&!b)for(;f.length;)delete h[f.pop()];else f=[];v=!1,b=!1}function o(n){if("string"==typeof n&&(n=n.split(w,2)),!g(n)||2!==n.length)throw new Error("Invalid tags: "+n);a=new RegExp(t(n[0])+"\\s*"),l=new RegExp("\\s*"+t(n[1])),d=new RegExp("\\s*"+t("}"+n[1]))}if(!e)return[];var a,l,d,p=[],h=[],f=[],v=!1,b=!1;o(r||n.tags);for(var y,k,j,C,S,M,H=new m(e);!H.eos();){if(y=H.pos,j=H.scanUntil(a))for(var L=0,D=j.length;L0?o[o.length-1][4]:t;break;default:i.push(e)}return t}function m(n){this.string=n,this.tail=n,this.pos=0}function p(n,e){this.view=n,this.cache={".":this.view},this.parent=e}function h(){this.cache={}}var f=Object.prototype.toString,g=Array.isArray||function(n){return"[object Array]"===f.call(n)},v=RegExp.prototype.test,b=/\S/,y={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="},x=/\s*/,w=/\s+/,O=/\s*=/,_=/\s*\}/,T=/#|\^|\/|>|\{|&|=|!/;m.prototype.eos=function(){return""===this.tail},m.prototype.scan=function(n){var e=this.tail.match(n);if(!e||0!==e.index)return"";var r=e[0];return this.tail=this.tail.substring(r.length),this.pos+=r.length,r},m.prototype.scanUntil=function(n){var e,r=this.tail.search(n);switch(r){case-1:e=this.tail,this.tail="";break;case 0:e="";break;default:e=this.tail.substring(0,r),this.tail=this.tail.substring(r)}return this.pos+=e.length,e},p.prototype.push=function(n){return new p(n,this)},p.prototype.lookup=function(n){var r,t=this.cache;if(t.hasOwnProperty(n))r=t[n];else{for(var o,a,s=this,l=!1;s;){if(n.indexOf(".")>0)for(r=s.view,o=n.split("."),a=0;null!=r&&a"===o?a=this.renderPartial(i,e,r,t):"&"===o?a=this.unescapedValue(i,e):"name"===o?a=this.escapedValue(i,e):"text"===o&&(a=this.rawValue(i)),void 0!==a&&(s+=a);return s},h.prototype.renderSection=function(n,r,t,i){function o(n){return s.render(n,r,t)}var s=this,l="",d=r.lookup(n[1]);if(d){if(g(d))for(var c=0,u=d.length;c",this.HTML):(this._mergeData(n),this._generateHTMLCSS(),this._extractChildren(this),e&&this.children.forEach(function(n,e){r._omi_order[e]=e}),this.children.forEach(function(n,e){r.HTML=r.HTML.replace(n._omiChildStr,r.children[r._omi_order[e]].HTML)}),this.HTML=(0,u.default)(this.HTML,this.id),this.HTML)}},{key:"_queryElements",value:function(n){n._mixRefs(),n._execPlugins(),n.children.forEach(function(e){e.node=n.node.querySelector("["+s.default.STYLESCOPEDPREFIX+e.id+"]"),n._queryElements(e)})}},{key:"_mixRefs",value:function(){var n=this,e=s.default.$$("*[ref]",this.node);e.forEach(function(e){e.hasAttribute(n._omi_scoped_attr)&&(n.refs[e.getAttribute("ref")]=e)});var r=this.node.getAttribute("ref");r&&(this.refs[r]=this.node)}},{key:"_execPlugins",value:function(){var n=this;Object.keys(s.default.plugins).forEach(function(e){var r=s.default.$$("*["+e+"]",n.node);r.forEach(function(r){r.hasAttribute(n._omi_scoped_attr)&&s.default.plugins[e](r,n)}),n.node.hasAttribute(e)&&s.default.plugins[e](n.node,n)})}},{key:"_childrenInstalled",value:function(n){var e=this;n.children.forEach(function(n){e._childrenInstalled(n),n.installed()})}},{key:"_fixForm",value:function(){s.default.$$("input",this.node).forEach(function(n){var e=n.type.toLowerCase();""===n.getAttribute("value")&&(n.value=""),"checked"!==e&&"radio"!==e||(n.hasAttribute("checked")?n.checked="checked":n.checked=!1)}),s.default.$$("textarea",this.node).forEach(function(n){n.value=n.getAttribute("value")}),s.default.$$("select",this.node).forEach(function(n){var e=n.getAttribute("value");if(e)s.default.$$("option",n).forEach(function(n){e===n.getAttribute("value")&&n.setAttribute("selected","selected")});else{var r=s.default.$$("option",n)[0];r&&r.setAttribute("selected","selected")}})}},{key:"_replaceTags",value:function(n,e){var r=n.join("|"),t=new RegExp("<("+r+"+)((?:\\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\\s*=\\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>\\s]+))?)*)\\s*(\\/?)>","g");return e.replace(t,function(n,e){var r=n.length-2;return r>=0&&n.lastIndexOf("/>")===n.length-2?n.replace("<"+e,'":n.lastIndexOf(">")===n.length-1?n.replace("<"+e,'":void 0})}},{key:"_createHiddenNode",value:function(){var n=document.createElement("input");return n.setAttribute("type","hidden"),n.setAttribute(this._omi_scoped_attr,""),n}},{key:"_mergeData",value:function(n){this.dataFirst?this.data=Object.assign({},this._getDataset(n),this.data):this.data=Object.assign({},this.data,this._getDataset(n))}},{key:"_generateHTMLCSS",value:function(){this.CSS=(this.style()||"").replace(/<\/?style>/g,""),this.CSS&&(this.CSS=d.default.scoper(this.CSS,"["+this._omi_scoped_attr+"]"),this.CSS===this._preCSS||this._omi_server_rendering||(d.default.addStyle(this.CSS,this.id),this._preCSS=this.CSS));var n=this.render();this.HTML=this._scopedAttr(s.default.template(n?n:"",this.data),this._omi_scoped_attr).trim(),this._omi_server_rendering&&(this.HTML='\r\n\r\n"+this.HTML,this.HTML+='\r\n\r\n")}},{key:"_scopedAttr",value:function(n,e){return n.replace(/<[^\/]([A-Za-z]*)[^>]*>/g,function(n){var r=n.split(" ")[0].replace(">","");return n.replace(r,r+" "+e)})}},{key:"_getDataset",value:function(n){var e=this,r=(0,f.default)(n),t=r.child[0].attr;return Object.keys(t).forEach(function(n){0===n.indexOf("data-")&&(e._dataset[e._capitalize(n.replace("data-",""))]=t[n])}),this._dataset}},{key:"_capitalize",value:function(n){return n=n.toLowerCase(),n=n.replace(/\b\w+\b/g,function(n){return n.substring(0,1).toUpperCase()+n.substring(1)}).replace(/-/g,""),n.substring(0,1).toLowerCase()+n.substring(1)}},{key:"_extractPropertyFromString",value:function(n,e){var r=n.replace(/['|"|\]]/g,"").replace(/\[/g,".").split("."),t=e;return r.forEach(function(n){t=t[n]}),r=null,t}},{key:"_extractChildren",value:function(n){var e=this;s.default.customTags.length>0&&(n.HTML=this._replaceTags(s.default.customTags,n.HTML));var r=n.HTML.match(/][\s\S]*?tag=['|"](\S*)['|"][\s\S]*?><\/child>/g);r&&r.forEach(function(r,t){var i=(0,f.default)(r),o=i.child[0].attr,a=o.tag;delete o.tag;var l=e.children[t];l&&l.___omi_constructor_name===a?l._childRender(r):!function(){var i={},d={},c={},u={},m=null,p=null;Object.keys(o).forEach(function(r){var t=o[r];if(0===r.indexOf("on")){var a=n[t];a&&(i[r]=a.bind(n))}else"omi-id"===r?m=t:"name"===r?p=t:"group-data"===r?(n._omiGroupDataCounter.hasOwnProperty(t)?n._omiGroupDataCounter[t]++:n._omiGroupDataCounter[t]=0,u=e._extractPropertyFromString(t,n)[n._omiGroupDataCounter[t]]):0===r.indexOf("data-")?d[e._capitalize(r.replace("data-",""))]=t:"data"===r&&(c=e._extractPropertyFromString(t,n))});var h=s.default.getClassFromString(a);if(!h)throw"Can't find Class called ["+a+"]";var f=new h(Object.assign(i,n.childrenData[t],d,c,u),!1);f._omiChildStr=r,f.parent=n,f.___omi_constructor_name=a,f._dataset={},f.install(),m&&(s.default.mapping[m]=f),p&&(n[p]=f),l?n.children[t]=f:n.children.push(f),f._childRender(r,!0)}()})}}]),n}();e.default=g},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){var r=new RegExp("([^\r\n,{}]+)(,(?=[^}]*{)|s*{)","g");return n=n.replace(r,function(n,r,t){return r.match(/^\s*(@media|@keyframes|to|from|@font-face)/)?r+t:(r.match(/:scope/)&&(r=r.replace(/([^\s]*):scope/,function(n,e){return""===e?"> *":"> "+e})),r=r.replace(/^(\s*)/,r.trim()+e+",$1"+e+" ").replace(/\s+/g," "),r+t)})}function o(n,e){var r=document.getElementById(s.default.STYLEPREFIX+e),t=document.getElementsByTagName("head")[0];r&&r.parentNode===t&&t.removeChild(r);var i=document.createElement("style");t.appendChild(i),i.setAttribute("type","text/css"),i.setAttribute("id",s.default.STYLEPREFIX+e),window.ActiveXObject?i.styleSheet.cssText=n:i.textContent=n}Object.defineProperty(e,"__esModule",{value:!0});var a=r(3),s=t(a);e.default={scoper:i,addStyle:o}},function(n,e){"use strict";function r(n,e,r){return n.split(e).map(function(n){return n.replace(new RegExp(r,"g"),e)}).join(r)}function t(n){return JSON.stringify(n).replace(/(^"|"$)/g,"")}function i(n){return n=r(n,"'",'"'),r(t(n),"'",'"')}function o(n){return n.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function a(n,e){return String.prototype.endsWith?String.prototype.endsWith.call(n,e):n.substr(n.length-1,1)===e}function s(n,e){return n.replace(/<[\s\S]*?[^=]>/g,function(n){return n.replace(/on(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave|Abort|Blur|Cancel|CanPlay|CanPlayThrough|Change|Click|Close|ContextMenu|CueChange|DblClick|Drag|DragEnd|DragEnter|DragLeave|DragOver|DragStart|Drop|DurationChange|Emptied|Ended|Error|Focus|Input|Invalid|KeyDown|KeyPress|KeyUp|Load|LoadedData|LoadedMetadata|LoadStart|MouseDown|MouseEnter|MouseLeave|MouseMove|MouseOut|MouseOver|MouseUp|MouseWheel|Pause|Play|Playing|Progress|RateChange|Reset|Resize|Scroll|Seeked|Seeking|Select|Show|Stalled|Submit|Suspend|TimeUpdate|Toggle|VolumeChange|Waiting|AutoComplete|AutoCompleteError|BeforeCopy|BeforeCut|BeforePaste|Copy|Cut|Paste|Search|SelectStart|Wheel|WebkitFullScreenChange|WebkitFullScreenError|TouchStart|TouchMove|TouchEnd|TouchCancel|PointerDown|PointerUp|PointerCancel|PointerMove|PointerOver|PointerOut|PointerEnter|PointerLeave)=('|"|{)([\s\S]*)('|"|})/g,function(n,r,t,s,l){if(0===s.indexOf("Omi.instances[")||0===s.indexOf("new Function("))return n;if("{"===t){var d="("+s+").bind(Omi.instances["+e+"])(event)",c="on"+r+"=\"new Function('event', '"+o(i(d))+"')(event)\"";return c.split("\n").map(function(n){return a(n,";")?n:n+";"}).join("")}return s.match(/.*?\(.*?\)/)?n.replace(/=(['|"])/,"=$1Omi.instances["+e+"]."):n})})}Object.defineProperty(e,"__esModule",{value:!0}),e.default=s},function(n,e,r){var t,i,o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(a,s){"object"===o(e)&&"undefined"!=typeof n?n.exports=s():(t=s,i="function"==typeof t?t.call(e,r,e,n):t,!(void 0!==i&&(n.exports=i)))}(void 0,function(){"use strict";function n(n){!d&&m.createRange&&(d=m.createRange(),d.selectNode(m.body));var e;return d&&d.createContextualFragment?e=d.createContextualFragment(n):(e=m.createElement("body"),e.innerHTML=n),e.childNodes[0]}function e(n,e){var r=n.nodeName,t=e.nodeName;return r===t||!!(e.actualize&&r.charCodeAt(0)<91&&t.charCodeAt(0)>90)&&r===t.toUpperCase()}function r(n,e){return e&&e!==u?m.createElementNS(e,n):m.createElement(n)}function t(n,e){for(var r=n.firstChild;r;){var t=r.nextSibling;e.appendChild(r),r=t}return e}function i(n,e){var r,t,i,o,a,s,l=e.attributes;for(r=l.length-1;r>=0;--r)t=l[r],i=t.name,o=t.namespaceURI,a=t.value,o?(i=t.localName||i,s=n.getAttributeNS(o,i),s!==a&&n.setAttributeNS(o,i,a)):(s=n.getAttribute(i),s!==a&&n.setAttribute(i,a));for(l=n.attributes,r=l.length-1;r>=0;--r)t=l[r],t.specified!==!1&&(i=t.name,o=t.namespaceURI,o?(i=t.localName||i,h(e,o,i)||n.removeAttributeNS(o,i)):h(e,null,i)||n.removeAttribute(i))}function o(n,e,r){n[r]!==e[r]&&(n[r]=e[r],n[r]?n.setAttribute(r,""):n.removeAttribute(r,""))}function a(){}function s(n){return n.id}function l(i){return function(o,l,d){function c(n){O?O.push(n):O=[n]}function u(n,e){if(n.nodeType===g)for(var r=n.firstChild;r;){var t=void 0;e&&(t=_(r))?c(t):(M(r),r.firstChild&&u(r,e)),r=r.nextSibling}}function p(n,e,r){S(n)!==!1&&(e&&e.removeChild(n),M(n),u(n,r))}function h(n){if(n.nodeType===g)for(var e=n.firstChild;e;){var r=_(e);r&&(D[r]=e),h(e),e=e.nextSibling}}function y(n){k(n);for(var r=n.firstChild;r;){var t=r.nextSibling,i=_(r);if(i){var o=D[i];o&&e(r,o)&&(r.parentNode.replaceChild(o,r),x(o,r))}y(r),r=t}}function x(n,r,t){var a,s=_(r);if(s&&delete D[s],!l.isSameNode||!l.isSameNode(o)){if(!t){if(j(n,r)===!1)return;if(i(n,r),C(n),H(n,r)===!1)return}if("TEXTAREA"!==n.nodeName){var d,u,h,w,O=r.firstChild,k=n.firstChild;n:for(;O;){for(h=O.nextSibling,d=_(O);k;){if(u=k.nextSibling,O.isSameNode&&O.isSameNode(k)){O=h,k=u;continue n}a=_(k);var S=k.nodeType,M=void 0;if(S===O.nodeType&&(S===g?(d?d!==a&&((w=D[d])?k.nextSibling===w?M=!1:(n.insertBefore(w,k),u=k.nextSibling,a?c(a):p(k,n,!0),k=w):M=!1):a&&(M=!1),M=M!==!1&&e(k,O),M&&x(k,O)):S!==v&&S!=b||(M=!0,k.nodeValue=O.nodeValue)),M){O=h,k=u;continue n}a?c(a):p(k,n,!0),k=u}if(d&&(w=D[d])&&e(w,O))n.appendChild(w),x(w,O);else{var L=T(O);L!==!1&&(L&&(O=L),O.actualize&&(O=O.actualize(n.ownerDocument||m)),n.appendChild(O),y(O))}O=h,k=u}for(;k;)u=k.nextSibling,(a=_(k))?c(a):p(k,n,!0),k=u}var A=f[n.nodeName];A&&A(n,r)}}if(d||(d={}),"string"==typeof l)if("#document"===o.nodeName||"HTML"===o.nodeName){var w=l;l=m.createElement("html"),l.innerHTML=w}else l=n(l);var O,_=d.getNodeKey||s,T=d.onBeforeNodeAdded||a,k=d.onNodeAdded||a,j=d.onBeforeElUpdated||a,C=d.onElUpdated||a,S=d.onBeforeNodeDiscarded||a,M=d.onNodeDiscarded||a,H=d.onBeforeElChildrenUpdated||a,L=d.childrenOnly===!0,D={};h(o);var A=o,E=A.nodeType,P=l.nodeType;if(!L)if(E===g)P===g?e(o,l)||(M(o),A=t(o,r(l.nodeName,l.namespaceURI))):A=l;else if(E===v||E===b){if(P===E)return A.nodeValue=l.nodeValue,A;A=l}if(A===l)M(o);else if(x(A,l,L),O)for(var I=0,X=O.length;I\s]+))?)*)\s*(\/?)>/,t=/^<\/([-A-Za-z0-9_]+)[^>]*>/,i=/([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g,o=function(n,e){function o(n,r,t,o){if(r=r.toLowerCase(),o=!!o,o||c.push(r),e.start){var a=[];t.replace(i,function(n,e){var r=arguments[2]?arguments[2]:arguments[3]?arguments[3]:arguments[4]?arguments[4]:"";a.push({name:e,value:r,escaped:r.replace(/(^|[^\\])"/g,'$1\\"')})}),e.start&&e.start(r,a,o)}}function a(n,r){if(r)for(var t=c.length-1;t>=0&&c[t]!=r;t--);else var t=0;if(t>=0){for(var i=c.length-1;i>=t;i--)e.end&&e.end(c[i]);c.length=t}}var s,l,d,c=[],u=n;for(c.last=function(){return this[this.length-1]};n;){if(l=!0,c.last())n=n.replace(new RegExp("([\\s\\S]*?)]*>"),function(n,r){return e.chars&&e.chars(r),""}),a("",c.last());else if(0==n.indexOf(">>0,i=0;if(2==arguments.length)e=arguments[1];else{for(;i=t)throw new TypeError("Reduce of empty array with no initial value");e=r[i++]}for(;i640){var o=document.querySelectorAll("pre"),a=this.getHighLight();if(a){for(var s in a)o[s]&&o[s].setAttribute("data-line",a[s]);n||lineHighLight()}}}},{key:"getHighLight",value:function(){var n=this,e=null;return m.default.menus[this.data.lan].forEach(function(r){r.list.forEach(function(r){r.md===n.data.name&&(e=r.highlight)})}),e}},{key:"installed",value:function(){}},{key:"render",value:function(){return this.data.html=marked(s(this.data.name,this.data.lan)),'\n
    \n {{{html}}}\n
    \n '}},{key:"style",value:function(){return"\n \n "}}]),e}(c.default.Component);e.default=p},function(n,e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r={isMobile:!1,mds:{cn:["installation","hello_world","components","communication","lifecycle","events","condition","loop","form","inherit","template","get_dom","plugin","thinking_in_omi","pr_env","pr_hello"],en:["installation","hello_world","components","communication","lifecycle","events","condition","loop","form","inherit","template","get_dom","plugin"]},menus:{cn:[{active:!0,title:"快速开始",currentIndex:0,list:[{name:"安装",md:"installation"},{name:"Hello World",md:"hello_world",highlight:{2:"6",5:"4,6"}},{name:"组件",md:"components",highlight:{2:"3,9,34"}},{name:"组件通讯",md:"communication",highlight:{0:"34",1:"5,11"}},{name:"生命周期",md:"lifecycle"},{name:"事件处理",md:"events"},{name:"条件判断",md:"condition"},{name:"循环遍历",md:"loop",highlight:{1:"9-11"}},{name:"表单",md:"form"},{name:"继承",md:"inherit"},{name:"模板切换",md:"template"},{name:"获取DOM节点",md:"get_dom"},{name:"插件体系",md:"plugin"},{name:"Omi的理念",md:"thinking_in_omi"}]}],en:[{title:"QUICK START",currentIndex:0,list:[{name:"Installation",md:"installation"},{name:"Hello World",md:"hello_world"},{name:"Components",md:"components"},{name:"Communication",md:"communication"},{name:"Lifecycle",md:"lifecycle"},{name:"Handling Events",md:"events"},{name:"Conditional Rendering",md:"condition"},{name:"Loop",md:"loop"},{name:"Forms",md:"form"},{name:"Inheritance",md:"inherit"},{name:"Templates",md:"template"},{name:"Get DOM",md:"get_dom"},{name:"Plugin",md:"plugin"},{name:"Thinking in Omi",md:"thinking_in_omi"}]}]}},t={versions:function(){var n=navigator.userAgent;navigator.appVersion;return{trident:n.indexOf("Trident")>-1,presto:n.indexOf("Presto")>-1,webKit:n.indexOf("AppleWebKit")>-1,gecko:n.indexOf("Gecko")>-1&&n.indexOf("KHTML")==-1,mobile:!!n.match(/AppleWebKit.*Mobile.*/),ios:!!n.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/),android:n.indexOf("Android")>-1||n.indexOf("Linux")>-1,iPhone:n.indexOf("iPhone")>-1,iPad:n.indexOf("iPad")>-1,webApp:n.indexOf("Safari")==-1}}(),language:(navigator.browserLanguage||navigator.language).toLowerCase()};(t.versions.mobile||t.versions.ios||t.versions.android||t.versions.iPhone||t.versions.iPad)&&(r.isMobile=!0),e.default=r},function(n,e,r){function t(n){return r(i(n))}function i(n){return o[n]||function(){throw new Error("Cannot find module '"+n+"'.")}()}var o={"./README.md":13,"./cn_communication.md":14,"./cn_components.md":15,"./cn_condition.md":16,"./cn_events.md":17,"./cn_form.md":18,"./cn_get_dom.md":19,"./cn_hello_world.md":20,"./cn_inherit.md":21,"./cn_installation.md":22,"./cn_lifecycle.md":23,"./cn_loop.md":24,"./cn_plugin.md":25,"./cn_pr_nearby.md":26,"./cn_template.md":27,"./cn_thinking_in_omi.md":28,"./deep_in/README.md":29,"./deep_in/cn_env.md":30,"./deep_in/cn_hello.md":31,"./deep_in/cn_nearby.md":32,"./deep_in/cn_omi-cli.md":33,"./en_communication.md":34,"./en_components.md":35,"./en_condition.md":36,"./en_events.md":37,"./en_form.md":38,"./en_get_dom.md":39,"./en_hello_world.md":40,"./en_inherit.md":41,"./en_installation.md":42,"./en_lifecycle.md":43,"./en_loop.md":44,"./en_plugin.md":45,"./en_template.md":46,"./en_thinking_in_omi.md":47};t.keys=function(){return Object.keys(o)},t.resolve=i,n.exports=t,t.id=12; +},function(n,e){n.exports='module.exports = "## [Docs Website](https://alloyteam.github.io/omi/website/docs.html)\\r\\n\\r\\n### Usage\\r\\n* [安装](./cn_installation.md)\\r\\n* [Hello World](./cn_hello_world.md)\\r\\n* [组件](./cn_components.md)\\r\\n* [组件通讯](./cn_communication.md)\\r\\n* [生命周期](./cn_lifecycle.md)\\r\\n* [事件处理](./cn_events.md)\\r\\n* [条件判断](./cn_condition.md)\\r\\n* [循环遍历](./cn_loop.md)\\r\\n* [表单](./cn_form.md)\\r\\n* [继承](./cn_inherit.md)\\r\\n* [模板切换](./cn_template.md)\\r\\n* [获取DOM节点](./cn_get_dom.md)\\r\\n* [插件体系](./cn_plugin.md)\\r\\n* [Omi理念](./cn_thinking_in_omi.md)\\r\\n\\r\\n### Usage(en-us)\\r\\n* [installation](./en_installation.md)\\r\\n* [Hello World](./en_hello_world.md)\\r\\n* [components](./en_components.md)\\r\\n* [communication](./en_communication.md)\\r\\n* [lifecycle](./en_lifecycle.md)\\r\\n* [events](./en_events.md)\\r\\n* [condition](./en_condition.md)\\r\\n* [loop](./en_loop.md)\\r\\n* [form](./en_form.md)\\r\\n* [inherit](./en_inherit.md)\\r\\n* [template](./en_template.md)\\r\\n\\r\\n"'},function(n,e){n.exports='module.exports = "

    组件通讯

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)组建间的通讯非常遍历灵活,因为有许多可选方案进行通讯:\\r\\n\\r\\n* 通过在组件上声明 data-* 传递给子节点 \\r\\n* 通过在组件上声明 data 传递给子节点 (支持复杂数据类型的映射)\\r\\n* 父容器设置 childrenData 自动传递给子节点\\r\\n* 声明 group-data 传递(支持复杂数据类型的映射)\\r\\n* 完全面向对象,可以非常容易地拿到对象的实例,之后可以设置实例属性和调用实例的方法\\r\\n\\r\\n所以通讯变得畅通无阻,下面一一来举例说明。\\r\\n\\r\\n### data-*通讯 \\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n \\tcursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n一般data-*用来传递值类型,如string、number。值得注意的是,通过data-*接收到的数据类型都是string,需要自行转成number类型。\\r\\n通常情况下,data-*能满足我们的要求,但是遇到复杂的数据类型是没有办法通过大量data-*去表达,所以可以通过data通讯,请往下看。\\r\\n\\r\\n### data通讯 \\r\\n\\r\\n如上面代码所示,通过 data-name=\\"Omi\\"可以把name传递给子组件。下面的代码也可以达到同样的效果。\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.helloData = { name : \'Omi\' };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n使用data声明,会去组件的instance(也就是this)下找对应的属性,this下可以挂载任意复杂的对象。所以这也就突破了data-*的局限性。\\r\\n\\r\\n如果instance下面的某个属性下面的某个属性下面的某个数组的第一个元素的某个属性要作为data传递Hello怎么办?\\r\\n没关系,data声明是支持复杂类型的,使用方式如下:\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n点击这里→data映射复杂数据\\r\\n\\r\\n### childrenData通讯\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.childrenData = [{ name : \'Omi\' } , { name : \'dntzhang\' }];\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n使用this.childrenData传递data给子组件,childrenData是一个数组类型,所以支持同时给多个组件传递data,与render里面的组件会一一对应上。\\r\\n\\r\\n### group-data通讯\\r\\n\\r\\nchildrenData的方式可以批量传递数据给组件,但是有很多场景下data的来源不一定非要都从childrenData来,childrenData是个数组,会和组件的顺序一一对应,这就给不同传递方式的data必须全部集中的childrenData中,非常不方便。group-data专门为解决上面的痛点而生,专门是为了给一组组件批量传递data。\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.testData = [{name: \'Omi\'}, {name: \'dntzhang\'}, {name: \'AlloyTeam\'}];\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n只需要在声明的子组件上标记group-data,就会去当前组件的instance(也就是this)下面找对应的属性,然后根据当前的位置,和对应数组的位置会一一对应起来。\\r\\n\\r\\n运行结果如下:\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170216110701535-1698390390.png)\\r\\n\\r\\n点击这里→group-data\\r\\n\\r\\n同样group-data支持复杂数据类型的映射,需要注意的是,group-data映射的终点必须是一个数组:\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n点击这里→group-data映射复杂数据\\r\\n\\r\\n### 通过对象实例\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n this.hello.data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n### 通过omi-id\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n Omi.get(\\"hello\\").data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n通过在组件上声明omi-id,在程序任何地方拿到该对象的实例。这个可以算是跨任意组件通讯神器。\\r\\n\\r\\n### 特别强调\\r\\n\\r\\n* 通过childrenData或者data方式通讯都是一锤子买卖。后续变更只能通过组件实例下的data属性去更新组件\\r\\n* 通过data-✼通讯也是一锤子买卖。后续变更只能通过组件实例下的data属性去更新组件。\\r\\n* 关于data-✼通讯也可以不是一锤子买卖,但是要设置组件实例的dataFirst为false,这样的话data-✼就会覆盖组件实例的data对应的属性\\r\\n\\r\\n关于上面的第三条也就是这样的逻辑伪代码:\\r\\n```js\\r\\nif(this.dataFirst){\\r\\n this.data = Object.assign({},data-✼ ,this.data);\\r\\n}else{\\r\\n this.data = Object.assign({},this.data, data-✼);\\r\\n}\\r\\n```"'},function(n,e){n.exports='module.exports = "

    组件

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)完全基于组件体系设计,我们希望开发者可以像搭积木一样制作Web程序,一切皆是组件,组件也可以嵌套子组件形成新的组件,新的组件又可以当作子组件嵌套至任意组件形成新的组件...\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170210093427338-1536910080.png)\\r\\n\\r\\n## 简单组件\\r\\n\\r\\n这里使用Todo的例子来讲解Omi组件体系的使用。\\r\\n\\r\\n```js\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.data.items.push(this.data.text);\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n
      {{#items}}
    • {{.}}
    • {{/items}}
    \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Todo({ items: [] ,text : \'\' }),\\"body\\");\\r\\n```\\r\\n\\r\\n组件生成的HTML最终会插入到body中。上面的例子展示了Omi的部分特性:\\r\\n\\r\\n- data传递: new Todo(data,..)的data可以直接提供给render方法里的模板\\r\\n- 局部CSS: h3只对render里的h3生效,不会污染外面的h3;button也是同样的\\r\\n- 声明式事件绑定: onchange调用的就是组件内的handleChange,this可以拿到当然的DOM元素,还可以拿到当前的event\\r\\n- 需要手动调用update方法才能更新组件\\r\\n\\r\\n这里需要特别强调的是,为了更加的自由和灵活度。Omi没有内置数据变更的自动更新,需要开发者自己调用update方法。\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n## 组件嵌套\\r\\n\\r\\n如果页面超级简单的话,可以没有组件嵌套。但是绝大部分Web网页或者Web应用,需要嵌套定义的组件来完成所有的功能和展示。比如上面的Todo,我们也是可以抽取出List。\\r\\n这样让程序易维护、可扩展、方便复用。如,我们抽取出List:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
      {{#items}}
    • {{.}}
    • {{/items}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n怎么使用这个List?我们需要使用Omi.makeHTML把List制作成可以声明式的标签,在render方法中就能直接使用该标签。如下所示:\\r\\n\\r\\n```js\\r\\nimport List from \'./list.js\';\\r\\n\\r\\nOmi.makeHTML(\'List\', List);\\r\\n\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.data.length = this.data.items.length;\\r\\n this.listData = { items : this.data.items };\\r\\n }\\r\\n\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.list.data.items.push(this.data.text);\\r\\n this.data.length = this.list.data.items.length;\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n* 第3行,通过makeHTML方法把组件制作成可以在render中使用的标签。当然Omi.makeHTML(\'List\', List);也可以写在List组件的代码下面。\\r\\n* 第9行,在父组件上定义listData属性用来传递给子组件。\\r\\n* 第34行,在render方法中使用List组件。其中name方法可以让你在代码里通过this快速方法到该组件的实例。data=\\"listData\\"可以让你把this.listData传递给子组件。\\r\\n\\r\\n需要注意的是,父组件的this.listData会被通过Object.assign浅拷贝到子组件。\\r\\n这样做的目的主要是希望以后DOM的变更都尽量修改子组件自身的data,然后再调用其update方法,而不是去更改父组件的listData。\\r\\n\\r\\n关于Omi组件通讯其实有4种方案,这个后续教程会专门来讲。\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports="module.exports = \"

    条件判断

    \\r\\n\\r\\n我们经常需要根据不同的状态呈现不同的界面,比如有的用户是vip要显示vip的Logo。Omi有许多种方式满足你的要求。\\r\\n\\r\\n### 方式一\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `{{#isVip}}\\r\\n
    you are VIP.
    \\r\\n {{/isVip}}\\r\\n {{^isVip}}\\r\\n
    you are not VIP.
    \\r\\n {{/isVip}}`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n上面完全使用mustachejs的条件判断的语法。当然Omi不强制你使用mustachejs。你可以是omi.lite.js,然后重写Omi.template方法去使用任意你喜爱的模板引擎。\\r\\n\\r\\n### 方式二\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nrender就是提供了很好的可编程性,里面可以写任意js逻辑代码。对了,差点忘了,style方法里面也可以写js逻辑的。\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style (){\\r\\n if(this.data.isVip){\\r\\n return 'div{ color : red; }';\\r\\n }else{\\r\\n return 'div{ color : green; }';\\r\\n }\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 方式三\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n ${this.data.isVip\\r\\n ?\\\"
    you are VIP.
    \\\"\\r\\n :\\\"
    you are not VIP.
    \\\"\\r\\n \\t\\t}\\r\\n `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n当然可以使用${ }里面写javascript代码进行输出。\""},function(n,e){n.exports='module.exports = "

    事件处理

    \\r\\n\\r\\nOmi的事件分内置事件和自定义事件。在内置事件处理方面巧妙地利用了浏览器自身的管线机制,可以通过event和this轻松拿到事件实例和触发该事件的元素。\\r\\n\\r\\n### 内置事件\\r\\n\\r\\n什么算内置事件?只要下面正则能匹配到就算内置事件。\\r\\n\\r\\n```js\\r\\non(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave)\\r\\n```\\r\\n\\r\\n内置事件怎么绑定?如下所示:\\r\\n\\r\\n```js\\r\\nclass EventTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n handleClick(dom, evt){\\r\\n alert(dom.innerHTML);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Hello, Omi!
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 自定义事件\\r\\n\\r\\n开发者自己定义的组件的事件,称为自定义事件,自定义事件必须以on开头,即onXXXX的格式,不然Omi识别不到。这里拿分页作为例子:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\nimport Pagination from \'./pagination.js\';\\r\\nimport Content from \'./content.js\';\\r\\n\\r\\nOmi.makeHTML(\'Pagination\', Pagination);\\r\\nOmi.makeHTML(\'Content\', Content);\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.content.goto(this.pagination.data.currentPage+1);\\r\\n }\\r\\n handlePageChange(index){\\r\\n this.content.goto(index+1);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    Pagination Example

    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render( new Main(),\'body\');\\r\\n```\\r\\n\\r\\n如上面的onPageChange就是自定义事件,触发会执行handlePageChange。onPageChange方法是在Pagination中执行:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\n\\r\\nclass Pagination extends Omi.Component {\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n linkTo: \\"#\\",\\r\\n prevText: \\"Prev\\",\\r\\n nextText: \\"Next\\",\\r\\n ellipseText: \\"...\\",\\r\\n prevShow: true,\\r\\n nextShow: true,\\r\\n onPageChange: function () { return false; }\\r\\n }, this.data);\\r\\n\\r\\n this.pageNum = Math.ceil(this.data.total / this.data.pageSize);\\r\\n }\\r\\n goto (index,evt) {\\r\\n evt.preventDefault();\\r\\n this.data.currentPage=index;\\r\\n this.update();\\r\\n this.data.onPageChange(index);\\r\\n }\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\n这里取了Pagination组件的部分代码。高亮的就是执行onPageChange的地方。\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/pagination/)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/pagination)\\r\\n"'},function(n,e){n.exports='module.exports = "

    表单

    \\r\\n\\r\\nOmi让一些表单操控起来更加方便,特别是select!\\r\\n\\r\\n### select标签\\r\\n\\r\\n以前,我们需要像如下的方式选中一个选项:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n第三个option由于加上了selected,所有会被选中。这样带来的问题就是,开发者写的程序可能要操遍历每个option。而使用Omi,你只需要这样子:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n这样就能达到同样的效果。比如你想选择第一项:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n是不是非常方便?\\r\\n\\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass FormTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n \\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n console.log(target.value)\\r\\n this.data.value = target.value;\\r\\n }\\r\\n\\r\\n handleSubmit(evt) {\\r\\n alert(\'Your favorite flavor is: \' + this.data.value);\\r\\n evt.preventDefault();\\r\\n }\\r\\n \\r\\n render () {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new FormTest({ value: \'mango\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    获取DOM节点

    \\r\\n\\r\\n虽然绝大部分情况下,开发者不需要去查找获取DOM,但是还是有需要获取DOM的场景,所以Omi提供了方便获取DOM节点的方式。\\r\\n\\r\\n### ref和refs\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(){\\r\\n alert(this.refs.abc.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\n可以看到通过在HTML中标记ref为abc,那么就通过this.refs.abc访问到该DOM节点。\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    Hello World

    \\r\\n\\r\\n你可以使用ES6+或者ES5的方式编写Omi程序来搭建你的Web程序。\\r\\n\\r\\n### Hello World with ES6+\\r\\n\\r\\n你可以使用 [webpack](https://webpack.github.io/) 打包工具,webpack会把你的模块代码打成一个很小的包,优化加载时间。使用[babel](http://babeljs.io/),让你立刻马上使用ES6+来编写你的web程序。你只需要在webpack配置的module设置好[babel-loader](https://github.com/babel/babel-loader)便可。\\r\\n\\r\\n一个Omi的简短的例子如下所示:\\r\\n\\r\\n```js\\r\\nimport Omi from \'./omi.js\';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n //注意,return中的包裹是可选的。主要是为了识别为JSX文件可以有CSS高亮。\\r\\n return `\\r\\n \\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\n组件生成的HTML最终会插入到#container中。上面的例子展示了Omi的部分特性:\\r\\n\\r\\n- data传递: new Hello(data,..)的data可以直接提供给render方法里的模板\\r\\n- 局部CSS: h1只对render里的h1生效,不会污染外面的h1\\r\\n- 声明式事件绑定: onclick调用的就是组件内的handleClick,this可以拿到当前的DOM元素,还可以拿到当前的event\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n你可以使用Omi.makeHTML来生成组件标签用于嵌套。\\r\\n```js\\r\\n Omi.makeHTML(\'Hello\', Hello);\\r\\n```\\r\\n那么你就在其他组件中使用,如\\r\\n```js\\r\\n ...\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Test
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n ...\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### Hello World with ES5\\r\\n\\r\\n当然Omi没有抛弃ES5的用户。你可以使用ES5的方式编写Omi。如,在你的HTML中引用omi.js:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\n然后:\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\", {\\r\\n style: function () {\\r\\n return \\"h1{ cursor:pointer }\\";\\r\\n },\\r\\n handleClick: function (dom) {\\r\\n alert(dom.innerHTML)\\r\\n },\\r\\n render: function () {\\r\\n return \'
    \\\\\\r\\n

    \\\\\\r\\n Hello ,{{name}}!\\\\\\r\\n

    \\\\\\r\\n
    \'\\r\\n }\\r\\n});\\r\\n\\r\\nvar Test = Omi.create(\\"Test\\", {\\r\\n render: function () {\\r\\n return \'
    \\\\\\r\\n
    Test
    \\\\\\r\\n \\\\\\r\\n
    \'\\r\\n }\\r\\n});\\r\\n\\r\\nOmi.render(new Test(),\'#container\');\\r\\n```\\r\\n当然除了在HTML引入脚本,你还可以使用AMD、CMD或者CommonJS的方式引入Omi,这里就不再一一列举。\\r\\n\\r\\n需要注意的是,Omi.create的第一个参数Hello是用来生成Tag Name的。你可以在其他地方嵌入你的组件。如:\\r\\n\\r\\n```js\\r\\n ...\\r\\n render:function() {\\r\\n return \'
    \\\\\\r\\n \\\\\\r\\n
    Test XXXX
    \\\\\\r\\n \\\\\\r\\n
    \';\\r\\n }\\r\\n ...\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports='module.exports = "

    继承

    \\r\\n\\r\\n通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。\\r\\n\\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n div{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n}\\r\\n\\r\\nclass SubHello extends Hello {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### ES5下的继承\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\",{\\r\\n render:function(){\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n})\\r\\n\\r\\nvar SubHello = Omi.create(\\"SubHello\\",Hello,{ });\\r\\n\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\n点击这里→在线试试"'},function(n,e){n.exports='module.exports = "

    安装

    \\n\\n[Omi](https://github.com/AlloyTeam/omi)(读音 / [ˈomɪ] /, 汉字类似于 欧米) 是一款用于创建用户界面的组件化框架,开放并且现代,故得名:Omi。\\n\\n### 安装 Omi\\n\\n我们推荐使用 [npm](https://www.npmjs.com/) 来管理你的前端依赖.\\n\\n通过npm安装Omi,你只需要执行下面的命令:\\n\\n``` js\\nnpm install omi\\n```\\n\\n## omi-cli\\n\\n你也可以通过omi-cli去初始化你的项目:\\n\\n``` js\\n$ npm install omi-cli -g //安装cli\\n$ omi init your_project_name //初始化项目,你也可以在一个空的文件夹下执行 omi init\\n$ cd your_project_name //如果你是在空文件夹下执行的 omi init。请无视这条命令\\n$ npm run dev //开发\\n$ npm run dist //部署发布\\n```"'},function(n,e){n.exports='module.exports = "

    生命周期

    \\r\\n\\r\\n|name |avatars |company | \\r\\n|---|---|---|\\r\\n| constructor | 构造函数 | new的时候 |\\r\\n| install | 初始化安装,这可以拿到用户传进的data进行处理 | 实例化 |\\r\\n| installed | 安装完成,HTML已经插入页面之后执行 | 实例化 |\\r\\n| uninstall | 卸载组件。执行remove方法会触发该事件 | 销毁时 |\\r\\n| beforeUpdate | 更新前 | 存在期 |\\r\\n| afterUpdate | 更新后 | 存在期 |\\r\\n\\r\\n## 示意图\\r\\n\\r\\n![lc](http://images2015.cnblogs.com/blog/105416/201701/105416-20170119153018546-1566368987.png)\\r\\n \\r\\n### 举个例子\\r\\n\\r\\n```js\\r\\nclass Timer extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n install () {\\r\\n this.data = {secondsElapsed: 0};\\r\\n }\\r\\n\\r\\n tick() {\\r\\n this.data.secondsElapsed++;\\r\\n this.update();\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.interval = setInterval(() => this.tick(), 1000);\\r\\n }\\r\\n\\r\\n uninstall() {\\r\\n clearInterval(this.interval);\\r\\n }\\r\\n\\r\\n\\r\\n style () {\\r\\n return `\\r\\n .num { color:red; }\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Seconds Elapsed: {{secondsElapsed}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n点击这里→在线试试\\r\\n"'},function(n,e){n.exports='module.exports = "

    循环遍历

    \\r\\n\\r\\n下面介绍mustache.js的方式和javascript遍历的方式。\\r\\n\\r\\n### 方式一\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n
      \\r\\n {{#items}} \\r\\n
    • {{text}}
    • \\r\\n {{/items}}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nmustache.js更详细的循环遍历使用可看[https://github.com/janl/mustache.js#non-empty-lists](https://github.com/janl/mustache.js#non-empty-lists)。 比如还支持:\\r\\n\\r\\n* 如果items的每一项是字符串,可以直接**{{.}}**的方式来输出每一项\\r\\n* 循环的时候调用定义好的函数\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n### 方式二\\r\\n\\r\\n既然ES6+了,当然可以使用${ }以及Array的map方法: \\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `
    \\r\\n
      \\r\\n ${this.data.items.map(item =>\\r\\n `
    • ${item.text}
    • `\\r\\n ).join(\'\')}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\n你将在页面看到如下效果:\\r\\n\\r\\n![pv](http://images2015.cnblogs.com/blog/105416/201701/105416-20170122095724129-2059595233.png)\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n如果想在循环里加些判断呢?比如需要把id为偶数的隐藏起来:\\r\\n\\r\\n```js\\r\\nrender() {\\r\\n return `
    \\r\\n
      \\r\\n ${this.data.items.map(item =>\\r\\n `
    • ${item.text}
    • `\\r\\n ).join(\'\')}\\r\\n
    \\r\\n
    `;\\r\\n}\\r\\n```\\r\\n\\r\\n所以模板字符串还是非常方便,随着ES继续发展下去,模板引擎估计会慢慢消失。所以omi提供了 omi.lite.js 版本不包含任何模板引擎。"'; +},function(n,e){n.exports="module.exports = \"

    插件体系

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi)是Web组件化框架,怎么又来了个插件的概念?\\r\\n\\r\\n可以这么理解: Omi插件体系可以赋予dom元素一些能力,并且可以和组件的实例产生关联。\\r\\n\\r\\n### omi-drag\\r\\n\\r\\n且看这个例子:\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n```js\\r\\nimport OmiDrag from './omi-drag.js';\\r\\n\\r\\nOmiDrag.init();\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n\\r\\n style(){\\r\\n return `\\r\\n .test{\\r\\n width:100px;\\r\\n height:100px;\\r\\n color:white;\\r\\n line-height:90px;\\r\\n text-align:center;\\r\\n background-color:#00BFF3;\\r\\n }\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n如上面的代码所示,通过在div上标记omi-drag,这个div就能够被用户使用鼠标拖拽。我们称omi-drag.js为omi插件。\\r\\n是不是非常方便?那么这个omi-drag是怎么实现的?\\r\\n\\r\\n## Omi.extendPlugin\\r\\n\\r\\n核心方法: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n下面的代码就是展示了如何通过 Omi.extendPlugin 赋予dom拖拽的能力:\\r\\n\\r\\n```js\\r\\n;(function () {\\r\\n\\r\\n var OmiDrag = {};\\r\\n var Omi = typeof require === 'function'\\r\\n ? require('omi')\\r\\n : window.Omi;\\r\\n\\r\\n OmiDrag.init = function(){\\r\\n Omi.extendPlugin('omi-drag',function(dom, instance){\\r\\n dom.style.cursor='move';\\r\\n var isMouseDown = false,\\r\\n preX = null,\\r\\n preY = null,\\r\\n currentX = null,\\r\\n currentY = null,\\r\\n translateX = 0,\\r\\n translateY = 0;\\r\\n\\r\\n dom.addEventListener('mousedown',function(evt){\\r\\n isMouseDown = true;\\r\\n preX = evt.pageX;\\r\\n preY = evt.pageY;\\r\\n evt.stopPropagation();\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n }\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mouseup',function(){\\r\\n isMouseDown = false;\\r\\n preX = preY = currentX = currentY = null;\\r\\n },false);\\r\\n });\\r\\n }\\r\\n\\r\\n OmiDrag.destroy = function(){\\r\\n delete Omi.plugins['omi-drag'];\\r\\n };\\r\\n\\r\\n if (typeof exports == \\\"object\\\") {\\r\\n module.exports = OmiDrag;\\r\\n } else if (typeof define == \\\"function\\\" && define.amd) {\\r\\n define([], function(){ return OmiDrag });\\r\\n } else {\\r\\n window.OmiDrag = OmiDrag;\\r\\n }\\r\\n\\r\\n})();\\r\\n```\\r\\n\\r\\n方法: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n其中pluginName为插件的名称\\r\\n其中handler为处理器。handler可以拿到标记了pluginName的dom以及dom所在的组件的实例,即 dom 和 instance。\\r\\n\\r\\n通过 Omi.extendPlugin,可以赋予dom元素一些能力,也可以和组件的实例(instance)产生关联。\\r\\n但是上面的例子没有和instance产生关联,我们接下来试试:\\r\\n\\r\\n## 关联instance\\r\\n\\r\\n我们想在组件里面能够监听到move并且执行回调。如下:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandler(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n主要被拖动过程中,moveHandler就不断地被执行。插件代码需要修改:\\r\\n\\r\\n```js\\r\\n...\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance.moveHandler(evt);\\r\\n }\\r\\n},false);\\r\\n```\\r\\n\\r\\n我们在里面增加了instance.moveHandler(evt);方法,用来执行组件实例上的moveHandler方法。\\r\\n这样的话:就是组件的实例(instance)产生关联。但是还是有问题?如果标记了多个omi-drag 就会有问题!如:\\r\\n\\r\\n```js\\r\\n...\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n通常我们系统每个omi-drag都能对应一个回调函数,如:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\n怎么办?怎么实现?有办法!通过dom传递数据给插件。\\r\\n\\r\\n## 传递数据\\r\\n\\r\\n先来看最后实现的效果:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nomi-drag修改的地方:\\r\\n\\r\\n```js\\r\\n...\\r\\nvar handlerName = dom.getAttribute('dragMove');\\r\\n\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance[handlerName](evt);\\r\\n }\\r\\n},false);\\r\\n...\\r\\n```\\r\\n\\r\\n* 通过 var handlerName = dom.getAttribute('dragMove') 拿到dom上声明的dragMove\\r\\n* 通过 instance[handlerName](evt) 去执行对应的方法\\r\\n\\r\\n点击这里→在线试试\\r\\n\\r\\n## 更多插件\\r\\n\\r\\n* [omi-finger](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-finger) Omi的[AlloyFinger](https://github.com/AlloyTeam/AlloyFinger)插件,支持各种触摸事件和手势\\r\\n* [omi-transform](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-transform) Omi的[transformjs](http://alloyteam.github.io/AlloyTouch/transformjs/)插件,快速方便地设置DOM的CSS3 Transform属性\\r\\n* [omi-touch](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-touch) Omi的[AlloyTouch](https://github.com/AlloyTeam/AlloyTouch)插件,Omi项目的触摸运动解决方案(支持触摸滚动、旋转、翻页、选择等等)\\r\\n* [omi-jquery-date-picker](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-jquery-date-picker) Omi的时间选择插件,支持各种时间或者时间区域选择\\r\\n\""},function(n,e){n.exports='module.exports = "## 写在前面\\r\\nOmi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。\\r\\n\\r\\n项目开始之前,实现选择一个脚手架。这个项目用的就是[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)\\r\\n\\r\\nGulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)\\r\\n\\r\\n\\r\\n所以,要使用Fiddler并配置Extention:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)\\r\\n\\r\\n\\r\\n## 目录\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)\\r\\n\\r\\n\\r\\n目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。\\r\\n组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。\\r\\n\\r\\n## 命令\\r\\n\\r\\n开发\\r\\n```js\\r\\nnpm run dev\\r\\n```\\r\\n\\r\\n发布\\r\\n```js\\r\\nnpm run dist\\r\\n```\\r\\n\\r\\n## 开始写码\\r\\n\\r\\n万事具备,开始写码。先写组件:\\r\\n\\r\\n```js\\r\\nimport Omi from \'omi\'\\r\\n\\r\\nclass UserList extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n install() {\\r\\n this.data.uin_info || (this.data.uin_info = [])\\r\\n this.data.uin_info.forEach(user => {\\r\\n this.prepareData(user)\\r\\n })\\r\\n }\\r\\n \\r\\n prepareData(user){\\r\\n user.desc_d = user.desc.split(\\" \\")[0]\\r\\n user.desc_t = user.desc.split(\\" \\")[1]\\r\\n user.isBoy = user.sex === \\"男\\"\\r\\n user.qlogo = user.url.replace(\\"http://\\", location.protocol + \\"//\\").replace(/&/g, \\"&\\")\\r\\n if (user.profession_desc) {\\r\\n user.hasProfession_desc = true\\r\\n }\\r\\n }\\r\\n \\r\\n appendUsers (users) {\\r\\n users.uin_info && users.uin_info.forEach(user =>{\\r\\n this.prepareData(user)\\r\\n this.data.uin_info.push(user)\\r\\n })\\r\\n this.update()\\r\\n }\\r\\n\\r\\n sendGift(uin, nick, qlogo) {\\r\\n //送礼物并关闭webview,此处省略\\r\\n //..\\r\\n //..\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n {{#uin_info}}\\r\\n
    \\r\\n
    \\r\\n \\r\\n
    \\r\\n
    \\r\\n
    {{{nick}}}
    \\r\\n
    \\r\\n {{#isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{^isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{#hasProfession_desc}} {{profession_desc}} {{/hasProfession_desc}}\\r\\n
    \\r\\n
    {{{intro}}}
    \\r\\n
    \\r\\n
    {{desc_d}} · {{desc_t}}
    \\r\\n
    \\r\\n {{/uin_info}}\\r\\n
    加载中...
    \\r\\n
    \\r\\n`\\r\\n }\\r\\n\\r\\n style() {\\r\\n return `\\r\\n\\r\\n\\r\\n.qlogo {\\r\\n overflow: hidden;\\r\\n width: 70px;\\r\\n height: 70px;\\r\\n -webkit-border-radius: 50%;\\r\\n border-radius: 50%;\\r\\n position: absolute;\\r\\n top: 10px;\\r\\n left: 12px;\\r\\n}\\r\\n...\\r\\n...\\r\\n..这里省略大量.....\\r\\n...\\r\\n...\\r\\n\\r\\n.distance_info {\\r\\n position: absolute;\\r\\n top: 15px;\\r\\n right: 9px;\\r\\n color: #7B7B84;\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nexport default UserList\\r\\n```\\r\\n\\r\\n组件里面有5个方法:\\r\\n\\r\\n* constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this\\r\\n* install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理\\r\\n* prepareData 对数据进行一些处理来满足模板的渲染\\r\\n* appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用\\r\\n* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..\\r\\n\\r\\n其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。\\r\\nrender里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;\\r\\n如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。\\r\\n\\r\\n这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)\\r\\n\\r\\n\\r\\n下面来看index.js:\\r\\n\\r\\n```js\\r\\nimport Root from \'./config.js\'\\r\\nimport Omi from \'omi\'\\r\\nimport UserList from \'../component/user_list/index.js\'\\r\\n\\r\\nOmi.makeHTML(\'UserList\', UserList)\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n installed() {\\r\\n window.onscroll = () => this.loadMore()\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n\\r\\n loadMore() {\\r\\n const body = document.body,\\r\\n html = document.documentElement,\\r\\n height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),\\r\\n vp_height = window.innerHeight\\r\\n\\r\\n if (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n }\\r\\n\\r\\n requestData(callback) {\\r\\n if (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }else{\\r\\n \\t//ajax 请求数据,这里省略\\r\\n }\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Main(),\'body\')\\r\\n```\\r\\n\\r\\n通过Omi.makeHTML(\'UserList\', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:\\r\\n\\r\\n```js\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n```\\r\\n\\r\\n下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。\\r\\n\\r\\n```js\\r\\nwindow.onscroll = () => this.loadMore()\\r\\n```\\r\\n\\r\\n通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:\\r\\n\\r\\n```js\\r\\nif (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n}\\r\\n```\\r\\n\\r\\nrequestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。\\r\\n慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:\\r\\n\\r\\n```js\\r\\n \\r\\n```\\r\\n\\r\\n上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!\\r\\n\\r\\n再来看下数据模拟:\\r\\n\\r\\n```js\\r\\nif (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }\\r\\n```\\r\\n\\r\\n这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!\\r\\n\\r\\n## 最后\\r\\n\\r\\n好了,就这么多,Omi让代码真心方便简洁~~~\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)"'},function(n,e){n.exports='module.exports = "

    模板切换

    \\r\\n\\r\\nOmi有三个版本。其中的omi.js和omi.lite.js属于Web端使用的版本。\\r\\n\\r\\n* omi.js内置了[mustache.js](https://github.com/janl/mustache.js)作为模版引擎\\r\\n* omi.lite.js不包含任何模版引擎\\r\\n\\r\\nOmi不强制开发者使用mustache.js,你可以根据业务场景使用任意模板引擎或者不使用模板引擎。\\r\\n\\r\\n那么怎么使用别的模板引擎?下面拿[artTemplate](https://github.com/aui/artTemplate)作为例子。\\r\\n\\r\\n### 使用artTemplate\\r\\n\\r\\n```js\\r\\nOmi.template = function(tpl, data){\\r\\n return artTemplate.compile(tpl)(data);\\r\\n}\\r\\n```\\r\\n重写Omi.template方法,tpl为传入的模板,data为模板所需的数据,返回值为HTML。\\r\\n重写完毕后就能在render使用artTemplate的语法,如:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h1 { color:red; }\\r\\n li{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `

    {{title}}

    \\r\\n
      \\r\\n {{each list as value i}}\\r\\n
    • 索引 {{i + 1}} :{{value}}
    • \\r\\n {{/each}}\\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/artTemplate/)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/artTemplate)"'},function(n,e){n.exports='module.exports = "

    Omi的理念

    \\r\\n\\r\\nOmi的理念是基于面向对象编程体系,内建积木系统。\\r\\n 传统的单向数据流或者抛出event的组件通讯方式增加了系统的稳定性,但是丧失了灵活性。一定程度上也降低了组建的复用。所谓鱼和熊掌不可兼得。\\r\\n 面向对象体系需要多一个逻辑层,可以自由操作所有组件的instance,instance之间的逻辑关系构建出了整个程序。这样组建间的逻辑,通信,复用就全部迎刃而解。组建也更加单一职责,更松耦合。\\r\\n\\r\\n对比函数式编程、命令式编程与面向对象编程,可以归纳总结出下面几条:\\r\\n\\r\\n- 命令式编程干脆直接,利用循环条件等控制流程,强调执行过程\\r\\n- 命令式编程对硬件执行友好,运行更容易,却阻碍了复杂程序的设计\\r\\n- 函数式强调输入和输出,并非执行过程\\r\\n- 函数式倡导多个简单执行单元组合成复杂运算程序\\r\\n- 面向对象编程将对象作为程序的基本单元,更具有重用性、灵活性和扩展性\\r\\n\\r\\nJavascript是哪种类型的语言?现在ES6+已经有了class。那么他是面向对象语言?\\r\\n但是JS可以在任意地方定义函数并且当作把函数当作值来传递。那么他是函数式编程语言?\\r\\n所以,没有精准的定义,取决于你的用法和姿势。其次,Web组件化架构层面编程模型和语言层面编程模型是非常自由的关系。意思就是,你可以用Javascript构建函数式编程框架如React,也可以基于面向对象体系搭建Omi。\\r\\n\\r\\n### 函数式编程 VS 面向对象编程\\r\\n\\r\\n在UI组件框架层面,函数式编程的代表有React,Omi属于面向对象编程体系。那么他们各有什么优缺点?下面做了个对比(其实也是函数式编程与面向对象编程的对比):\\r\\n\\r\\n| | React | Omi |\\r\\n| ------------- |:-------------:|:-----:|\\r\\n| 组件通信 | ★★★★☆| ★★★★★ |\\r\\n| 稳定性 | ★★★★★ | ★★★★☆ |\\r\\n| 灵活性 | ★★★★☆| ★★★★★ |\\r\\n| 扩展性 | ★★★★☆ | ★★★★★ |\\r\\n| 测试性 | ★★★★★ | ★★★★☆ |\\r\\n| 文件大小 | ★★★☆☆ | ★★★★★ |\\r\\n| 功能特性 | ★★★☆☆ | ★★★★☆ |\\r\\n| DOM性能 | ★★★★★ | ★★★★☆ |\\r\\n| 动画性能 | ★★★★☆ | ★★★★★ |\\r\\n| 抽象复杂度 | ★★★★☆ | ★★★★★ |\\r\\n| 异步编程 | ★★★★★ | ★★★★☆ |\\r\\n\\r\\n可以看得出,鱼和熊掌不可兼得。面向对象编程更具有重用性、灵活性和扩展性,带来的问题就是更加难测试。\\r\\n具体来说,如函数式编程,其测试面积是state1 + state2 + ... + stateN;在面向对象编程中,其测试面积是state1×event1 + state2×event2 + ... + stateN×eventN。\\r\\n\\r\\n总结来说,更加推荐使用面向对象的方式去搭建UI组件化框架。\\r\\n\\r\\n
    \\r\\n\\r\\n### 全文结束,感谢阅读。[开始Omi之旅吧!](https://github.com/AlloyTeam/omi) \\r\\n\\r\\n"'},function(n,e){n.exports='module.exports = "# 深入Omi\\r\\n\\r\\n(待续...)\\r\\n\\r\\n* [环境搭建](./cn_env.md)\\r\\n* [Hello Omi](./cn_hello.md)\\r\\n* [手Q附近Web页Omi实战](./cn_nearby.md)\\r\\n* 局部CSS揭秘\\r\\n* 组件嵌套揭秘\\r\\n* 事件处理揭秘\\r\\n* 服务器端渲染揭秘\\r\\n* 模板切换揭秘\\r\\n* 容器系统揭秘"'},function(n,e){n.exports='module.exports = "

    环境搭建

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)使用 Webpack + ES6 的方式去开发;使用karma+jasmine来作为Omi的测试工具。\\r\\n\\r\\n## Karma介绍\\r\\n\\r\\nKarma是一个基于Node.js的JavaScript测试执行过程管理工具(Test Runner)。该工具可用于测试所有主流Web浏览器,也可集成到CI(Continuous integration)工具,也可和其他代码编辑器一起使用。这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行。但是集成到travis ci要把singleRun设置成true,让其只执行一遍。\\r\\n\\r\\n## Jasmine介绍\\r\\nJasmine 是一款 JavaScript BDD(行为驱动开发)测试框架,它不依赖于其他任何 JavaScript 组件。它有干净清晰的语法,让您可以很简单的写出测试代码。\\r\\n\\r\\n## 开发依赖包\\r\\n\\r\\n在package.json中,有如下配置:\\r\\n\\r\\n```js\\r\\n \\"devDependencies\\": {\\r\\n \\"babel-core\\": \\"^6.0.20\\",\\r\\n \\"babel-loader\\": \\"^6.0.1\\",\\r\\n \\"babel-preset-es2015\\": \\"^6.0.15\\",\\r\\n \\"node-libs-browser\\": \\"^0.5.3\\",\\r\\n \\"webpack\\": \\"^1.14.0\\",\\r\\n \\"jasmine-core\\": \\"^2.5.2\\",\\r\\n \\"karma\\": \\"^1.3.0\\",\\r\\n \\"karma-chrome-launcher\\": \\"^2.0.0\\",\\r\\n \\"karma-jasmine\\": \\"^1.1.0\\",\\r\\n \\"karma-webpack\\": \\"^1.8.1\\"\\r\\n }\\r\\n```\\r\\n\\r\\n* ES6+相关依赖有babel-core、babel-loader和babel-preset-es2015\\r\\n\\r\\n在webpack.config.js中配置js文件使用babel-loader编译。\\r\\n```js\\r\\nloaders: [\\r\\n {\\r\\n loader: \'babel-loader\',\\r\\n test: /\\\\.js$/,\\r\\n query: {\\r\\n presets: \'es2015\',\\r\\n }\\r\\n }\\r\\n]\\r\\n```\\r\\n\\r\\n* webpack相关依赖有node-libs-browser和webpack\\r\\n* 其余都是单元测试相关依赖\\r\\n\\r\\n 注意,这里使用了karma-webpack。因为使用Omi框架支持ES6+和ES5,使用karma-webpack是为了在单元测试里面使用ES6+的import和Class等语法。\\r\\n\\r\\n在karma.conf.js中配置webpack:\\r\\n\\r\\n```js\\r\\n webpack: webpackConfig,\\r\\n webpackMiddleware:{\\r\\n noInfo:false\\r\\n },\\r\\n plugins: [\\r\\n \'karma-webpack\',\\r\\n \'karma-jasmine\',\\r\\n \'karma-chrome-launcher\'\\r\\n ]\\r\\n```\\r\\n\\r\\n具体配置看test目录下的[karma.conf.js](https://github.com/AlloyTeam/omi/blob/master/test/karma.conf.js)和[webpack.test.config.js](https://github.com/AlloyTeam/omi/blob/master/test/webpack.test.config.js)便可。\\r\\n\\r\\n注意,karma.conf.js需要设置\\r\\n\\r\\n```js\\r\\n// if true, Karma captures browsers, runs the tests and exits\\r\\nsingleRun: true,\\r\\n```\\r\\n\\r\\n不然,travis ci脚本执行的时候不会中断导致执行超时异常。\\r\\n\\r\\n## npm 脚本\\r\\n\\r\\n```js\\r\\n \\"scripts\\": {\\r\\n \\"build\\": \\"webpack -w\\",\\r\\n \\"test\\": \\"karma start test/karma.conf.js\\",\\r\\n \\"hello\\": \\"webpack -w\\",\\r\\n \\"todo\\": \\"webpack -w\\"\\r\\n }\\r\\n```\\r\\n\\r\\n其中:\\r\\n* npm run build : 生成dist目录的omi.js文件\\r\\n* npm run test : 执行单元测试\\r\\n* npm run hello : 编译hello的demo\\r\\n* npm run todo : 编译todo的demo\\r\\n\\r\\n在webpack.config.js中,会根据 process.env.npm_lifecycle_event去设置不同的入口文件。所以同样是执行webpack -w,执行结果可以不一样。\\r\\n\\r\\n来看下build的相关webpack配置:\\r\\n\\r\\n```js\\r\\nif(ENV === \'build\'){\\r\\n config = {\\r\\n entry: {\\r\\n omi: \'./src/index.js\'\\r\\n },\\r\\n output: {\\r\\n path: \'dist/\',\\r\\n library:\'Omi\',\\r\\n libraryTarget: \'umd\',\\r\\n filename: \'[name].js\'\\r\\n },\\r\\n```\\r\\n\\r\\n这里把libraryTarget设置成了umd,webpack会帮助我们build出umd的Omi。\\r\\n\\r\\n如果是打包demo(npm run hello 和 npm run todo)的话,会进入下面的条件判断:\\r\\n\\r\\n```js\\r\\nelse {\\r\\n config.entry = \'./example/\' + ENV + \'/main.js\';\\r\\n config.output.path = \'./example/\' + ENV + \'/\';\\r\\n}\\r\\n```\\r\\n\\r\\n会去example下对应的目录查找main.js作为webpack入口文件。\\r\\n\\r\\n这里可以看到,我们不仅用webpack build出Omi框架,也使用webpack build所有demo。\\r\\n详细配置参考[webpack.config.js](https://github.com/AlloyTeam/omi/blob/master/webpack.config.js)的配置。\\r\\n\\r\\n## 参考文档\\r\\n\\r\\n* [http://www.cnblogs.com/cqhaibin/p/5867125.html](http://www.cnblogs.com/cqhaibin/p/5867125.html)\\r\\n* [https://karma-runner.github.io/latest/intro/installation.html](https://karma-runner.github.io/latest/intro/installation.html)\\r\\n* [https://karma-runner.github.io/latest/intro/configuration.html](https://karma-runner.github.io/latest/intro/configuration.html)\\r\\n\\r\\n"'},function(n,e){n.exports="module.exports = \"

    Hello Omi

    \\r\\n\\r\\n[Omi框架](https://github.com/AlloyTeam/omi)的每个组件都继承自Omi.Component,本篇会去完成Omi的Component的基本锥形,让其能够渲染第一个组件。\\r\\n\\r\\n## omi.js实现\\r\\n\\r\\n```js\\r\\nvar Omi = {};\\r\\nOmi._instanceId = 0;\\r\\nOmi.getInstanceId = function () {\\r\\n return Omi._instanceId++;\\r\\n};\\r\\n\\r\\nOmi.render = function(component, renderTo){\\r\\n component.renderTo = typeof renderTo === \\\"string\\\" ? document.querySelector(renderTo) : renderTo;\\r\\n component._render();\\r\\n return component;\\r\\n};\\r\\n\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n* Omi.getInstanceId 用来给每个组件生成自增的ID\\r\\n* Omi.render 用来把组件渲染到页面\\r\\n\\r\\n## 基类Omi.Component实现\\r\\n\\r\\n所有的组件都是继承自Omi.Component。\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\n\\r\\nclass Component {\\r\\n constructor(data) {\\r\\n this.data = data || {};\\r\\n this.id = Omi.getInstanceId();\\r\\n this.HTML = null;\\r\\n this.renderTo = null;\\r\\n }\\r\\n\\r\\n _render() {\\r\\n this.HTML = this.render();\\r\\n this.renderTo.innerHTML = this.HTML;\\r\\n }\\r\\n}\\r\\n\\r\\nexport default Component;\\r\\n```\\r\\n\\r\\n* Omi使用完全面向对象的方式去开发组件,这里约定好带有下划线的方法是用于内部实现调用,不建议Omi框架的使用者去调用。\\r\\n* 其中,_render为私有方法用于内部实现调用,会去调用组件的真正render方法用于生成HTML,并且把生成的HTML插入到renderTo容器里面。\\r\\n* 注意,这里目前没有引入dom diff,不管第几次渲染都是无脑设置innerHTML,复杂HTML结构对浏览器的开销很大,这里后续会引入diff。\\r\\n\\r\\n## index.js整合\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi = Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n这里把Omi给直接暴露在window下,因为每个组件都生成了唯一的ID,后续实现事件作用域以及对象实例获取都要通过window下的Omi获取。\\r\\n\\r\\n## 最后使用\\r\\n\\r\\n实现完omi.js和component.js以及index.js之后,你就可以实现Hello Omi拉:\\r\\n\\r\\n```js\\r\\nimport Omi from 'index.js'; \\r\\n//或者使用webpack build之后的omi.js \\r\\n//import Omi from 'omi.js';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,`+ this.data.name +`!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : 'Omi' }),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n什么?都2017年了还在拼接字符串?!虽然ES6+的template string让多行字符串拼接更加得心应手,但是template string+模板引擎可以让更加优雅方便。既然用了template string,也可以写成这样子:\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,${this.data.name}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : 'Omi' }),\\\"#container\\\");\\r\\n```\\r\\n\\r\\n## 引入mustachejs模板引擎\\r\\n\\r\\nOmi支持任意模板引擎。可以看到,上面是通过拼接字符串的形式生成HTML,这里当然可以使用模板引擎。\\r\\n\\r\\n修改一下index.js:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Mustache from './mustache.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.template = Mustache.render;\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi=Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n这里把Mustache.render挂载在Omi.template下。再修改一下component.js:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\n\\r\\nclass Component {\\r\\n constructor(data) {\\r\\n this.data = data || {};\\r\\n this.id = Omi.getInstanceId();\\r\\n this.HTML = null;\\r\\n }\\r\\n\\r\\n _render() {\\r\\n this.HTML = Omi.template(this.render(), this.data);\\r\\n this.renderTo.innerHTML = this.HTML;\\r\\n }\\r\\n}\\r\\n\\r\\nexport default Component;\\r\\n```\\r\\n\\r\\nOmi.template(即Mustache.render)需要接受两个参数,第一个参数是模板,第二个参数是模板使用的数据。\\r\\n\\r\\n现在,你便可以使用mustachejs模板引擎的语法了:\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n从上面的代码可以看到,你完全可以重写Omi.template方法去使用任意模板引擎。重写Omi.template的话,建议使用omi.lite.js,因为omi.lite.js是不包含任何模板引擎的。那么怎么build出两个版本的omi?且看webpack里设置的多入口:\\r\\n\\r\\n```js\\r\\n entry: {\\r\\n omi: './src/index.js',\\r\\n 'omi.lite': './src/index.lite.js'\\r\\n},\\r\\noutput: {\\r\\n path: 'dist/',\\r\\n library:'Omi',\\r\\n libraryTarget: 'umd',\\r\\n filename: '[name].js'\\r\\n},\\r\\n```\\r\\n\\r\\nindex.lite.js的代码如下:\\r\\n\\r\\n```js\\r\\nimport Omi from './omi.js';\\r\\nimport Component from './component.js';\\r\\n\\r\\nOmi.template = function(tpl, data){\\r\\n return tpl;\\r\\n}\\r\\n\\r\\nOmi.Component = Component;\\r\\n\\r\\nwindow.Omi=Omi;\\r\\nmodule.exports = Omi;\\r\\n```\\r\\n\\r\\n可以看到Omi.template没有对tpl做任何处理直接返回,开发者可以重写该方法。\\r\\n\\r\\n## 总结\\r\\n\\r\\n到目前为止,已经实现了:\\r\\n\\r\\n* 第一个组件的渲染\\r\\n* 模板引擎的接入\\r\\n* 多入口打包omi.js和omi.lite.js\\r\\n\\r\\n下片,将介绍《Omi原理-局部CSS》,欢迎关注...\\r\\n\""},function(n,e){n.exports='module.exports = "## 写在前面\\r\\nOmi很适合大型复杂的Web页面开发,例如一些Web在线工具的开发。但是制作这种简单的QQ附近用户列表Web页,也不会有大炮哄蚊子的感觉。\\r\\n\\r\\n项目开始之前,实现选择一个脚手架。这个项目用的就是[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)作为其项目脚手架。主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。(ps:目前脚手架先上github弄下来,pasturn和Aresn正在开发omi-cli,不久就要发布了)\\r\\n\\r\\nGulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n这里需要注意的是,BrowserSync会启动localhost:3000导致你的AJAX请求跨域而无法拿到数据。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184323476-1150194475.png)\\r\\n\\r\\n\\r\\n所以,要使用Fiddler并配置Extention:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184331445-1124037886.png)\\r\\n\\r\\n\\r\\n## 目录\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184337726-1825094998.png)\\r\\n\\r\\n\\r\\n目录结构也是和[Omi Github上的scaffolding](https://github.com/AlloyTeam/omi/tree/master/scaffolding)一样。\\r\\n组件全放在component目录,公共的工具库放在common,其他资源文件放在asset里。\\r\\n\\r\\n## 命令\\r\\n\\r\\n开发\\r\\n```js\\r\\nnpm run dev\\r\\n```\\r\\n\\r\\n发布\\r\\n```js\\r\\nnpm run dist\\r\\n```\\r\\n\\r\\n## 开始写码\\r\\n\\r\\n万事具备,开始写码。先写组件:\\r\\n\\r\\n```js\\r\\nimport Omi from \'omi\'\\r\\n\\r\\nclass UserList extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n install() {\\r\\n this.data.uin_info || (this.data.uin_info = [])\\r\\n this.data.uin_info.forEach(user => {\\r\\n this.prepareData(user)\\r\\n })\\r\\n }\\r\\n \\r\\n prepareData(user){\\r\\n user.desc_d = user.desc.split(\\" \\")[0]\\r\\n user.desc_t = user.desc.split(\\" \\")[1]\\r\\n user.isBoy = user.sex === \\"男\\"\\r\\n user.qlogo = user.url.replace(\\"http://\\", location.protocol + \\"//\\").replace(/&/g, \\"&\\")\\r\\n if (user.profession_desc) {\\r\\n user.hasProfession_desc = true\\r\\n }\\r\\n }\\r\\n \\r\\n appendUsers (users) {\\r\\n users.uin_info && users.uin_info.forEach(user =>{\\r\\n this.prepareData(user)\\r\\n this.data.uin_info.push(user)\\r\\n })\\r\\n this.update()\\r\\n }\\r\\n\\r\\n sendGift(uin, nick, qlogo) {\\r\\n //送礼物并关闭webview,此处省略\\r\\n //..\\r\\n //..\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n {{#uin_info}}\\r\\n
    \\r\\n
    \\r\\n \\r\\n
    \\r\\n
    \\r\\n
    {{{nick}}}
    \\r\\n
    \\r\\n {{#isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{^isBoy}}\\"\\"{{age}} {{/isBoy}}\\r\\n {{#hasProfession_desc}} {{profession_desc}} {{/hasProfession_desc}}\\r\\n
    \\r\\n
    {{{intro}}}
    \\r\\n
    \\r\\n
    {{desc_d}} · {{desc_t}}
    \\r\\n
    \\r\\n {{/uin_info}}\\r\\n
    加载中...
    \\r\\n
    \\r\\n`\\r\\n }\\r\\n\\r\\n style() {\\r\\n return `\\r\\n\\r\\n\\r\\n.qlogo {\\r\\n overflow: hidden;\\r\\n width: 70px;\\r\\n height: 70px;\\r\\n -webkit-border-radius: 50%;\\r\\n border-radius: 50%;\\r\\n position: absolute;\\r\\n top: 10px;\\r\\n left: 12px;\\r\\n}\\r\\n...\\r\\n...\\r\\n..这里省略大量.....\\r\\n...\\r\\n...\\r\\n\\r\\n.distance_info {\\r\\n position: absolute;\\r\\n top: 15px;\\r\\n right: 9px;\\r\\n color: #7B7B84;\\r\\n font-size: 10px;\\r\\n}\\r\\n\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nexport default UserList\\r\\n```\\r\\n\\r\\n组件里面有5个方法:\\r\\n\\r\\n* constructor 组件的构造函数,生命周期的一部分,其实在super上面和super调用下面可以对data做一些处理。super之上不能拿到this\\r\\n* install 组件的初始化安装,生命周期的一部分,这里也可以拿到用户传进的data进行处理\\r\\n* prepareData 对数据进行一些处理来满足模板的渲染\\r\\n* appendUsers 新增数据,用来处理用户向下滚动的load more 的行为的时候调用\\r\\n* sendGift 送礼物,点击每一项的时候会有送礼物的行为,业务相关,可以无视..\\r\\n\\r\\n其他两个方法的render和style用来生成组件的HTML和局部CSS,不再叙述。\\r\\nrender里面使用了[mustache.js](https://github.com/janl/mustache.js)模板引擎;\\r\\n如果使用omi.lite.js版本(不包含[mustache.js](https://github.com/janl/mustache.js)模板引擎)的话,你也可以使用ES6 map去遍历数据生成HTML,或者重写 Omi.template去使用任意你喜欢的模板引擎,非常灵活方便。\\r\\n\\r\\n这里友情提醒一下,如果使用webstorm的话,可以把js version设置成JSX Harmony或者ECMAScript 6,这样才是写ES6+的姿势。\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170222184433148-472636444.png)\\r\\n\\r\\n\\r\\n下面来看index.js:\\r\\n\\r\\n```js\\r\\nimport Root from \'./config.js\'\\r\\nimport Omi from \'omi\'\\r\\nimport UserList from \'../component/user_list/index.js\'\\r\\n\\r\\nOmi.makeHTML(\'UserList\', UserList)\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data)\\r\\n }\\r\\n\\r\\n installed() {\\r\\n window.onscroll = () => this.loadMore()\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n\\r\\n loadMore() {\\r\\n const body = document.body,\\r\\n html = document.documentElement,\\r\\n height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),\\r\\n vp_height = window.innerHeight\\r\\n\\r\\n if (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n }\\r\\n }\\r\\n\\r\\n requestData(callback) {\\r\\n if (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }else{\\r\\n \\t//ajax 请求数据,这里省略\\r\\n }\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Main(),\'body\')\\r\\n```\\r\\n\\r\\n通过Omi.makeHTML(\'UserList\', UserList)这句代码,UserList变成了可以嵌套至render方法中的标签。如:\\r\\n\\r\\n```js\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    `\\r\\n }\\r\\n```\\r\\n\\r\\n下面这行代码,是监听滚动,快滚动到底部的时候在loadMore里面会去请求。\\r\\n\\r\\n```js\\r\\nwindow.onscroll = () => this.loadMore()\\r\\n```\\r\\n\\r\\n通过height - document.body.scrollTop - vp_height < 200判断用户快要滚动底部,滚动到底部有个加载更多的行为,即:\\r\\n\\r\\n```js\\r\\nif (height - document.body.scrollTop - vp_height < 200) {\\r\\n this.requestData(data => this.list.appendUsers(data))\\r\\n}\\r\\n```\\r\\n\\r\\nrequestData是去服务器请求分页的数据,请求成功,会去调用this.list.appendUsers进行数据的添加。\\r\\n慢着?this.list哪里来的?appendUsers又是哪里定义的方法?且看下面:\\r\\n\\r\\n```js\\r\\n \\r\\n```\\r\\n\\r\\n上面标记的name,让你可以直接通过this.list访问到UserList对象的实例,所以也就可以调用它的appendUsers方法!\\r\\n\\r\\n再来看下数据模拟:\\r\\n\\r\\n```js\\r\\nif (Root.isDev) {\\r\\n require.ensure([], ()=> {\\r\\n callback(require(\'./mock_data.js\').default)\\r\\n })\\r\\n }\\r\\n```\\r\\n\\r\\n这里在dev环境下是mock数据,使用了require.ensure,这样当你npm run dist的时候,mock的数据就不会被打包进js里了!!\\r\\n\\r\\n## 最后\\r\\n\\r\\n好了,就这么多,Omi让代码真心方便简洁~~~\\r\\n\\r\\n### 相关地址\\r\\n\\r\\n* [演示地址](http://alloyteam.github.io/omi/example/qq_nearby/dev/index.html)\\r\\n* [源码地址](https://github.com/AlloyTeam/omi/tree/master/example/qq_nearby)"'; +},function(n,e){n.exports='module.exports = "# Omi命令行界面omi-cli发布\\r\\n\\r\\n通常认为,命令行界面(CLI)没有图形用户界面(GUI)那么方便用户操作。但是CLI比GUI节约资源,在熟悉命令之后,CLI会比GUI更加高效地帮你完成想要的任务。\\r\\n\\r\\n下面来介绍下[pasturn](https://github.com/pasturn)童鞋为Omi开发的CLI的两种使用姿势:\\r\\n\\r\\n## 姿势一\\r\\n\\r\\n```js\\r\\n$ npm install omi-cli -g //安装cli\\r\\n$ omi init your_project_name //初始化项目\\r\\n$ cd your_project_name //转到项目目录\\r\\n$ npm run dev //开发\\r\\n$ npm run dist //部署发布\\r\\n```\\r\\n\\r\\n## 姿势二\\r\\n\\r\\n当我们在一个空文件夹的时候,可以执行下面的命令。\\r\\n\\r\\n```js\\r\\n$ npm install omi-cli -g //安装cli\\r\\n$ omi init //初始化项目\\r\\n$ npm run dev //开发\\r\\n$ npm run dist //部署发布\\r\\n```\\r\\n\\r\\n这里不用再去跳转目录了,当前目录就是项目的目录。\\r\\n\\r\\n## 安装过程截图\\r\\n\\r\\n安装omi-cli:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100545470-696026058.png)\\r\\n\\r\\n\\r\\n安装初始化项目omi init:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100554891-1802174132.png)\\r\\n\\r\\n上面的成功的界面。注意:初始化项目会自动安装相关的npm依赖包,所以时间较长,请耐心等待。\\r\\n安装完成之后,在项目目录下你可以看到下面的目录结构:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100755845-465268116.png)\\r\\n\\r\\n开发 npm run dev:\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100601235-1477801934.png)\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170227100608985-921528126.png)\\r\\n\\r\\n如果,你看到了上面的界面,说明一切OK了。创建出来的项目主要基于 Gulp + Webpack + Babel + BrowserSync 进行开发和部署。Gulp用来串联整个流程,Webpack + Babel让你可以写ES6和打包,BrowserSync用来帮你刷浏览器,不用F5了。\\r\\n\\r\\n## 后续\\r\\n\\r\\n更多脚手架模板以及更多功能的命令正在开发中,如果有什么意见或者建议欢迎让我们知道。\\r\\n\\r\\n## 相关\\r\\n\\r\\n* Omi的Github地址[https://github.com/AlloyTeam/omi](https://github.com/AlloyTeam/omi)\\r\\n* 如果想体验一下Omi框架,可以访问 [Omi Playground](http://alloyteam.github.io/omi/example/playground/)\\r\\n* 如果想使用Omi框架或者开发完善Omi框架,可以访问 [Omi使用文档](https://github.com/AlloyTeam/omi/tree/master/docs#omi使用文档)\\r\\n* 如果你想获得更佳的阅读体验,可以访问 [Docs Website](http://alloyteam.github.io/omi/website/docs.html)\\r\\n* 如果你懒得搭建项目脚手架,可以试试 [omi-cli](https://github.com/AlloyTeam/omi/tree/master/cli)\\r\\n* 如果你有Omi相关的问题可以 [New issue](https://github.com/AlloyTeam/omi/issues/new)\\r\\n* 如果想更加方便的交流关于Omi的一切可以加入QQ的Omi交流群(256426170)\\r\\n\\r\\n![](http://images2015.cnblogs.com/blog/105416/201702/105416-20170208095745213-1049686133.png)"'},function(n,e){n.exports='module.exports = "

    Component Communication

    \\r\\n\\r\\nCommunication between [Omi](https://github.com/AlloyTeam/omi) components is very flexible, there are many options:\\r\\n\\r\\n- By declaring `data-*` on the component to pass data to child node\\r\\n- By declaring `data` on the component to pass data to child node (support complex data types mapping)\\r\\n- By declaring `childrenData` on parent component to automatically pass data to child node\\r\\n- By declaring `group-data` (support complex data types mapping)\\r\\n- It\'s completely object-oriented, you can easily get the object instance, then you can set the instance of the property or call the instance of the method\\r\\n\\r\\nLet\'s see some examples.\\r\\n\\r\\n### Communicate by `data-*`\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n \\tcursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\t

    Hello ,{{name}}!

    \\r\\n
    \\r\\n \\t\\t`;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nGenerally `data-*` is used to pass value types such as string and number. It is worth noting that, through `data-*`, received data types are string. You need to manually transform it to the number type.\\r\\n\\r\\nNormally, communicate by `data-*` is enough, but sometimes we may need to use complex data types, then we can use `data` to communicate.\\r\\n\\r\\n### Communicate by `data`\\r\\n\\r\\nAs shown in the above code, name can be passed to the subcomponent by `data-name=\\"Omi\\"`. The following code can also achieve the same effect.\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.helloData = { name : \'Omi\' };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nUse the `data` tag, it will find the property from the component instance (that is, this), this can be mounted with any complex objects. This also broke the limitations of `data-*`.\\r\\n\\r\\nThen how do we pass `data` that is in a deep depth of the instance to the Hello? No worries, `data` tag can be a complex statement:\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nClick me for the complex data mapping\\r\\n\\r\\n### Communicate by `childrenData`\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.childrenData = [{ name : \'Omi\' } , { name : \'dntzhang\' }];\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nWe can use `this.childrenData` to transfer data to the sub-component. In this case, `childrenData` is an array, so it can pass data to multiple components in the same time. In the meanwhile, the data will be passed to components one by one.\\r\\n\\r\\n### Communicate by `group-data`\\r\\n\\r\\n`childrenData` can pass data to multiple components. However, there are many scenes where the source of data does not have to be from `childrenData`. `childrenData` is an array, and it should be the same order with the components, so that the data must all concentrated in `childrenData`, it\'s very inconvenient. `group-data` dedicated to solve the above pain points, specifically to pass data to a group of components.\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.testData = [{name: \'Omi\'}, {name: \'dntzhang\'}, {name: \'AlloyTeam\'}];\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nBy declaring a `group-data` tag in the sub-components, it will go to the current instance of the component (that is, `this`) to find the corresponding property. Then according to the current location, the data will pass to the positions one by one.\\r\\n\\r\\nThe results are as follows:\\r\\n\\r\\n![group-data results](http://images2015.cnblogs.com/blog/105416/201702/105416-20170216110701535-1698390390.png)\\r\\n\\r\\nClick me for the group-data example\\r\\n\\r\\nSimilarly, `group-data` supports the mapping of complex data types. It should be noted that the end of the group-data mapping must be an array:\\r\\n\\r\\n```js\\r\\nimport Hello from \'./hello.js\';\\r\\n\\r\\n\\r\\nOmi.makeHTML(\'Hello\', Hello);\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.complexData ={\\r\\n a:{\\r\\n b:{\\r\\n c:[\\r\\n {\\r\\n e:[{\\r\\n name:\'ComplexData Support1\'\\r\\n },{\\r\\n name:\'ComplexData Support2\'\\r\\n }]\\r\\n },\\r\\n {\\r\\n name: \'ComplexData Support3\'\\r\\n }\\r\\n ]\\r\\n }\\r\\n }\\r\\n };\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nClick me for the complex group-data mapping\\r\\n\\r\\n### By object instance\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n this.hello.data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\n### By omi-id\\r\\n\\r\\n```js\\r\\n...\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n \\r\\n installed(){\\r\\n Omi.get(\\"hello\\").data.name = \\"Omi\\";\\r\\n this.update()\\r\\n }\\r\\n \\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\"#container\\");\\r\\n```\\r\\n\\r\\nBy declaring `omi-id` on the component, we can get the instance of the object anywhere in the program. This can be regarded as any component communication artifacts.\\r\\n\\r\\n### Warm Tips\\r\\n\\r\\n- The data that passed by `childrenData` or `data` is shadow copied to sub-components. In order to update it, we need to update the `data` attribute of the component instance.\\r\\n- The data that passed by `data-*` is also shadow copied to sub-components. In order to update it, we need to update the `data` attribute of the component instance.\\r\\n- If we set the `dataFirst` property of the component instance to `false`, then `data-*` will override the `data` of component instance.\\r\\n\\r\\nFor the third tip, please checkout the pseudo-code:\\r\\n\\r\\n```js\\r\\nif(this.dataFirst){\\r\\n this.data = Object.assign({},data-✼ ,this.data);\\r\\n}else{\\r\\n this.data = Object.assign({},this.data, data-✼);\\r\\n}\\r\\n```"'},function(n,e){n.exports='module.exports = "

    Components

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is based entirely on component architecture, which allows developers to build web applications like building blocks. Everything is components, components can be nested to create new components.\\r\\n\\r\\n![Omi Components System](http://images2015.cnblogs.com/blog/105416/201702/105416-20170210093427338-1536910080.png)\\r\\n\\r\\n### Simple Components\\r\\n\\r\\nLet\'s explore a simple Todo example to learn the components system in Omi.\\r\\n\\r\\n```js\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.data.items.push(this.data.text);\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n
      {{#items}}
    • {{.}}
    • {{/items}}
    \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Todo({ items: [] ,text : \'\' }),\\"body\\");\\r\\n```\\r\\n\\r\\nThe HTML generated by the component will eventually be inserted into the body. The above example shows some of the features of Omi:\\r\\n\\r\\n- Data flow: `data` in `new Todo(data,..)` can be used directly in the template in render method.\\r\\n- Partial CSS: `h3` in `style()` only effect inside of render. It\'ll never pollute `h3` outside of this component. The same rule applies to `button`.\\r\\n- Declarative event binding: `onchange` will call `handleChange` that inside of the component. `this` refers to the current DOM element, `event` refers to the current DOM Event Object.\\r\\n- You need to manually call the `this.update()` method to update the component\\r\\n\\r\\nIt is important to note that, for more freedom and flexibility, Omi does not automatically update DOM while data changes. Developers need to call the `update` method manually.\\r\\n\\r\\nYou can also use [oba] (https://github.com/dntzhang/oba) or mobx to implement automatic updates.\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n## Component Nesting\\r\\n\\r\\nIt\'s ok to not use nesting component if your page is super simple. However, for most of webpages and web applications, it is a necessary to define the nesting Components to implement complex features.\\r\\n\\r\\nFor instance, we can extract a `List` component form the Todo example. This brings maintainable, scalable and reuseable to our project:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
      {{#items}}
    • {{.}}
    • {{/items}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nThen how to use this `List`? We need to use `Omi.makeHTML` to make the `List` to a tag which can be used in render method:\\r\\n\\r\\n```js\\r\\nimport List from \'./list.js\';\\r\\n\\r\\nOmi.makeHTML(\'List\', List);\\r\\n\\r\\nclass Todo extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n this.data.length = this.data.items.length;\\r\\n this.listData = { items : this.data.items };\\r\\n }\\r\\n\\r\\n add (evt) {\\r\\n evt.preventDefault();\\r\\n this.list.data.items.push(this.data.text);\\r\\n this.data.length = this.list.data.items.length;\\r\\n this.data.text = \'\';\\r\\n this.update();\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h3 { color:red; }\\r\\n button{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n this.data.text = target.value;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    TODO

    \\r\\n \\r\\n
    \\r\\n \\r\\n \\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n- In line 3, we use `makeHTML` to make the component to a tag which can be used in render method. Of course, `Omi.makeHTML(\'List\', List);` can also be written in the end of List component.\\r\\n- In line 9, the parent component defines the \'listData\' property\\r\\n- In line 34, we use List component in the render method. `name` attribute allows us easily find the instance of the component by using `this`.`data=\\"listData\\"` attribute allows us easily pass `this.listData` to the sub component from parent component.\\r\\n\\r\\nIt should be noted that the `data` passed from `data=\\"listData\\"` is cloned to the subcomponents by Object.assign(shallow copy) , which means if we want to change the DOM, we recommend that first update the `data` of the instance of subcomponent(not the parent component\'s `listData` ) and secondly call the `update` method.\\r\\n\\r\\nIn fact there are 4 way to communicate between components, it\'ll be explained later.\\r\\n\\r\\nClick me for the live demo\\r\\n"'},function(n,e){n.exports="module.exports = \"

    Conditional Rendering

    \\r\\n\\r\\nIn most case, we need to show different layouts according to different states. For example, some users are vip and we need to show vip logo for them. Omi has many ways to meet this kind of requirements.\\r\\n\\r\\n### First Option\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `{{#isVip}}\\r\\n
    you are VIP.
    \\r\\n {{/isVip}}\\r\\n {{^isVip}}\\r\\n
    you are not VIP.
    \\r\\n {{/isVip}}`;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nIn the above case, we use the condition in mustachejs for rendering. Of course Omi does not force you to use mustachejs. You can use omi.lite.js and then override the `Omi.template` method to use any of your favorite template engines.\\r\\n\\r\\n### Second Option\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n`render` provides a very good programmability, which can write any js code inside. Oh, don't forget that `style` method can also have js code inside it.\\r\\n\\r\\n```js\\r\\nclass ConditionTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style (){\\r\\n if(this.data.isVip){\\r\\n return 'div{ color : red; }';\\r\\n }else{\\r\\n return 'div{ color : green; }';\\r\\n }\\r\\n }\\r\\n\\r\\n render () {\\r\\n if(this.data.isVip){\\r\\n return '
    you are VIP.
    ';\\r\\n }else{\\r\\n return '
    you are not VIP.
    ';\\r\\n }\\r\\n }\\r\\n}\\r\\n```\""},function(n,e){n.exports='module.exports = "

    Handling Events

    \\r\\n\\r\\nThere are two types of events in Omi, built-in events and custom events. Built-in events clever use of the browser\'s own pipeline mechanism, you can easily get events instance and the triggered event elements through `event` and `this`.\\r\\n\\r\\n### Built-in events\\r\\n\\r\\nWhat is the built-in event? As long as the it can match the following regular expression.\\r\\n\\r\\n```js\\r\\non(abort|blur|cancel|canplay|canplaythrough|change|click|close|contextmenu|cuechange|dblclick|drag|dragend|dragenter|dragleave|dragover|dragstart|drop|durationchange|emptied|ended|error|focus|input|invalid|keydown|keypress|keyup|load|loadeddata|loadedmetadata|loadstart|mousedown|mouseenter|mouseleave|mousemove|mouseout|mouseover|mouseup|mousewheel|pause|play|playing|progress|ratechange|reset|resize|scroll|seeked|seeking|select|show|stalled|submit|suspend|timeupdate|toggle|volumechange|waiting|autocomplete|autocompleteerror|beforecopy|beforecut|beforepaste|copy|cut|paste|search|selectstart|wheel|webkitfullscreenchange|webkitfullscreenerror|touchstart|touchmove|touchend|touchcancel|pointerdown|pointerup|pointercancel|pointermove|pointerover|pointerout|pointerenter|pointerleave)\\r\\n```\\r\\n\\r\\nHow to bind built-in events? As follows:\\r\\n\\r\\n```js\\r\\nclass EventTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n handleClick(dom, evt){\\r\\n alert(dom.innerHTML);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Hello, Omi!
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### Custom events\\r\\n\\r\\nEvents that defined by developers is the custom events. Here is the pagination example:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\nimport Pagination from \'./pagination.js\';\\r\\nimport Content from \'./content.js\';\\r\\n\\r\\nOmi.makeHTML(\'Pagination\', Pagination);\\r\\nOmi.makeHTML(\'Content\', Content);\\r\\n\\r\\nclass Main extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.content.goto(this.pagination.data.currentPage+1);\\r\\n }\\r\\n handlePageChange(index){\\r\\n this.content.goto(index+1);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n

    Pagination Example

    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render( new Main(),\'body\');\\r\\n```\\r\\n\\r\\nAs we can see, the `onPageChange` is a custom event, `handlePageChange` will being executed when `onPageChange` is triggered. The `onPageChange` method is executed in `Pagination`:\\r\\n\\r\\n```js\\r\\nimport Omi from \'../../src/index.js\';\\r\\n\\r\\nclass Pagination extends Omi.Component {\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n linkTo: \\"#\\",\\r\\n prevText: \\"Prev\\",\\r\\n nextText: \\"Next\\",\\r\\n ellipseText: \\"...\\",\\r\\n prevShow: true,\\r\\n nextShow: true,\\r\\n onPageChange: function () { return false; }\\r\\n }, this.data);\\r\\n\\r\\n this.pageNum = Math.ceil(this.data.total / this.data.pageSize);\\r\\n }\\r\\n goto (index,evt) {\\r\\n evt.preventDefault();\\r\\n this.data.currentPage=index;\\r\\n this.update();\\r\\n this.data.onPageChange(index);\\r\\n }\\r\\n ...\\r\\n ...\\r\\n ...\\r\\n}\\r\\n```\\r\\n\\r\\nThis is a part of `Pagination` code. Highlight is the place to execute `onPageChange`.\\r\\n\\r\\n### Links\\r\\n\\r\\n- [Demo](http://alloyteam.github.io/omi/example/pagination/)\\r\\n- [Source](https://github.com/AlloyTeam/omi/tree/master/example/pagination)"'},function(n,e){n.exports='module.exports = "

    Forms

    \\r\\n\\r\\nIt\'s much more convenient to control forms in Omi, especially `\\r\\n \\r\\n \\r\\n \\r\\n \\r\\n\\r\\n```\\r\\n\\r\\nThe third option is selected because it is being set to `selected` attribute. The problem is that developers need to traversed each option. While using Omi, you can write code like this:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\nThis will achieve the same effect. For example, you want to choose the first item:\\r\\n\\r\\n```html\\r\\n\\r\\n```\\r\\n\\r\\nIsn\'t it very convenient?\\r\\n\\r\\n### For Example\\r\\n\\r\\n```js\\r\\nclass FormTest extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n \\r\\n }\\r\\n\\r\\n handleChange(target){\\r\\n console.log(target.value)\\r\\n this.data.value = target.value;\\r\\n }\\r\\n\\r\\n handleSubmit(evt) {\\r\\n alert(\'Your favorite flavor is: \' + this.data.value);\\r\\n evt.preventDefault();\\r\\n }\\r\\n \\r\\n render () {\\r\\n return `\\r\\n
    \\r\\n \\r\\n \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new FormTest({ value: \'mango\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for a live demo"'},function(n,e){n.exports='module.exports = "

    Get DOM

    \\r\\n\\r\\nWhile most of the time, developers do not need to find the DOM, but sometimes is a need to get the DOM.\\r\\n\\r\\nOmi provides a way to get the DOM node.\\r\\n\\r\\n### ref and refs\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(){\\r\\n alert(this.refs.abc.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"#container\\");\\r\\n```\\r\\n\\r\\nAs we can see, by referencing `ref` as `abc` in HTML, the DOM node can be accessed through `this.refs.abc`.\\r\\n\\r\\nClick me for the live demo\\r\\n"'},function(n,e){n.exports='module.exports = "

    Hello World

    \\r\\n\\r\\n\\r\\n### Hello World with ES20XX \\r\\n\\r\\nWe recommend using a bundler like [webpack](https://webpack.github.io/) or [Browserify](http://browserify.org/) so you can write modular code and bundle it together into small packages to optimize load time.\\r\\n\\r\\nThe small Omi example looks like this:\\r\\n\\r\\n```js\\r\\nimport Omi from \'./omi.js\';\\r\\n\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n h1{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n

    Hello ,{{name}}!

    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new Hello({ name : \\"Omi\\" }),\\"body\\");\\r\\n\\r\\n```\\r\\n\\r\\nThis code renders into body element. \\r\\n\\r\\n\\r\\n### Hello World with ES5\\r\\n\\r\\n\\r\\n```html\\r\\n\\r\\n```"'},function(n,e){n.exports='module.exports = "

    Inheritance

    \\r\\n\\r\\nThrough the inheritance mechanism, we can define new classes base on old classes. The new classes not only have newly defined members, but also have old members at the same time.\\r\\n\\r\\nWe call the existing class the base class, also known as the parent class. And the new class derived from the existing class is called a derived class, also known as a subclass.\\r\\n\\r\\n### For Example\\r\\n\\r\\n```js\\r\\nclass Hello extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n style () {\\r\\n return `\\r\\n div{\\r\\n cursor:pointer;\\r\\n }\\r\\n `;\\r\\n }\\r\\n handleClick(target, evt){\\r\\n alert(target.innerHTML);\\r\\n }\\r\\n render() {\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n}\\r\\n\\r\\nclass SubHello extends Hello {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n### inherit in ES5\\r\\n\\r\\n```js\\r\\nvar Hello = Omi.create(\\"Hello\\",{\\r\\n render:function(){\\r\\n return \'
    Hello {{name}}!
    \'\\r\\n }\\r\\n})\\r\\n\\r\\nvar SubHello = Omi.create(\\"SubHello\\",Hello,{ });\\r\\n\\r\\n\\r\\nOmi.render(new SubHello({ name : \'Omi\' }),\'#container\');\\r\\n```\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports='module.exports = "

    Installation

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is open and modern framework for building user interfaces.\\r\\n\\r\\n### Installing Omi\\r\\n\\r\\nWe recommend using [npm](https://www.npmjs.com/) for managing front-end dependencies. If you\'re new to package managers.\\r\\n\\r\\nTo install Omi with npm, run:\\r\\n\\r\\n``` js\\r\\nnpm install omi\\r\\n```\\r\\n### omi-cli\\r\\n\\r\\n``` js\\r\\n$ npm install omi-cli -g \\r\\n$ omi init your_project_name \\r\\n$ cd your_project_name \\r\\n$ npm run dev \\r\\n$ npm run dist \\r\\n```"'; +},function(n,e){n.exports='module.exports = "

    Lifecycle

    \\r\\n\\r\\n| Name | Meaning | Occasion |\\r\\n| :-------------: | :-------------: | :-----: |\\r\\n| constructor | The constructor | When new a constructor |\\r\\n| install | The installation. We can process the data that user pass | When instantiate |\\r\\n| installed | Complete the installation. It\'ll trigger after HTML being inserted to the page. Please note that it\'ll trigger when component being removed and restored | **Instantiation and existence** |\\r\\n| uninstall | Uninstall the component. It\'ll trigger when remove is executed | When destroy |\\r\\n| beforeUpdate | Before update | When existence |\\r\\n| afterUpdate | After update | When existence |\\r\\n\\r\\n## Illustration\\r\\n\\r\\n![lc](http://images2015.cnblogs.com/blog/105416/201701/105416-20170119153018546-1566368987.png)\\r\\n\\r\\nIt should be noted that the installed will be executed during the instantiation, which is not shown above. For example, it\'ll executed when a component is removed and restored, or when the new component is being added.\\r\\n\\r\\n### Examples\\r\\n\\r\\n```js\\r\\nclass Timer extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n install () {\\r\\n this.data = {secondsElapsed: 0};\\r\\n }\\r\\n\\r\\n tick() {\\r\\n this.data.secondsElapsed++;\\r\\n this.update();\\r\\n }\\r\\n\\r\\n installed(){\\r\\n this.interval = setInterval(() => this.tick(), 1000);\\r\\n }\\r\\n\\r\\n uninstall() {\\r\\n clearInterval(this.interval);\\r\\n }\\r\\n\\r\\n\\r\\n style () {\\r\\n return `\\r\\n .num { color:red; }\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    Seconds Elapsed: {{secondsElapsed}}
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports='module.exports = "

    Loop

    \\r\\n\\r\\nThe following describes how to traverses in mustache.js and javascript.\\r\\n\\r\\n### First Option\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `
    \\r\\n
      \\r\\n {{#items}} \\r\\n
    • {{text}}
    • \\r\\n {{/items}}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nMustache.js more detailed loop traversal use can see \\r\\n\\r\\nFor more details for traversal in mustache.js please view [https://github.com/janl/mustache.js#non-empty-lists](https://github.com/janl/mustache.js#non-empty-lists).\\r\\n\\r\\nFor example, it also support:\\r\\n\\r\\n- If each item of items is a string, you can directly use **{{.}}** to output each item\\r\\n- Call the defined function when looping\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n### Second Option\\r\\n\\r\\nOf course, you can also use template string inside the `map`:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `
    \\r\\n
      \\r\\n ${this.data.items.map(item =>\\r\\n `
    • ${item.text}
    • `\\r\\n ).join(\'\')}\\r\\n
    \\r\\n
    `;\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new List({\\r\\n items: [\\r\\n {id: 1, text: \'Omi\'},\\r\\n {id: 2, text: \'dntzhang\'},\\r\\n {id: 3, text: \'AlloyTeam\'}\\r\\n ]\\r\\n}),\\"body\\");\\r\\n```\\r\\n\\r\\nYou will see the following page:\\r\\n\\r\\n![pv](http://images2015.cnblogs.com/blog/105416/201701/105416-20170122095724129-2059595233.png)\\r\\n\\r\\nClick me for the live demo"'},function(n,e){n.exports="module.exports = \"

    Plugin

    \\r\\n\\r\\n[Omi](https://github.com/AlloyTeam/omi) is a componentized web framework. Then what is plugin?\\r\\n\\r\\nIt can be understood that the Omi plugin system can give the dom element some ability and can be associated with the instance of the components.\\r\\n\\r\\n### omi-drag\\r\\n\\r\\nLet's see this example:\\r\\n\\r\\nClick me for the live deme\\r\\n\\r\\n```js\\r\\nimport OmiDrag from './omi-drag.js';\\r\\n\\r\\nOmiDrag.init();\\r\\n\\r\\nclass App extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n render() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n\\r\\n }\\r\\n\\r\\n style(){\\r\\n return `\\r\\n .test{\\r\\n width:100px;\\r\\n height:100px;\\r\\n color:white;\\r\\n line-height:90px;\\r\\n text-align:center;\\r\\n background-color:#00BFF3;\\r\\n }\\r\\n `\\r\\n }\\r\\n}\\r\\n\\r\\nOmi.render(new App(),\\\"#container\\\");\\r\\n```\\r\\n\\r\\nAs shown above, by adding `omi-drag` attribute to the div, it can be dragged by the user using the mouse. We call omi-drag.js an omi plugin.\\r\\n\\r\\nIsn't it very convenient? So how did this omi-drag implement?\\r\\n\\r\\n如上面的代码所示,通过在div上标记omi-drag,这个div就能够被用户使用鼠标拖拽。我们称omi-drag.js为omi插件。\\r\\n是不是非常方便?那么这个omi-drag是怎么实现的?\\r\\n\\r\\n## Omi.extendPlugin\\r\\n\\r\\nCore method: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\nThe following code shows how to use `Omi.extendPlugin` to give dom the drap and drop ability:\\r\\n\\r\\n```js\\r\\n;(function () {\\r\\n\\r\\n var OmiDrag = {};\\r\\n var Omi = typeof require === 'function'\\r\\n ? require('omi')\\r\\n : window.Omi;\\r\\n\\r\\n OmiDrag.init = function(){\\r\\n Omi.extendPlugin('omi-drag',function(dom, instance){\\r\\n dom.style.cursor='move';\\r\\n var isMouseDown = false,\\r\\n preX = null,\\r\\n preY = null,\\r\\n currentX = null,\\r\\n currentY = null,\\r\\n translateX = 0,\\r\\n translateY = 0;\\r\\n\\r\\n dom.addEventListener('mousedown',function(evt){\\r\\n isMouseDown = true;\\r\\n preX = evt.pageX;\\r\\n preY = evt.pageY;\\r\\n evt.stopPropagation();\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n }\\r\\n },false);\\r\\n\\r\\n window.addEventListener('mouseup',function(){\\r\\n isMouseDown = false;\\r\\n preX = preY = currentX = currentY = null;\\r\\n },false);\\r\\n });\\r\\n }\\r\\n\\r\\n OmiDrag.destroy = function(){\\r\\n delete Omi.plugins['omi-drag'];\\r\\n };\\r\\n\\r\\n if (typeof exports == \\\"object\\\") {\\r\\n module.exports = OmiDrag;\\r\\n } else if (typeof define == \\\"function\\\" && define.amd) {\\r\\n define([], function(){ return OmiDrag });\\r\\n } else {\\r\\n window.OmiDrag = OmiDrag;\\r\\n }\\r\\n\\r\\n})();\\r\\n```\\r\\n\\r\\nMethod: Omi.extendPlugin( pluginName, handler )\\r\\n\\r\\n`pluginName` is the name of the plugin.\\r\\n\\r\\n`handler` is the processor. The handler can get the dom which marked as the `pluginName` and the instance of the component.\\r\\n\\r\\nWith `Omi.extendPlugin`, we can give the dom some ability, and can also be associated with the component instance.\\r\\n\\r\\nThe above example is not associated with the instance, let's try it:\\r\\n\\r\\n## Associated with instance\\r\\n\\r\\nWe want to be able to listen to the `move` inside the component and perform a callback. As follows:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandler(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nIn this case, the `moveHandler` will be continually executed while dragging. We can modify some code to solve this issue:\\r\\n\\r\\n```js\\r\\n...\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance.moveHandler(evt);\\r\\n }\\r\\n},false);\\r\\n```\\r\\n\\r\\nWe add `instance.moveHandler(evt)` method to execute the `moveHandler` method of component instance.\\r\\n\\r\\nThis is how associated with instance works.\\r\\n\\r\\nHowever, this may still have an issue if we add `omi-drag` to a list of `div`:\\r\\n\\r\\n```js\\r\\n...\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me
    \\r\\n
    Drag Me
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nUsually each of our `omi-drag` can correspond to a callback function, such as:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nHow to achieve this? We can pass the data to the plugin via dom.\\r\\n\\r\\n## Passing data\\r\\n\\r\\nLet's see the final code:\\r\\n\\r\\n```js\\r\\n...\\r\\n...\\r\\nmoveHandlerA(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nmoveHandlerB(){\\r\\n console.log('moving');\\r\\n}\\r\\n\\r\\nrender() {\\r\\n return `\\r\\n
    \\r\\n
    Drag Me A
    \\r\\n
    Drag Me B
    \\r\\n
    \\r\\n `;\\r\\n}\\r\\n...\\r\\n```\\r\\n\\r\\nWhere `omi-drag` modified:\\r\\n\\r\\n```js\\r\\n...\\r\\nvar handlerName = dom.getAttribute('dragMove');\\r\\n\\r\\nwindow.addEventListener('mousemove',function(evt){\\r\\n if(isMouseDown){\\r\\n currentX = evt.pageX;\\r\\n currentY = evt.pageY;\\r\\n if(preX != null){\\r\\n translateX += currentX - preX;\\r\\n translateY += currentY - preY;\\r\\n dom.style.transform = 'translateX('+translateX+'px) translateY('+translateY+'px)';\\r\\n }\\r\\n preX = currentX;\\r\\n preY = currentY;\\r\\n evt.preventDefault();\\r\\n instance[handlerName](evt);\\r\\n }\\r\\n},false);\\r\\n...\\r\\n```\\r\\n\\r\\n- We use `var handlerName = dom.getAttribute('dragMove')` to get the `dragMove` of dom\\r\\n- We use `instance[handlerName](evt)` to execute the method\\r\\n\\r\\nClick me for the live demo\\r\\n\\r\\n## More plugins\\r\\n\\r\\n* [omi-finger](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-finger) The [AlloyFinger](https://github.com/AlloyTeam/AlloyFinger) plugin for Omi, which support touch events and gustures\\r\\n* [omi-transform](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-transform) The [transformjs](http://alloyteam.github.io/AlloyTouch/transformjs/) plugin for Omi, which can easily set CSS3 Transform to DOM\\r\\n* [omi-touch](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-touch) The [AlloyTouch](https://github.com/AlloyTeam/AlloyTouch) plugin for Omi. The touch movement solution for Omi (support touch scroll, rotate, flip, select, etc.)\\r\\n* [omi-jquery-date-picker](https://github.com/AlloyTeam/omi/tree/master/plugins/omi-jquery-date-picker) The date picker plugin for Omi, which support choose any time zone\\r\\n\""},function(n,e){n.exports='module.exports = "

    Templates

    \\r\\n\\r\\nThere are three types of Omi. omi.js and omi.lite.js is for web side.\\r\\n\\r\\n- omi.js has a built-in [mustache.js](https://github.com/janl/mustache.js) as the template engine\\r\\n- omi.lite.js doesn\'t have any template engines\\r\\n\\r\\nOmi does not force developers to use mustache.js, you can use any template engine based on business scenarios or do not use any template engines.\\r\\n\\r\\nHow to use other template engines? Let\'s see the [artTemplate](https://github.com/aui/artTemplate) example.\\r\\n\\r\\n### Use artTemplate\\r\\n\\r\\n```js\\r\\nOmi.template = function(tpl, data){\\r\\n return artTemplate.compile(tpl)(data);\\r\\n}\\r\\n```\\r\\n\\r\\nWe need to rewrite the `Omi.template` method, the `tpl` is the incoming template, the `data` is the required data for the template, and the return value is HTML.\\r\\n\\r\\nAfter rewriting, you can use the artTemplate syntax in `render`, such as:\\r\\n\\r\\n```js\\r\\nclass List extends Omi.Component {\\r\\n constructor(data) {\\r\\n super(data);\\r\\n }\\r\\n\\r\\n style () {\\r\\n return `\\r\\n h1 { color:red; }\\r\\n li{ color:green;}\\r\\n `;\\r\\n }\\r\\n\\r\\n render () {\\r\\n return `

    {{title}}

    \\r\\n
      \\r\\n {{each list as value i}}\\r\\n
    • # {{i + 1}} :{{value}}
    • \\r\\n {{/each}}\\r\\n
    `;\\r\\n }\\r\\n}\\r\\n```\\r\\n\\r\\n### Links\\r\\n\\r\\n* [Demo Link](http://alloyteam.github.io/omi/example/artTemplate/)\\r\\n* [Source Code](https://github.com/AlloyTeam/omi/tree/master/example/artTemplate)"'},function(n,e){n.exports='module.exports = "

    Thinking in Omi

    \\r\\n\\r\\nOmi is based on object-oriented programming, with plugin system.\\r\\n\\r\\nThe traditional one-way data flow or the event-throwing component communicating can increase the stability of the system, but it loses it\'s flexibility. To a certain extent also reduced the component reusing.\\r\\n\\r\\nObject-oriented system has an other logical layer, which let you control the instance of components. The logic between instances build the entire program.\\r\\n\\r\\nThen the issues like communication, reusing and logics between components are all solved.\\r\\n\\r\\n\\r\\nPlus, the component is also more single duty, more loosely coupled.\\r\\n\\r\\nFor functional programming, imperative programming and object-oriented programming, we can sum up the following list:\\r\\n\\r\\n- Imperative programming is well understood, we use loop and if-else condition to control processes, it emphasize the process of execution\\r\\n- Imperative programming is hardware friendly, easy to run, but hard to design complex program\\r\\n- Functional programming is all about input and output, not the process of execution\\r\\n- Functional programming advocates multiple simple execution units into complex operations\\r\\n- Object-oriented programming uses objects as the basic unit of the program, with more reusability, flexibility, and extensibility\\r\\n\\r\\nWhat kind of language is JavaScript? We have `class` in ES6+, so is JavaScript object-oriented language?\\r\\n\\r\\nJavaScript can pass a function as a argumant, so is JavaScript a functional language?\\r\\n\\r\\nThere are no right answer, it depands on how you use JavaScript.\\r\\n\\r\\nIt\'s free to chooce, you can use functional programming framework like React, or object-oriented framework like Omi. \\r\\n\\r\\n### Functional Programming VS Object-Oriented Programming\\r\\n\\r\\nIn the UI component framework scope, functional programming is represented by React, while Omi belongs to object-oriented programming.\\r\\n\\r\\nSo what are their strengths and weaknesses? The following is a comparison (in fact, functional programming and object-oriented programming comparison):\\r\\n\\r\\n| | React | Omi |\\r\\n| ------------- |:-------------:|:-----:|\\r\\n| Component communication | ★★★★☆| ★★★★★ |\\r\\n| Stability | ★★★★★ | ★★★★☆ |\\r\\n| Flexibility | ★★★★☆| ★★★★★ |\\r\\n| Scalability | ★★★★☆ | ★★★★★ |\\r\\n| Testability | ★★★★★ | ★★★★☆ |\\r\\n| File size | ★★★☆☆ | ★★★★★ |\\r\\n| Features | ★★★☆☆ | ★★★★☆ |\\r\\n| DOM performance | ★★★★★ | ★★★★☆ |\\r\\n| Animation performance | ★★★★☆ | ★★★★★ |\\r\\n| Abstract complexity | ★★★★☆ | ★★★★★ |\\r\\n| Asynchronous programming | ★★★★★ | ★★★★☆ |\\r\\n\\r\\nAs we can see, we can not have it both ways. Object-oriented programming is more reusable, flexible and scalable, the problem is more difficult to test.\\r\\n\\r\\nSpecifically, if the functional programming, the test area is state1 + state2 + ... + stateN; in object-oriented programming, the test area is state1 × event1 + state2 × event2 + ... + stateN × eventN.\\r\\n\\r\\nIn summary, it is more recommended to use the object-oriented programming to build UI component framework.\\r\\n\\r\\n
    \\r\\n\\r\\n### The end. Thanks for reading. [Let\'s start the Omi journey](https://github.com/AlloyTeam/omi)!\\r\\n"'},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n @media only screen and (max-width: 768px) {\n .list{\n transform: translateX(-100%);\n background-color:white;\n\n -moz-transition: all .6s ease;\n -o-transition: all .6s ease;\n -webkit-transition: all .6s ease;\n transition: all .6s ease;\n }\n\n .list.show {\n -moz-transform: translateX(0%) translateZ(0);\n -ms-transform: translateX(0%) translateZ(0);\n -o-transform: translateX(0%) translateZ(0);\n -webkit-transform: translateX(0%) translateZ(0);\n transform: translateX(0%) translateZ(0);\n }\n }\n\n .list{\n width:200px;\n text-indent: 20px;\n border-right: 1px solid #eee;\n overflow-x: hidden;\n overflow-y: auto;\n position:fixed;\n top:45px;\n }\n .version{\n height:20px;\n }\n \n "}},{key:"render",value:function(){return'\n
    \n
    \n {{#items}} {{/items}}\n
    '}}]),e}(d.default.Component);e.default=h},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n
  • {{title}}
  • \n {{#list}}\n
  • \n {{name}}\n
  • \n {{/list}}\n '}},{key:"style",value:function(){return"\n \n "}}]),e}(d.default.Component);e.default=c},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n .head{\n position:fixed;\n height:45px;\n line-height: 45px;\n border-bottom: 1px solid #eee;\n width:100%;\n background-color:#303030;\n z-index:100;\n\n }\n ul,li{\n display: inline-block;\n }\n .logo_box{\n width:100px;\n display: inline-block;\n text-align:center;\n line-height: 60px;\n }\n .menu a,.logo_box a{\n display: inline-block;\n height:45px;\n color:#ddd;\n }\n .menu{\n position: absolute;\n right:20px;\n }\n .menu li{\n margin-left:15px;\n }\n .logo_box a{\n font-size: 34px;\n font-weight: bold;\n color: #00bff3;\n padding: 0px 15px;\n line-height: 45px;\n cursor: pointer;\n }\n .menu a:hover{\n color: white;\n }\n\n .m_menu{\n position:fixed;\n display:none;\n }\n\n @media only screen and (max-width: 768px) {\n .menu li{\n display:none;\n }\n .menu .m_show{\n display:block;\n }\n\n .logo_box{\n display:inline-block;\n }\n\n .head{\n text-align:center;\n }\n\n .m_menu{\n\n top:0;\n left:0;\n display:block;\n width:50px;\n height:50px;\n padding-top: 6px;\n }\n .m_menu img{\n width:30px;\n }\n\n }\n \n "}},{key:"render",value:function(){return'\n
    \n \n
    \n Omi\n
    \n \n
    '}}]),e}(d.default.Component);e.default=m},function(n,e,r){var t,i,o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(){var a={},s=r(52),l=r(2),d=function(){},c=function(n,e,r){var t="on"+n.substring(0,1).toUpperCase()+n.substring(1),i=e.getAttribute(t);return null===i?d:r[i].bind(r)};a.init=function(){l.extendPlugin("omi-finger",function(n,e){e.alloyFinger&&e.alloyFinger.destroy();var r=new s(n,{touchStart:c("touchStart",n,e),touchMove:c("touchMove",n,e),touchEnd:c("touchEnd",n,e),touchCancel:c("touchCancel",n,e),multipointStart:c("multipointStart",n,e),multipointEnd:c("multipointEnd",n,e),tap:c("tap",n,e),doubleTap:c("doubleTap",n,e),longTap:c("longTap",n,e),singleTap:c("singleTap",n,e),rotate:c("rotate",n,e),pinch:c("pinch",n,e),pressMove:c("pressMove",n,e),swipe:c("swipe",n,e)});e.alloyFinger=r})},a.destroy=function(){delete l.plugins["omi-finger"]},"object"==o(e)?n.exports=a:(t=[],i=function(){return a}.apply(e,t),!(void 0!==i&&(n.exports=i)))}()},function(n,e,r){"use strict";var t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};!function(){function r(n){return Math.sqrt(n.x*n.x+n.y*n.y)}function i(n,e){return n.x*e.x+n.y*e.y}function o(n,e){var t=r(n)*r(e);if(0===t)return 0;var o=i(n,e)/t;return o>1&&(o=1),Math.acos(o)}function a(n,e){return n.x*e.y-e.x*n.y}function s(n,e){var r=o(n,e);return a(n,e)>0&&(r*=-1),180*r/Math.PI}function l(n,e){var r=new d(n);return r.add(e),r}var d=function(n){this.handlers=[],this.el=n};d.prototype.add=function(n){this.handlers.push(n)},d.prototype.del=function(n){n||(this.handlers=[]);for(var e=this.handlers.length;e>=0;e--)this.handlers[e]===n&&this.handlers.splice(e,1)},d.prototype.dispatch=function(){for(var n=0,e=this.handlers.length;n0&&this.delta<=250&&Math.abs(this.preTapPosition.x-this.x1)<30&&Math.abs(this.preTapPosition.y-this.y1)<30),this.preTapPosition.x=this.x1,this.preTapPosition.y=this.y1,this.last=this.now;var e=this.preV,t=n.touches.length;if(t>1){this._cancelLongTap(),this._cancelSingleTap();var i={x:n.touches[1].pageX-this.x1,y:n.touches[1].pageY-this.y1};e.x=i.x,e.y=i.y,this.pinchStartLen=r(e),this.multipointStart.dispatch(n)}this.longTapTimeout=setTimeout(function(){this.longTap.dispatch(n)}.bind(this),750)}},move:function(n){if(n.touches){var e=this.preV,t=n.touches.length,i=n.touches[0].pageX,o=n.touches[0].pageY;if(this.isDoubleTap=!1,t>1){var a={x:n.touches[1].pageX-i,y:n.touches[1].pageY-o};null!==e.x&&(this.pinchStartLen>0&&(n.scale=r(a)/this.pinchStartLen,this.pinch.dispatch(n)),n.angle=s(a,e),this.rotate.dispatch(n)),e.x=a.x,e.y=a.y}else null!==this.x2?(n.deltaX=i-this.x2,n.deltaY=o-this.y2):(n.deltaX=0,n.deltaY=0),this.pressMove.dispatch(n);this.touchMove.dispatch(n),this._cancelLongTap(),this.x2=i,this.y2=o,t>1&&n.preventDefault()}},end:function(n){if(n.changedTouches){this._cancelLongTap();var e=this;n.touches.length<2&&this.multipointEnd.dispatch(n),this.touchEnd.dispatch(n),this.x2&&Math.abs(this.x1-this.x2)>30||this.y2&&Math.abs(this.preV.y-this.y2)>30?(n.direction=this._swipeDirection(this.x1,this.x2,this.y1,this.y2),this.swipeTimeout=setTimeout(function(){e.swipe.dispatch(n)},0)):(this.tapTimeout=setTimeout(function(){e.tap.dispatch(n),e.isDoubleTap&&(e.doubleTap.dispatch(n),clearTimeout(e.singleTapTimeout),e.isDoubleTap=!1)},0),e.isDoubleTap||(e.singleTapTimeout=setTimeout(function(){e.singleTap.dispatch(n)},250))),this.preV.x=0,this.preV.y=0,this.scale=1,this.pinchStartLen=null,this.x1=this.x2=this.y1=this.y2=null}},cancel:function(n){clearTimeout(this.tapTimeout),clearTimeout(this.singleTapTimeout),clearTimeout(this.longTapTimeout),clearTimeout(this.swipeTimeout),this.touchCancel.dispatch(n)},_cancelLongTap:function(){clearTimeout(this.longTapTimeout)},_cancelSingleTap:function(){clearTimeout(this.singleTapTimeout)},_swipeDirection:function(n,e,r,t){return Math.abs(n-e)>=Math.abs(r-t)?n-e>0?"Left":"Right":r-t>0?"Up":"Down"},on:function(n,e){this[n]&&this[n].add(e)},off:function(n,e){this[n]&&this[n].del(e)},destroy:function(){return this.tapTimeout&&clearTimeout(this.tapTimeout),this.singleTapTimeout&&clearTimeout(this.singleTapTimeout),this.longTapTimeout&&clearTimeout(this.longTapTimeout),this.swipeTimeout&&clearTimeout(this.swipeTimeout),this.element.removeEventListener("touchstart",this.start),this.element.removeEventListener("touchmove",this.move),this.element.removeEventListener("touchend",this.end),this.element.removeEventListener("touchcancel",this.cancel),this.rotate.del(),this.touchStart.del(),this.multipointStart.del(),this.multipointEnd.del(),this.pinch.del(),this.swipe.del(),this.tap.del(),this.doubleTap.del(),this.longTap.del(),this.singleTap.del(),this.pressMove.del(),this.touchMove.del(),this.touchEnd.del(),this.touchCancel.del(),this.preV=this.pinchStartLen=this.scale=this.isDoubleTap=this.delta=this.last=this.now=this.tapTimeout=this.singleTapTimeout=this.longTapTimeout=this.swipeTimeout=this.x1=this.x2=this.y1=this.y2=this.preTapPosition=this.rotate=this.touchStart=this.multipointStart=this.multipointEnd=this.pinch=this.swipe=this.tap=this.doubleTap=this.longTap=this.singleTap=this.pressMove=this.touchMove=this.touchEnd=this.touchCancel=null,null}},"undefined"!=typeof n&&"object"===t(e)?n.exports=c:window.AlloyFinger=c}()},function(n,e,r){"use strict";function t(n){return n&&n.__esModule?n:{default:n}}function i(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}function o(n,e){if(!n)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?n:e}function a(n,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);n.prototype=Object.create(e&&e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(n,e):n.__proto__=e)}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function n(n,e){for(var r=0;r\n {{#preName}} ←{{preName}}{{/preName}}\n {{#nextName}} {{/nextName}}\n ':'\n
    \n {{#preName}} ←{{preName}}{{/preName}}\n {{#nextName}} {{/nextName}}\n
    '}},{key:"style",value:function(){return"\n \n "}}]),e}(d.default.Component);e.default=h}]); \ No newline at end of file