├── Design outline of QC.doc ├── README.md ├── build ├── qc.js ├── qc.js.JSCompress └── qc.min.js ├── demo ├── animate.html ├── array.html ├── bindother.html ├── colligate.html ├── event.html ├── hello.html ├── jquery-1.11.2.min.js ├── rcs.html ├── update.html ├── watch.html └── widget │ └── test.js ├── src ├── animate.js ├── commonjs.js ├── core │ ├── binddata.js │ ├── creatvm.js │ ├── dbevent.js │ ├── extent.js │ ├── head.js │ ├── ie.js │ ├── other.js │ ├── parse.js │ └── sweep.js └── event.js └── test ├── index.html ├── js └── test3.js └── mod ├── test1.js └── test2.js /Design outline of QC.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/time-go/qc/2f354c47a846c4f6690482834af8dd7be4cd04a1/Design outline of QC.doc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | ### What is qc.js? 3 | QC is a lightweight javascript framework for building complex web applications.It supports IE8+ and modern browse.All the code is only about 2000 lines.Unlike other monolithic frameworks,you can build your web applications without webpack.Simplicity is the eternal subject.If you’d like to learn more about QC before diving in,you may browse http://time-go.github.io/qc. 4 | + author:time-go@163.com 5 | + QQ Group:330603020 6 | + course and api:http://time-go.github.io/qc/ 7 | 8 | ### Code directory 9 | - build 10 | - qc.js(Merged documents) 11 | - qc.min.js(Merge compressed files) 12 | - qc.js.JSCompress(Package configuration file)) 13 | - demo (Some simple examples) 14 | - src 15 | + core(Core code directory) 16 | - animate.js(A custom animation) 17 | - commonjs.js (Module management need an ajax library) 18 | - event.js (An extended mobile terminal event) 19 | - test (Development of some test files for mode adjustment) 20 | - Design outline of QC.doc(Design outline) 21 | 22 | ### Thanks 23 | + QQ5759125 24 | + QQ1491897341 -------------------------------------------------------------------------------- /build/qc.js.JSCompress: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /build/qc.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * head.js 4 | *//** 5 | * Created by zhangyan on 2016/4/5. 6 | * 主要用于放和ie的兼容处理相关内容 7 | * ie.js 8 | *//** 9 | * Created by zhangyan on 2016/4/5. 10 | * parse.js 11 | */ 12 | /*处理表达式解析器*//** 13 | * Created by zhangyan on 2016/4/5. 14 | * creatvm.js 15 | */ 16 | 17 | /*创建虚拟节点*/ 18 | //需要依赖ie.js 19 | /** 20 | * Created by zhangyan on 2016/4/5. 21 | * other.js 22 | *//** 23 | * Created by zhangyan on 2016/4/5. 24 | * binddata.js 25 | *//** 26 | * Created by zhangyan on 2016/4/5. 27 | * sweep.js 28 | *//** 29 | * Created by zhangyan on 2016/4/5. 30 | * dbevent.js 31 | *//** 32 | * Created by zhangyan on 2016/4/5. 33 | * extent.js 34 | *//** 35 | * Created by zhangyan on 2016/4/5. 36 | * commonjs.js 37 | */ 38 | (function(e){window.qc||(window.qc={},window.qc.PREFIX="q",window.qc.fun={},window.qc.animate={})})();(function(){document.querySelectorAll||(document.querySelectorAll=function(e){var n=document.createElement("style"),b=[];document.documentElement.firstChild.appendChild(n);document._qsa=[];n.styleSheet.cssText=e+"{x-qsa:expression(document._qsa \x26\x26 document._qsa.push(this))}";window.scrollBy(0,0);for(n.parentNode.removeChild(n);document._qsa.length;)e=document._qsa.shift(),e.style.removeAttribute("x-qsa"),b.push(e);document._qsa=null;return b});document.querySelector||(document.querySelector=function(e){e=document.querySelectorAll(e);return e.length?e[0]:null});window.qclib||(window.qclib={});qclib.setTBodyInnerHTML=function(e,n){var b=document.createElement("div");for(b.innerHTML="\x3ctable\x3e\x3ctbody\x3e"+n+"\x3c/tbody\x3e\x3c/table\x3e";e.firstChild;)e.removeChild(e.firstChild);for(;0d;else if("\x3e\x3d"===a)b=b>=d;else if("\x3c"===a)b=bb?f(d[b]):"":d);return b},m={"\\\\":"\\\\"},d=function(b,a,f){for(var d=[],c=0;c/g,"\x26gt;"),b=b.replace(/\r\n/g,"\x3cbr\x3e"),b=b.replace(/\n/g,"\x3cbr\x3e"));return b};qclib.isNullObj=function(b){for(var c in b)if(b.hasOwnProperty(c))return!1;return!0};qclib.expEval=function(b,e,d,l,f){for(var a=[],g=0;gd.indexOf("$"))if(qclib.isArray(b[d]))for(a[d]=[],f=0;ff.indexOf("$")&&(a.hasOwnProperty("$"+b+"-each-"+f)?void 0!==c[f]&&a.$set(f,c[f]):void 0!==c[f]&&"object"===typeof a[f]&&"object"===typeof c[f]&&null!=c[f]&&r(a[f],c[f]));for(f in a)"function"!==typeof a[f]&&0>f.indexOf("$")&&!a.hasOwnProperty("$"+b+"-each-"+f)&&void 0!==c[f]&&"object"!==typeof a[f]&&(a[f]=c[f],a.$map&&void 0!==a.$map[f]&&p(a.$map[f]))};r(this,a);h&&h(a,k,this.$p)}else"object"===typeof f?c[a].$set(f):this[a]!==f&&(h=g(c.$path+"."+a),k=e.getModel(c[a]),this[a]=f,this.hasOwnProperty("$map")&&(a=this.$map[a],void 0!==a&&p(a,d)),h&&h(f,k,c))};for(var f in c)"function"!==typeof c[f]&&0>f.indexOf("$")&&!qclib.isArray(c[f])&&null!=c[f]&&"object"===typeof c[f]&&(c[f].$path=c.$path+"."+f,z(c[f],c))};z(c);if("#text"===a.localName)return a.nodeValue;if(void 0===d||""===d||null===d)d=e.getRandom()+"";if(e.widget.hasOwnProperty(a.localName)){var g=e.widget[a.localName];if(g.hasOwnProperty("view")&&"function"===typeof g.view){f={props:{},id:d,vDom:g.vDom,getElement:function(){return document.querySelector("["+b+'-id\x3d"'+this.id+'"]')},parent:{},updateParent:function(b,a){for(var c=this.parent[b],c=c.split("."),f=e.vms[c[0]],d=1;db&&(c.splice.apply(c,a),v.$set(r,c))};if(2==arguments.length)for(var d=a[0];db.lastIndexOf(".js")&&(b+=".js");p=e(b);"js"==c&&(p="(function(out){\n"+p.replace(/\$url:\//g,"/").replace(/\$url:/g,a),p=eval(p+"\n return out;\n"+("})({});//@ sourceURL\x3d"+b)));return p}})(); -------------------------------------------------------------------------------- /demo/animate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 动画 6 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /demo/array.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 索引: 13 | 姓名: 14 | 性别: 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/bindother.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | class style绑定 6 | 7 | 16 | 17 | 18 | 19 | 你好 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 姓名:--- 28 | 性别: 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /demo/colligate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | oooooo 17 | 18 | 19 | 20 | 张三 21 | 李四 22 | 23 | 24 | 张三: 25 | 李四: 26 | 增加 27 | 28 | 29 | () 30 | 31 | 32 | + 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /demo/event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 点击 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /demo/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /demo/rcs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 张三 12 | 李四 13 | 王五 14 | 15 | 16 | check1 17 | check2 18 | check3 19 | 20 | 21 | 22 | 23 | 张三 24 | 李四 25 | 王五 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /demo/update.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 书名: 11 | 价格:元 12 | 改变价格 13 | 更换书籍 14 | 增加数组 15 | () 16 | 17 | 18 | 19 | . 20 | 姓名: 21 | 性别: 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /demo/watch.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /demo/widget/test.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | //创建控件 3 | qc.createWidget("demo", { 4 | templete: "", 5 | view: function (vm, ve) { 6 | vm.name = "hello" 7 | window.console && console.log(this.props); 8 | var _this = this; 9 | setTimeout(function () { 10 | _this.updateParent("name", "hello"); 11 | }, 3000) 12 | }, 13 | load: function () { 14 | window.console && console.log("控件加载完毕..."); 15 | }, 16 | update: function () { 17 | window.console && console.log(this.props); 18 | } 19 | }); 20 | })() 21 | -------------------------------------------------------------------------------- /src/animate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by 张岩 on 2016/3/31. 3 | * 动画模块 4 | * animate.js 5 | */ 6 | 7 | ;(function () { 8 | /* 9 | * requestAnimationFrame兼容写法 10 | * */ 11 | var _requestAnimationFrame = (function () { 12 | return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { 13 | window.setTimeout(callback, 16) 14 | }; 15 | })(); 16 | /* 17 | * 获取运行时样式 18 | * */ 19 | var _getComputedStyle = function (obj, unit) { 20 | if (unit !== undefined) { 21 | return window.getComputedStyle(obj, null)[unit]; 22 | } else { 23 | return window.getComputedStyle(obj, null); 24 | } 25 | } 26 | 27 | /* 28 | * 简单动画函数实现 29 | * */ 30 | var animate = function (obj, config, callback) { 31 | var name = config.name; 32 | var unit = config.unit; 33 | var start = (_getComputedStyle(obj, name) + "").replace(unit, "") * 1; 34 | var end = config.value * 1; 35 | var easeOut = function (t, b, c, d) { 36 | return -c * ((t = t / d - 1) * t * t * t - 1) + b; 37 | } 38 | var t = 1; 39 | var animate = function () { 40 | if (name.indexOf("scroll") === 0) { 41 | obj[name] = easeOut(t, start, end - start, 20); 42 | } else { 43 | obj.style[name] = easeOut(t, start, end - start, 20) + unit; 44 | } 45 | t++; 46 | if (t <= 20) { 47 | _requestAnimationFrame(animate); 48 | } else { 49 | if (typeof callback === "function") { 50 | callback(); 51 | } 52 | } 53 | } 54 | _requestAnimationFrame(animate); 55 | } 56 | 57 | var hasClass = function (obj, cls) { 58 | return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')); 59 | } 60 | 61 | var addClass = function (obj, cls) { 62 | if (!hasClass(obj, cls)) obj.className += " " + cls; 63 | } 64 | 65 | var removeClass = function (obj, cls) { 66 | if (hasClass(obj, cls)) { 67 | var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)'); 68 | obj.className = obj.className.replace(reg, ' '); 69 | } 70 | } 71 | 72 | /*淡入淡出*/ 73 | qc.animate.fade = function (action, run) { 74 | if (action == "enter") { 75 | this.style.opacity = 0; 76 | animate(this, { 77 | name: "opacity", 78 | value: 1, 79 | unit: "" 80 | }) 81 | } else if (action == "leave") { 82 | this.style.opacity = 1; 83 | animate(this, { 84 | name: "opacity", 85 | value: 0, 86 | unit: "" 87 | }, run); 88 | } 89 | } 90 | qc.animate.fadeIn = function (action, run) { 91 | if (action == "enter") { 92 | this.style.opacity = 0; 93 | animate(this, { 94 | name: "opacity", 95 | value: 1, 96 | unit: "" 97 | }) 98 | } else { 99 | run(); 100 | } 101 | } 102 | qc.animate.fadeOut = function (action, run) { 103 | if (action == "leave") { 104 | this.style.opacity = 1; 105 | animate(this, { 106 | name: "opacity", 107 | value: 0, 108 | unit: "" 109 | }, run); 110 | } 111 | } 112 | /*上拉下拉*/ 113 | qc.animate.slide = function (action, run) { 114 | var overflow = this.style.overflow; 115 | var height = _getComputedStyle(this, "height").replace("px", "") * 1; 116 | this.style.overflow = "hidden"; 117 | var _this = this; 118 | if (action == "enter") { 119 | this.style.height = "0px"; 120 | animate(this, { 121 | name: "height", 122 | value: height, 123 | unit: "px" 124 | }, function () { 125 | _this.style.overflow = overflow; 126 | _this.style.height = ""; 127 | }) 128 | } else if (action == "leave") { 129 | animate(this, { 130 | name: "height", 131 | value: 0, 132 | unit: "px" 133 | }, run); 134 | } 135 | } 136 | qc.animate.slideUp = function (action, run) { 137 | var overflow = this.style.overflow; 138 | var height = _getComputedStyle(this, "height"); 139 | this.style.overflow = "hidden"; 140 | var _this = this; 141 | if (action == "enter") { 142 | this.style.height = "0px"; 143 | animate(this, { 144 | name: "height", 145 | value: height, 146 | unit: "px" 147 | }, function () { 148 | _this.style.overflow = overflow; 149 | _this.style.height = ""; 150 | }) 151 | } else { 152 | run(); 153 | } 154 | } 155 | qc.animate.slideDown = function (action, run) { 156 | if (action == "leave") { 157 | var height = _getComputedStyle(this, "height"); 158 | this.style.opacity = 1; 159 | animate(this, { 160 | name: "height", 161 | value: 0, 162 | unit: "px" 163 | }, run); 164 | } 165 | } 166 | })() -------------------------------------------------------------------------------- /src/commonjs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * commonjs.js 4 | */ 5 | 6 | ; (function () { 7 | var get = function (url) { 8 | // XMLHttpRequest对象用于在后台与服务器交换数据 9 | url = url + "?r=" + (new Date() - 1); 10 | var retStr = ""; 11 | var xhr = new XMLHttpRequest(); 12 | xhr.open('GET', url, false); 13 | xhr.onreadystatechange = function () { 14 | // readyState == 4说明请求已完成 15 | if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { 16 | // 从服务器获得数据 17 | retStr = xhr.responseText; 18 | } else { 19 | window.console && console.log(url + "加载失败"); 20 | } 21 | }; 22 | xhr.send(); 23 | return retStr; 24 | } 25 | //---------------commonjs规范----------------//; 26 | var getPath = function () { 27 | var jsPath = document.currentScript ? document.currentScript.src : function () { 28 | var js = document.scripts 29 | , last = js.length - 1 30 | , src; 31 | for (var i = last; i > 0; i--) { 32 | if (js[i].readyState === 'interactive') { 33 | src = js[i].src; 34 | break; 35 | } 36 | } 37 | return src || js[last].src; 38 | }(); 39 | if(!jsPath){ 40 | var jsPath=window.location.href; 41 | if(jsPath[jsPath.length-1]!='/'){ 42 | jsPath=jsPath.substring(0, jsPath.lastIndexOf('/') + 1); 43 | } 44 | }else{ 45 | jsPath=jsPath.substring(0, jsPath.lastIndexOf('/') + 1); 46 | } 47 | return jsPath; 48 | } 49 | window.needStack=[]; 50 | window.need = function (path) { 51 | var model; 52 | var type = "js"; 53 | if(path.indexOf('$url:')==0){ 54 | var parent=getPath(); 55 | path=path.replace('$url:',''); 56 | if(path.substr(0, 1) != "/"){ 57 | path=getPath()+path; 58 | } 59 | } 60 | var basePath = path.substr(0, path.lastIndexOf("/") + 1); 61 | if (path.lastIndexOf("!") > -1) { 62 | type = path.substr(path.lastIndexOf("!") + 1); 63 | path = path.substr(0, path.lastIndexOf("!")); 64 | } else { 65 | if (path.lastIndexOf(".js") < 0) { 66 | path = path + ".js"; 67 | } 68 | } 69 | model = get(path); 70 | if (type == "js") { //js预编译 71 | var script = "(function(out){\n"; 72 | script += model.replace(/\$url:\//g,'\/').replace(/\$url:/g,basePath); 73 | script += "\n return out;\n"; 74 | script += "})({});" + "//@ sourceURL=" + path; 75 | model = eval(script); 76 | } 77 | return model; 78 | } 79 | })(); -------------------------------------------------------------------------------- /src/core/binddata.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * binddata.js 4 | */ 5 | ; 6 | (function (qc) { 7 | /* 8 | * 更新视图 9 | * maps 需要更新的元素列表 10 | * dub 触发更新事件的 比如input 如果焦点不在上面 或者触发事件的元素不只自己 满足一个条件才更新 11 | * */ 12 | var PREFIX = qc.PREFIX; 13 | var render = function (maps, dub) { 14 | for (var _map in maps) { 15 | var map = maps[_map]; 16 | var dom = document.querySelector("[" + PREFIX + "-id=\"" + _map + "\"" + "]"); 17 | var comDom = qclib.getCommentNodes(_map);//获取注释节点 18 | for (var m = 0; m < map.length; m++) { 19 | var uuid = map[m]["uuid"]; 20 | var type = map[m]["type"]; 21 | var exp = map[m]["exp"]; 22 | var vm = map[m]["vm"]; 23 | var widget = map[m]["widget"]; 24 | 25 | type = type.split(","); 26 | var k = type[0]; 27 | var v = type.length > 1 ? type[1] : ""; 28 | if (k === "visible") { 29 | var myValue = qclib.count(vm, exp); 30 | if (myValue) { 31 | if (dom === null) { 32 | if (comDom === null) { 33 | delete maps[uuid]; 34 | } else { 35 | //绑定 36 | delete maps[uuid]; 37 | var ele = document.createElement("div"); 38 | comDom.parentNode.insertBefore(ele, comDom); 39 | comDom.parentNode.removeChild(comDom); 40 | var newid = qc.getRandom() + ""; 41 | ele.outerHTML = bindData(vm, vm["$visible" + uuid], undefined, newid); 42 | qclib.load(); 43 | var newDom = document.querySelector("[" + PREFIX + "-id='" + newid + "']"); 44 | if (newDom.hasAttribute(PREFIX + "-animate")) { 45 | var veAnimate = newDom.getAttribute(PREFIX + "-animate"); 46 | if (qc.animate.hasOwnProperty(veAnimate) && typeof qc.animate[veAnimate] == "function") { 47 | qc.animate[veAnimate].call(newDom, "enter");//显示 48 | } 49 | } 50 | delete vm["$visible" + uuid]; 51 | } 52 | break; 53 | } 54 | } else { 55 | if (dom !== null) { 56 | var remove = function () { 57 | var comNode = document.createComment(uuid);//创建注释节点 58 | dom.parentNode.insertBefore(comNode, dom); 59 | dom.parentNode.removeChild(dom); 60 | } 61 | 62 | if (dom.hasAttribute(PREFIX + "-animate")) { 63 | var veAnimate = dom.getAttribute(PREFIX + "-animate"); 64 | if (qc.animate.hasOwnProperty(veAnimate) && typeof qc.animate[veAnimate] == "function") { 65 | qc.animate[veAnimate].call(dom, "leave", remove);//显示 66 | } else { 67 | remove(); 68 | } 69 | } else { 70 | remove(); 71 | } 72 | } 73 | //垃圾回收 74 | qc.collection(); 75 | break; 76 | } 77 | } else { 78 | if (dom !== null) { 79 | var myValue = qclib.count(vm, exp); 80 | if (k === "attr") { 81 | dom.setAttribute(v, myValue); 82 | } else if (k === "css") { 83 | dom.style[v] = myValue; 84 | } else if (k === "class") { 85 | var classList = dom.className.split(" "); 86 | for (var c = classList.length - 1; c >= 0; c--) { 87 | if (classList[c] === v) { 88 | classList.splice(c, 1); 89 | } 90 | } 91 | if (myValue) { 92 | classList.push(v); 93 | } 94 | dom.className = classList.join(" "); 95 | } else if (k === "prop") { 96 | if (myValue) { 97 | dom.setAttribute(v, "true"); 98 | } else { 99 | dom.removeAttribute(v); 100 | } 101 | } else if (k === "value") { 102 | if (v === "text") { 103 | try { 104 | if (document.activeElement !== dom || dub !== dom) { 105 | dom.value = myValue; 106 | } 107 | } catch (e) {//iebug修复 108 | dom.value = myValue; 109 | } 110 | } else if (v === "textarea") { 111 | if (document.activeElement !== dom || dub !== dom) { 112 | dom.value = myValue; 113 | } 114 | } 115 | 116 | } else if (k === "text") { 117 | try { 118 | dom.innerHTML = qclib.innerText(myValue); 119 | } catch (e) { 120 | qclib.setTBodyInnerHTML(dom, qclib.innerText(myValue)); 121 | } 122 | } else if (k === "html") { 123 | try { 124 | dom.innerHTML = myValue; 125 | } catch (e) { 126 | qclib.setTBodyInnerHTML(dom, myValue); 127 | } 128 | } else if (k === "select") { 129 | if (document.activeElement !== dom) { 130 | for (var i = 0; i < dom.options.length; i++) { 131 | if (myValue == dom.options[i].value) { 132 | dom.options[i].selected = true; 133 | break; 134 | } 135 | } 136 | } 137 | } 138 | else if (k === "check") { 139 | if (document.activeElement !== dom) { 140 | var qtrue = dom.getAttribute("qtrue"); 141 | var qfalse = dom.getAttribute("qfalse"); 142 | if (qtrue == undefined || qtrue == null) { 143 | if (myValue == qtrue) { 144 | dom.checked = true; 145 | } else { 146 | dom.checked = false; 147 | } 148 | } else { 149 | if (myValue) { 150 | dom.checked = true; 151 | } else { 152 | dom.checked = false; 153 | } 154 | } 155 | } 156 | } else if (k === "radio") { 157 | if (document.activeElement !== dom) { 158 | if (myValue == dom.value) { 159 | dom.checked = true; 160 | } else { 161 | dom.checked = false; 162 | } 163 | } 164 | } else if (k === "widget") { 165 | widget.props[v] = myValue; 166 | if (widget.hasOwnProperty("update") && typeof widget["update"] === "function") { 167 | widget.update(v, myValue); 168 | } 169 | } 170 | } else { 171 | if (comDom === null) { 172 | delete maps[uuid]; 173 | break; 174 | } 175 | } 176 | } 177 | } 178 | } 179 | } 180 | 181 | function bindData(vm, vDom, option, uuid) { 182 | var path = "_"; 183 | var show = true; 184 | if (vm.hasOwnProperty("$path")) { 185 | path = vm.$path; 186 | } 187 | var bindSet = function (vm, $p) { 188 | if ($p !== undefined) { 189 | vm.$p = $p; 190 | } 191 | if (!vm.hasOwnProperty("$map")) { 192 | vm.$map = {}; 193 | } 194 | vm.$set =vm.setValue = function (key, value, dub) { 195 | function getMypath(path) { 196 | path = path.replace(/\[\d+\]/g, ""); 197 | var view = vm.$path; 198 | var len = view.indexOf("."); 199 | if (len > -1) { 200 | view = view.substr(0, len) 201 | } 202 | if (view !== null) { 203 | view = qc.vms[view].$watch; 204 | for (var i = 0; i < view.length; i++) { 205 | if (view[i].path === path) { 206 | return view[i].callback; 207 | } 208 | } 209 | } 210 | return false; 211 | } 212 | 213 | if (qclib.isArray(value)) { 214 | if (typeof key === "object") { 215 | return; 216 | } 217 | if (!qclib.isArray(vm[key])) { 218 | return; 219 | } 220 | var watch = getMypath(vm.$path + "." + key); 221 | var oldValue = qc.getModel(vm[key]); 222 | var each = this["$" + PREFIX + "-each-" + key]; 223 | vm[key] = value; 224 | for (var l = 0; l < vm[key].length; l++) { 225 | vm[key][l].$p = vm; 226 | vm[key][l].$index = vm[key][l].$key = l; 227 | vm[key][l].$path = vm.$path + "." + key + "[" + l + "]"; 228 | } 229 | if (qclib.isArray(each)) { 230 | for (var _k = each.length - 1; _k >= 0; _k--) { 231 | var html = []; 232 | for (var l = 0; l < vm[key].length; l++) { 233 | html.push(bindData(vm[key][l], each[_k].vDom)); 234 | if (html.length > 1000) {//数组进行性能优化 235 | html = [html.join("")]; 236 | } 237 | } 238 | var s = document.querySelector("[" + PREFIX + "-id=\"" + each[_k].uuid + "\"" + "]"); 239 | if (s === null) { 240 | each.splice(_k, 1); 241 | } else { 242 | try { 243 | s.innerHTML = html.join(""); 244 | } catch (e) { 245 | qclib.setTBodyInnerHTML(s, html.join("")); 246 | } 247 | qclib.load(); 248 | } 249 | } 250 | 251 | } 252 | //更新数组长度绑定 253 | render(this["$map"][key]); 254 | //垃圾回收 255 | qc.collection(); 256 | if (watch) { 257 | watch(value, oldValue, vm); 258 | } 259 | } else if (typeof key === "object") { 260 | function setObject(map, data) { 261 | for (var m in map) { 262 | if (typeof map[m] !== "function" && m.indexOf("$") < 0) { 263 | if (map.hasOwnProperty("$" + PREFIX + "-each-" + m)) { 264 | if (data[m] !== undefined) { 265 | map.$set(m, data[m]); 266 | } 267 | continue; 268 | } 269 | if (data[m] !== undefined) { 270 | if (typeof map[m] === "object") { 271 | if (typeof data[m] === "object" && data[m] != null) { 272 | setObject(map[m], data[m]); 273 | } 274 | } 275 | } 276 | } 277 | } 278 | for (var m in map) { 279 | if (typeof map[m] !== "function" && m.indexOf("$") < 0) { 280 | if (map.hasOwnProperty("$" + PREFIX + "-each-" + m)) { 281 | continue; 282 | } 283 | if (data[m] !== undefined) { 284 | if (typeof map[m] !== "object") { 285 | map[m] = data[m]; 286 | if (map["$map"] && map["$map"][m] !== undefined) { 287 | render(map["$map"][m]); 288 | } 289 | } 290 | } 291 | } 292 | } 293 | } 294 | 295 | setObject(this, key); 296 | if (watch) { 297 | watch(key, oldValue, this.$p); 298 | } 299 | } else if (typeof value === "object") { 300 | vm[key].$set(value); 301 | } 302 | else { 303 | if (this[key] === value) { 304 | return; 305 | } 306 | var watch = getMypath(vm.$path + "." + key); 307 | var oldValue = qc.getModel(vm[key]); 308 | this[key] = value; 309 | if (this.hasOwnProperty("$map")) { 310 | var list = this.$map[key]; 311 | if (list !== undefined) { 312 | render(list, dub); 313 | } 314 | } 315 | if (watch) { 316 | watch(value, oldValue, vm); 317 | } 318 | } 319 | } 320 | 321 | for (var v in vm) { 322 | if (typeof vm[v] !== "function" && v.indexOf("$") < 0 && !qclib.isArray(vm[v]) && vm[v] != null && typeof vm[v] === "object") { 323 | vm[v].$path = vm.$path + "." + v; 324 | bindSet(vm[v], vm); 325 | } 326 | } 327 | } 328 | 329 | bindSet(vm) 330 | if (vDom.localName === "#text") { 331 | return vDom.nodeValue; 332 | } 333 | if (uuid === undefined || uuid === "" || uuid === null) { 334 | uuid = qc.getRandom() + ""; 335 | } 336 | 337 | if (qc.widget.hasOwnProperty(vDom.localName)) { 338 | var implement = qc.widget[vDom.localName]; 339 | if (implement.hasOwnProperty("view") && typeof implement.view === "function") { 340 | var obj = { 341 | props: {}, 342 | id: uuid, 343 | vDom: implement.vDom, 344 | getElement: function () { 345 | return document.querySelector("[" + PREFIX + "-id=\"" + this.id + "\"" + "]"); 346 | }, 347 | parent: {}, 348 | updateParent: function (key, value) { 349 | function getValue(path) { 350 | path = path.split("."); 351 | var vm = qc.vms[path[0]]; 352 | for (var i = 1; i < path.length - 1; i++) { 353 | var s = path[i]; 354 | if (s.indexOf("[") > -1) { 355 | var index = s.substr(s.indexOf("[")); 356 | index = index.substr(1, index.length - 2); 357 | index = index * 1; 358 | s = s.substr(0, s.indexOf("[")); 359 | vm = vm[s][index]; 360 | } else { 361 | vm = vm[s]; 362 | } 363 | } 364 | return { 365 | vm: vm, 366 | pro: path[path.length - 1] 367 | } 368 | } 369 | 370 | var vmValue = getValue(this.parent[key]); 371 | vmValue.vm.$set(vmValue.pro, value); 372 | }, 373 | view: implement.view 374 | } 375 | qc.vms[uuid] = {}; 376 | qc.vms[uuid].$ve = {}; 377 | qc.vms[uuid].$watch = []; 378 | qc.vms[uuid].$ve.$watch = function (path, callback) { 379 | qc.vms[uuid].$watch.push({ path: uuid + "." + path, callback: callback }) 380 | } 381 | if (vDom.hasOwnProperty("attributes")) { 382 | for (var ar in vDom.attributes) { 383 | var name = ar; 384 | var value = vDom.attributes[ar]; 385 | if (name.indexOf("bind:") === 0) { 386 | name = name.substr(5); 387 | var pValue = qclib.expEval(vm, ["{" + value + "}"], uuid, "widget," + name, obj); 388 | obj.props[name] = pValue; 389 | obj.parent[name] = vm.$path + "." + value; 390 | } else { 391 | obj.props[name] = value; 392 | } 393 | } 394 | } 395 | obj.viewModel = qc.vms[uuid]; 396 | obj.view(qc.vms[uuid], qc.vms[uuid].$ve); 397 | if (implement.hasOwnProperty("update")) { 398 | obj.update = implement.update; 399 | } 400 | if (implement.hasOwnProperty("load")) { 401 | obj.load = implement.load; 402 | qc.load.push(obj); 403 | } 404 | delete qc.vms[uuid].$ve.$watch; 405 | qc.vms[uuid].$path = uuid; 406 | var widgetStr = bindData(qc.vms[uuid], obj.vDom); 407 | widgetStr = widgetStr.replace(">", " " + PREFIX + "-id=\"" + uuid + "\"" + " >"); 408 | return widgetStr; 409 | 410 | } 411 | } 412 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-visible")) { 413 | var expV = vDom[PREFIX][PREFIX + "-visible"]; 414 | vm["$visible" + uuid] = vDom;//建立绑定映射 415 | if (!qclib.expEval(vm, expV, uuid, "visible")) { 416 | show = false; 417 | } 418 | } 419 | var html = ["<" + vDom.localName]; 420 | if (show) { 421 | if (!qclib.isNullObj(vDom[PREFIX])) { 422 | html.push(" " + PREFIX + "-id=\"" + uuid + "\"") 423 | } 424 | var classObject = {}; 425 | if (vDom.hasOwnProperty("className")) { 426 | var classList = vDom.className; 427 | for (var i = 0; i < classList.length; i++) { 428 | classObject[classList[i]] = classList[i]; 429 | } 430 | } 431 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-class")) { 432 | var dClass = vDom[PREFIX][PREFIX + "-class"]; 433 | for (var c in dClass) { 434 | var result = qclib.expEval(vm, dClass[c], uuid, "class," + c); 435 | if (result) { 436 | classObject[c] = c; 437 | } else { 438 | delete classObject[c]; 439 | } 440 | } 441 | classList = []; 442 | for (var c in classObject) { 443 | classList.push(c); 444 | } 445 | if (classList.length > 0) { 446 | html.push(" class=\"" + classList.join(" ") + "\"");//class 447 | } 448 | } else { 449 | if (vDom.className.length > 0) { 450 | html.push(" class=\"" + vDom.className.join(" ") + "\"");//class 451 | } 452 | } 453 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-attr")) { 454 | var dAttr = vDom[PREFIX][PREFIX + "-attr"]; 455 | for (var a in dAttr) { 456 | var value = qclib.expEval(vm, dAttr[a], uuid, "attr," + a); 457 | html.push(" " + a + "=" + "\"" + value + "\""); 458 | if (a === "value" && vDom.localName === "option") { 459 | if (option === value) { 460 | html.push(" selected"); 461 | } 462 | } 463 | if (a === "value") { 464 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-radio")) { 465 | var textValue = vDom[PREFIX][PREFIX + "-radio"]; 466 | var text = textValue[0]; 467 | text = text.substr(1, text.length - 2); 468 | if (qclib.expEval(vm, textValue, uuid, "radio") == value) { 469 | html.push(" checked onchange=qc.bindRadio(\"" + path + "." + text + "\",this)"); 470 | } else { 471 | html.push(" onchange=qc.bindRadio(\"" + path + "." + text + "\",this)"); 472 | } 473 | } 474 | } 475 | } 476 | } 477 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-prop")) { 478 | var dProp = vDom[PREFIX][PREFIX + "-prop"]; 479 | for (var p in dProp) { 480 | if (qclib.expEval(vm, dProp[p], uuid, "prop," + p)) { 481 | html.push(" " + p); 482 | } 483 | } 484 | } 485 | if (vDom.hasOwnProperty("attributes")) { 486 | for (var ar in vDom.attributes) { 487 | var name = ar; 488 | var value = vDom.attributes[ar]; 489 | if (((!vDom[PREFIX].hasOwnProperty(PREFIX + "-attr")) || vDom[PREFIX][PREFIX + "-attr"][name] === undefined) && ((!vDom[PREFIX].hasOwnProperty(PREFIX + "-prop")) || vDom[PREFIX][PREFIX + "-prop"][name] === undefined)) { 490 | html.push(" " + name + "=" + "\"" + value + "\""); 491 | if (name === "value" && vDom.localName === "option") { 492 | if (option === value) { 493 | html.push(" selected"); 494 | } 495 | } 496 | if (name === "value") {//因为要和自身的属性value做比较,所以放在 属性的循环里 497 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-radio")) { 498 | var textValue = vDom[PREFIX][PREFIX + "-radio"]; 499 | var text = textValue[0]; 500 | text = text.substr(1, text.length - 2); 501 | if (qclib.expEval(vm, textValue, uuid, "radio") == value) { 502 | html.push(" checked onchange=qc.bindRadio(\"" + path + "." + text + "\",this)"); 503 | } else { 504 | html.push(" onchange=qc.bindRadio(\"" + path + "." + text + "\",this)"); 505 | } 506 | } 507 | } 508 | } 509 | 510 | } 511 | } 512 | var styleList = []; 513 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-css")) { 514 | var dCss = vDom[PREFIX][PREFIX + "-css"]; 515 | for (var c in dCss) { 516 | styleList.push(c + ":" + qclib.expEval(vm, dCss[c], uuid, "css," + c)); 517 | } 518 | } 519 | if (vDom.hasOwnProperty("style")) { 520 | for (var sy in vDom.style) { 521 | if ((!vDom[PREFIX].hasOwnProperty(PREFIX + "-css")) || vDom[PREFIX][PREFIX + "-css"][sy] === undefined) { 522 | styleList.push(sy + ":" + vDom.style[sy]); 523 | } 524 | } 525 | } 526 | if (styleList.length > 0) { 527 | html.push(" style=\"" + styleList.join(";") + "\""); 528 | } 529 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-value")) { 530 | var tempValue = qclib.expEval(vm, vDom[PREFIX][PREFIX + "-value"], uuid, "value,text"); 531 | if (vDom.localName === "input") { 532 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-radio")) { 533 | var textValue = vDom[PREFIX][PREFIX + "-radio"]; 534 | var text = textValue[0]; 535 | text = text.substr(1, text.length - 2); 536 | if (qclib.expEval(vm, textValue, uuid, "radio") == tempValue) { 537 | html.push(" checked onchange=qc.bindRadio(\"" + path + "." + text + "\",this)"); 538 | } else { 539 | html.push(" onchange=qc.bindRadio(\"" + path + "." + text + "\",this)"); 540 | } 541 | } 542 | html.push(" value=\"" + tempValue + "\""); 543 | } 544 | } 545 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-value-change")) { 546 | var textValue = vDom[PREFIX][PREFIX + "-value-change"]; 547 | if (vDom.localName === "input") { 548 | html.push(" value=\"" + qclib.expEval(vm, textValue, uuid, "value,text") + "\""); 549 | } 550 | var text = textValue[0]; 551 | text = text.substr(1, text.length - 2); 552 | if (qclib.isLowIe()) { 553 | html.push(" onkeyup=qc.bindText(\"" + path + "." + text + "\",this)"); 554 | } else { 555 | html.push(" oninput=qc.bindText(\"" + path + "." + text + "\",this)"); 556 | } 557 | } 558 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-value-blur")) { 559 | var textValue = vDom[PREFIX][PREFIX + "-value-blur"]; 560 | if (vDom.localName === "input") { 561 | html.push(" value=\"" + qclib.expEval(vm, textValue, uuid, "value,text") + "\""); 562 | } 563 | var text = textValue[0]; 564 | text = text.substr(1, text.length - 2); 565 | html.push(" onchange=qc.bindText(\"" + path + "." + text + "\",this)"); 566 | } 567 | var selectValue = null; 568 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-select")) { 569 | var textValue = vDom[PREFIX][PREFIX + "-select"]; 570 | var text = textValue[0]; 571 | text = text.substr(1, text.length - 2); 572 | selectValue = qclib.expEval(vm, textValue, uuid, "select"); 573 | html.push(" onchange=qc.bindSelect(\"" + path + "." + text + "\",this)"); 574 | } 575 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-check")) { 576 | var textValue = vDom[PREFIX][PREFIX + "-check"]; 577 | var text = textValue[0]; 578 | text = text.substr(1, text.length - 2); 579 | var qtrue = vDom.attributes.qtrue; 580 | var qfalse = vDom.attributes.qfalse; 581 | if (qtrue == undefined || qtrue == null) { 582 | if (qclib.expEval(vm, textValue, uuid, "check")) { 583 | html.push(" checked onchange=qc.bindCheck(\"" + path + "." + text + "\",this)"); 584 | } else { 585 | html.push(" onchange=qc.bindCheck(\"" + path + "." + text + "\",this)"); 586 | } 587 | } else { 588 | if (qclib.expEval(vm, textValue, uuid, "check") == qtrue) { 589 | html.push(" checked onchange=qc.bindCheck(\"" + path + "." + text + "\",this)"); 590 | } else { 591 | html.push(" onchange=qc.bindCheck(\"" + path + "." + text + "\",this)"); 592 | } 593 | } 594 | } 595 | //绑定事件 596 | // click,dblclick,mousedown,mouseup 597 | //移动 touchstart touchend//需要扩展 598 | var eventList = ["click", "dblclick", "keydown", "keyup", "mousedown", "mouseup", "mousemove", "mouseenter ", "mouseleave", "mouseover", "mouseout"]; 599 | eventList = eventList.concat(["touchstart", "touchmove", "touchend", "touchcancel"]); 600 | for (var i = 0; i < eventList.length; i++) { 601 | var veType = eventList[i]; 602 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-" + veType + "")) { 603 | var veName = vDom[PREFIX][PREFIX + "-" + veType + ""]; 604 | veName = veName[0]; 605 | veName = veName.substr(1, veName.length - 2) 606 | html.push(" " + PREFIX + "-path=\"" + path + "\""); 607 | html.push(" " + PREFIX + "-vetype=\"" + veType + "\""); 608 | html.push(" " + PREFIX + "-vename=\"" + veName + "\""); 609 | } 610 | } 611 | for (var veType in qc.ve) {//扩展事件绑定 612 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-" + veType + "")) { 613 | var veName = vDom[PREFIX][PREFIX + "-" + veType + ""]; 614 | veName = veName[0]; 615 | veName = veName.substr(1, veName.length - 2) 616 | html.push(" " + PREFIX + "-path=\"" + path + "\""); 617 | html.push(" " + PREFIX + "-vetype=\"" + veType + "\""); 618 | html.push(" " + PREFIX + "-vename=\"" + veName + "\""); 619 | } 620 | } 621 | /*动画*/ 622 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-animate")) { 623 | var lenAnimate = vDom[PREFIX][PREFIX + "-animate"][0]; 624 | lenAnimate = lenAnimate.substr(1, lenAnimate.length - 2); 625 | html.push(" " + PREFIX + "-animate=\"" + lenAnimate + "\""); 626 | } 627 | html.push(">"); 628 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-value")) { 629 | var textValue = vDom[PREFIX][PREFIX + "-value"]; 630 | if (vDom.localName !== "input") { 631 | html.push(qclib.expEval(vm, textValue, uuid, "value,textarea")); 632 | } 633 | } 634 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-value-change")) { 635 | var textValue = vDom[PREFIX][PREFIX + "-value-change"]; 636 | if (vDom.localName !== "input") { 637 | html.push(qclib.expEval(vm, textValue, uuid, "value,textarea")); 638 | } 639 | } 640 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-value-blur")) { 641 | var textValue = vDom[PREFIX][PREFIX + "-value-blur"]; 642 | if (vDom.localName !== "input") { 643 | html.push(qclib.expEval(vm, textValue, uuid, "value,textarea")); 644 | } 645 | } 646 | } 647 | var arr = vDom[PREFIX][PREFIX + "-each"]; 648 | if (arr !== undefined) { 649 | arr = arr[0]; 650 | arr = arr.substr(1, arr.length - 2); 651 | var arrList = arr.split("."); 652 | var $parent, $prop; 653 | if (arrList.length > 1) { 654 | $prop = arrList.pop(); 655 | $parent = qclib.valuePro(vm, "{" + arrList.join(".") + "}"); 656 | } else { 657 | $parent = vm; 658 | $prop = arr; 659 | } 660 | var list = $parent[$prop]; 661 | if (list === undefined) { 662 | $parent[$prop] = []; 663 | list = $parent[$prop]; 664 | } 665 | var addAnimate = function (index) { 666 | var divObject = $parent["$" + PREFIX + "-each-" + $prop]; 667 | for (var k = divObject.length - 1; k >= 0; k--) { 668 | var newDom = document.querySelector("[" + PREFIX + "-id='" + divObject[k].uuid + "']"); 669 | try { 670 | var childNodes = newDom.childNodes; 671 | newDom = childNodes[index]; 672 | if (newDom.hasAttribute(PREFIX + "-animate")) { 673 | var veAnimate = newDom.getAttribute(PREFIX + "-animate"); 674 | if (qc.animate.hasOwnProperty(veAnimate) && typeof qc.animate[veAnimate] == "function") { 675 | qc.animate[veAnimate].call(newDom, "enter");//显示 676 | } 677 | } 678 | } catch (e) { 679 | } 680 | } 681 | } 682 | var removeAnimate = function (index, callback) { 683 | var divObject = $parent["$" + PREFIX + "-each-" + $prop]; 684 | var isCall = true; 685 | for (var k = divObject.length - 1; k >= 0; k--) { 686 | try { 687 | var newDom = document.querySelector("[" + PREFIX + "-id='" + divObject[k].uuid + "']"); 688 | var childNodes = newDom.childNodes; 689 | newDom = childNodes[index]; 690 | if (newDom.hasAttribute(PREFIX + "-animate")) { 691 | var veAnimate = newDom.getAttribute(PREFIX + "-animate"); 692 | if (qc.animate.hasOwnProperty(veAnimate) && typeof qc.animate[veAnimate] == "function") { 693 | qc.animate[veAnimate].call(newDom, "leave", callback); 694 | isCall = false; 695 | } 696 | } 697 | } catch (e) { 698 | // 699 | } 700 | } 701 | if (isCall) { 702 | callback(); 703 | } 704 | } 705 | for (var i = 0; i < vDom.childNodes.length; i++) { 706 | if (vDom.childNodes[i].localName !== "#text") { 707 | if (!$parent.hasOwnProperty("$" + PREFIX + "-each-" + $prop)) { 708 | $parent["$" + PREFIX + "-each-" + $prop] = []; 709 | } 710 | $parent["$" + PREFIX + "-each-" + $prop].push({ 711 | uuid: uuid, 712 | vDom: vDom.childNodes[i] 713 | }) 714 | for (var l = 0; l < list.length; l++) { 715 | list[l].$p = $parent; 716 | list[l].$index = list[l].$key = l; 717 | list[l].$path = path + "." + arr + "[" + l + "]"; 718 | if (selectValue === null) { 719 | html.push(bindData(list[l], vDom.childNodes[i])); 720 | } else { 721 | html.push(bindData(list[l], vDom.childNodes[i], selectValue)); 722 | } 723 | if (html.length > 1000) {//数组进行性能优化 724 | html = [html.join("")]; 725 | } 726 | } 727 | $parent[$prop + "push"] = function (value) { 728 | var divObject = $parent["$" + PREFIX + "-each-" + $prop]; 729 | var list = $parent[$prop]; 730 | var start = list.length; 731 | list.push(value) 732 | list[start].$p = $parent; 733 | list[start].$index = list[start].$key = start; 734 | list[start].$path = path + "." + arr + "[" + start + "]"; 735 | for (var k = divObject.length - 1; k >= 0; k--) { 736 | var divText = []; 737 | divText.push(bindData(list[start], divObject[k].vDom)); 738 | var s = document.querySelector("[" + PREFIX + "-id=\"" + divObject[k].uuid + "\"" + "]"); 739 | if (s === null) { 740 | divObject.splice(k, 1); 741 | } else { 742 | try { 743 | var _tagName = s.tagName.toLocaleLowerCase(); 744 | if (_tagName == "table" || _tagName == "tr" || _tagName == "tbody") { 745 | qclib.setTBodyAppendHtml(s, divText.join("")); 746 | } else { 747 | var newDiv = document.createElement("div"); 748 | newDiv.innerHTML = divText.join(""); 749 | s.appendChild(newDiv.children[0]); 750 | } 751 | } catch (e) { 752 | qclib.setTBodyAppendHtml(s, divText.join("")); 753 | } 754 | qclib.load(); 755 | 756 | } 757 | } 758 | addAnimate(list.length - 1); 759 | //更新数组长度绑定 760 | render($parent["$map"][$prop]); 761 | } 762 | $parent[$prop + "pop"] = function () { 763 | var list = qc.getModel($parent[$prop]); 764 | var remove = function () { 765 | list.pop(); 766 | $parent.$set($prop, list); 767 | } 768 | removeAnimate(list.length - 1, remove); 769 | } 770 | $parent[$prop + "splice"] = function () { 771 | var k = 0; 772 | var args = arguments; 773 | var list = qc.getModel($parent[$prop]); 774 | var remove = function () { 775 | k--; 776 | if (k < 0) { 777 | list.splice.apply(list, args); 778 | $parent.$set($prop, list); 779 | } 780 | } 781 | if (arguments.length == 2) { 782 | for (var index = args[0]; index < args[0] + args[1]; index++) { 783 | k++; 784 | removeAnimate(index, remove); 785 | } 786 | remove(); 787 | } else { 788 | remove(); 789 | } 790 | 791 | } 792 | $parent[$prop + "shift"] = function () { 793 | var list = qc.getModel($parent[$prop]); 794 | var remove = function () { 795 | list.shift(); 796 | $parent.$set($prop, list) 797 | } 798 | removeAnimate(0, remove); 799 | } 800 | $parent[$prop + "unshift"] = function (value) { 801 | var list = qc.getModel($parent[$prop]); 802 | list.unshift(value); 803 | $parent.$set($prop, list); 804 | addAnimate(0); 805 | } 806 | $parent[$prop + "concat"] = function (value) { 807 | var divObject = $parent["$" + PREFIX + "-each-" + $prop]; 808 | var list = $parent[$prop]; 809 | var start = list.length; 810 | $parent[$prop] = list.concat(value); 811 | list = $parent[$prop]; 812 | var end = list.length - 1; 813 | for (var k = divObject.length - 1; k >= 0; k--) { 814 | var divText = []; 815 | for (var l = start; l < value.length + start; l++) { 816 | list[l].$p = $parent; 817 | list[l].$index = list[l].$key = l; 818 | list[l].$path = path + "." + arr + "[" + l + "]"; 819 | divText.push(bindData(list[l], divObject[k].vDom)); 820 | } 821 | var s = document.querySelector("[" + PREFIX + "-id=\"" + divObject[k].uuid + "\"" + "]"); 822 | if (s === null) { 823 | divObject.splice(k, 1); 824 | } else { 825 | try { 826 | var _tagName = s.tagName.toLocaleLowerCase(); 827 | if (_tagName == "table" || _tagName == "tr" || _tagName == "tbody") { 828 | qclib.setTBodyAppendHtml(s, divText.join("")); 829 | } else { 830 | var newDiv = document.createElement("div"); 831 | newDiv.innerHTML = divText.join(""); 832 | while (newDiv.children.length > 0) { 833 | s.appendChild(newDiv.children[0]); 834 | } 835 | } 836 | } catch (e) { 837 | qclib.setTBodyAppendHtml(s, divText.join("")); 838 | } 839 | qclib.load(); 840 | } 841 | } 842 | for (var index = start; index <= end; index++) { 843 | addAnimate(index); 844 | } 845 | //更新数组长度绑定 846 | render($parent["$map"][$prop]); 847 | 848 | } 849 | break; 850 | } 851 | 852 | } 853 | } 854 | else { 855 | if (show) { 856 | if (vDom[PREFIX].hasOwnProperty(PREFIX + "-text")) {//绑定text 857 | var text = vDom[PREFIX][PREFIX + "-text"]; 858 | var bindText = qclib.expEval(vm, text, uuid, "text"); 859 | html.push(qclib.innerText(bindText)); 860 | } else if (vDom[PREFIX].hasOwnProperty(PREFIX + "-html")) { 861 | var text = vDom[PREFIX][PREFIX + "-html"]; 862 | var bindText = qclib.expEval(vm, text, uuid, "html"); 863 | html.push(bindText); 864 | } else { 865 | for (var i = 0; i < vDom.childNodes.length; i++) { 866 | if (selectValue === null) { 867 | html.push(bindData(vm, vDom.childNodes[i])); 868 | } else { 869 | html.push(bindData(vm, vDom.childNodes[i], selectValue)); 870 | } 871 | ; 872 | if (html.length > 1000) {//数组进行性能优化 873 | html = [html.join("")]; 874 | } 875 | } 876 | } 877 | 878 | } else { 879 | for (var i = 0; i < vDom.childNodes.length; i++) { 880 | if (selectValue === null) { 881 | bindData(vm, vDom.childNodes[i]) 882 | } else { 883 | bindData(vm, vDom.childNodes[i], selectValue) 884 | } 885 | } 886 | } 887 | } 888 | html.push("" + vDom.localName + ">") 889 | if (show) { 890 | return html.join(""); 891 | } else { 892 | return ""; 893 | } 894 | } 895 | 896 | qclib.bindData = bindData; 897 | if (!window.qclib) { 898 | window.qclib = {}; 899 | } 900 | })(qc) -------------------------------------------------------------------------------- /src/core/creatvm.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * creatvm.js 4 | */ 5 | 6 | /*创建虚拟节点*/ 7 | //需要依赖ie.js 8 | ; 9 | (function (qc) { 10 | var PREFIX = qc.PREFIX; 11 | var expresssion = function (exp) { 12 | var list = []; 13 | var text = exp; 14 | var v = ""; 15 | try { 16 | text.length; 17 | } catch (e) { 18 | window.console && console.log(text); 19 | } 20 | for (var t = 0; t < text.length; t++) { 21 | var char = text.charAt(t); 22 | if (char == "{") { 23 | if (v !== "") { 24 | list.push(v); 25 | } 26 | v = "{" 27 | } else if (char == "}") { 28 | v += "}" 29 | list.push(v); 30 | v = ""; 31 | } else { 32 | v += char; 33 | } 34 | if (t === text.length - 1) { 35 | if (v !== "") { 36 | list.push(v); 37 | v = "" 38 | } 39 | } 40 | } 41 | return list; 42 | } 43 | 44 | var exp = function (exp) { 45 | var o = {}; 46 | var css = exp.mySplit(";"); 47 | for (var i = 0; i < css.length; i++) { 48 | var exp = css[i].mySplit(":"); 49 | o[exp[0]] = expresssion(exp[1]); 50 | } 51 | return o; 52 | } 53 | 54 | var htmlToObj = function (dom) { 55 | var retObj = {}; 56 | var to = function (d, o, p) { 57 | if (d.nodeName === "#text") { 58 | o.localName = "#text"; 59 | o.nodeValue = d.nodeValue; 60 | return; 61 | } 62 | o.localName = d.nodeName.toLowerCase(); 63 | if (p !== undefined) { 64 | o.parentNode = p; 65 | } 66 | if (d.className !== "") { 67 | o.className = d.className.mySplit(" "); 68 | } else { 69 | o.className = []; 70 | } 71 | o.attributes = {}; 72 | o[PREFIX] = {}; 73 | try { 74 | o.innerHTML = d.innerHTML; 75 | } catch (e) { 76 | qclib.setTBodyInnerHTML(o, d.innerHTML); 77 | } 78 | if (d.attributes.length > 0) { 79 | for (var a = 0; a < d.attributes.length; a++) { 80 | var _node = d.attributes[a] 81 | if (_node.nodeName.indexOf(PREFIX + "-") == 0 && _node.nodeName !== PREFIX + "-view") { 82 | if (_node.nodeName === PREFIX + "-text" || _node.nodeName === PREFIX + "-html") {//text文本 83 | o[PREFIX][_node.nodeName] = expresssion(_node.value); 84 | } else if (_node.nodeName === PREFIX + "-css") {//style 85 | o[PREFIX][_node.nodeName] = exp(_node.value); 86 | } else if (_node.nodeName === PREFIX + "-attr") {//属性 87 | o[PREFIX][_node.nodeName] = exp(_node.value); 88 | } else if (_node.nodeName === PREFIX + "-class") {//class 89 | o[PREFIX][_node.nodeName] = exp(_node.value); 90 | } else if (_node.nodeName === PREFIX + "-prop") {//prop 91 | o[PREFIX][_node.nodeName] = exp(_node.value); 92 | } else if (_node.nodeName === PREFIX + "-visible") {//是否显示 93 | o[PREFIX][_node.nodeName] = expresssion(_node.value); 94 | } else { 95 | o[PREFIX][_node.nodeName] = ["{" + _node.value + "}"]; 96 | } 97 | //处理表达式; 98 | } else if (_node.nodeName !== "class" && _node.nodeName !== "style") { 99 | o.attributes[_node.nodeName] = _node.value; 100 | } else if (_node.nodeName === "style") { 101 | var styleList = _node.value.split(";"); 102 | o.style = {}; 103 | for (var k = 0; k < styleList.length; k++) { 104 | if(styleList[k]!==undefined) { 105 | var v = styleList[k].mySplit(":"); 106 | o.style[v[0]] = v[1]; 107 | } 108 | } 109 | } 110 | } 111 | } 112 | o.childNodes = []; 113 | for (var i = 0; i < d.childNodes.length; i++) { 114 | if (d.childNodes[i].nodeType !== 8) { 115 | var child = {}; 116 | to(d.childNodes[i], child, o); 117 | o.childNodes.push(child); 118 | } 119 | } 120 | } 121 | 122 | to(dom, retObj); 123 | return retObj; 124 | } 125 | 126 | if (!window.qclib) { 127 | window.qclib = {}; 128 | } 129 | window.qclib.htmlToObj = htmlToObj; 130 | })(qc) -------------------------------------------------------------------------------- /src/core/dbevent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * dbevent.js 4 | */ 5 | ; 6 | (function (qc) { 7 | var PREFIX = qc.PREFIX; 8 | var getValue = function (path) { 9 | path = path.split("."); 10 | var vm = qc.vms[path[0]]; 11 | for (var i = 1; i < path.length - 1; i++) { 12 | var s = path[i]; 13 | if (s.indexOf("[") > -1) { 14 | var index = s.substr(s.indexOf("[")); 15 | index = index.substr(1, index.length - 2); 16 | index = index * 1; 17 | s = s.substr(0, s.indexOf("[")); 18 | vm = vm[s][index]; 19 | } else { 20 | vm = vm[s]; 21 | } 22 | } 23 | return { 24 | vm: vm, 25 | pro: path[path.length - 1] 26 | } 27 | } 28 | qc.bindText = function (path, obj) { 29 | var v = getValue(path); 30 | v.vm.$set(v.pro, obj.value, obj); 31 | } 32 | qc.bindSelect = function (path, obj) { 33 | if (document.activeElement === obj) { 34 | var v = getValue(path); 35 | if (obj.selectedIndex < obj.options.length) { 36 | v.vm.$set(v.pro, obj.options[obj.selectedIndex].value); 37 | } else { 38 | obj.selectedIndex = -1; 39 | } 40 | } 41 | } 42 | qc.bindCheck = function (path, obj) { 43 | if (document.activeElement === obj) { 44 | var v = getValue(path); 45 | var qtrue = obj.getAttribute("qtrue"); 46 | var qfalse = obj.getAttribute("qfalse"); 47 | if (qtrue == undefined || qtrue == null) { 48 | if (obj.checked) { 49 | v.vm.$set(v.pro, true); 50 | } else { 51 | v.vm.$set(v.pro, false); 52 | } 53 | } else { 54 | if (obj.checked) { 55 | v.vm.$set(v.pro, qtrue); 56 | } else { 57 | v.vm.$set(v.pro, qfalse); 58 | } 59 | } 60 | 61 | } 62 | } 63 | qc.bindRadio = function (path, obj) { 64 | if (document.activeElement === obj) { 65 | var v = getValue(path); 66 | if (obj.checked) { 67 | v.vm.$set(v.pro, obj.value); 68 | } 69 | } 70 | } 71 | })(qc) -------------------------------------------------------------------------------- /src/core/extent.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * extent.js 4 | */ 5 | ; 6 | (function (qc) { 7 | //创建控件 8 | qc.createWidget = function (name, implement) { 9 | if (!qc.hasOwnProperty("widget")) { 10 | qc.widget = {}; 11 | } 12 | if (implement.hasOwnProperty("templete") && implement.templete !== "") { 13 | var dom = document.createElement("div"); 14 | try { 15 | dom.innerHTML = implement.templete; 16 | } catch (e) { 17 | qclib.setTBodyInnerHTML(dom, implement.templete); 18 | } 19 | dom = dom.children[0]; 20 | implement.vDom = qclib.htmlToObj(dom); 21 | } 22 | 23 | qc.widget[name] = implement; 24 | } 25 | 26 | qc.extendEvent = function () { 27 | var ars = arguments; 28 | for (var i = 0; i < ars.length; i++) { 29 | qc.ve[ars[i].name] = ars[i]; 30 | } 31 | } 32 | })(qc) -------------------------------------------------------------------------------- /src/core/head.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * head.js 4 | */ 5 | ; 6 | (function (qc) { 7 | var PREFIX = "q"; 8 | if (!window.qc) { 9 | window.qc = {}; 10 | window.qc.PREFIX = PREFIX; 11 | window.qc.fun = {}; 12 | window.qc.animate = {}; 13 | } 14 | })() 15 | -------------------------------------------------------------------------------- /src/core/ie.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * 主要用于放和ie的兼容处理相关内容 4 | * ie.js 5 | */ 6 | ;(function () { 7 | //IE6 IE7做处理*/ IE8 开始支持这个方法 8 | if (!document.querySelectorAll) { 9 | document.querySelectorAll = function (selectors) { 10 | var style = document.createElement('style'), elements = [], element; 11 | document.documentElement.firstChild.appendChild(style); 12 | document._qsa = []; 13 | 14 | style.styleSheet.cssText = selectors + '{x-qsa:expression(document._qsa && document._qsa.push(this))}'; 15 | window.scrollBy(0, 0); 16 | style.parentNode.removeChild(style); 17 | 18 | while (document._qsa.length) { 19 | element = document._qsa.shift(); 20 | element.style.removeAttribute('x-qsa'); 21 | elements.push(element); 22 | } 23 | document._qsa = null; 24 | return elements; 25 | }; 26 | } 27 | if (!document.querySelector) { 28 | document.querySelector = function (selectors) { 29 | var elements = document.querySelectorAll(selectors); 30 | return (elements.length) ? elements[0] : null; 31 | }; 32 | } 33 | /*私有函数*/ //tbosy 复制 iebug 34 | var setTBodyInnerHTML = function (tbody, html) {//兼容ie6-ie9 的table innerHTML 不能修改 35 | var div = document.createElement('div') 36 | div.innerHTML = '' + html + '' 37 | while (tbody.firstChild) { 38 | tbody.removeChild(tbody.firstChild) 39 | } 40 | while (div.firstChild.firstChild.childNodes.length > 0) { 41 | tbody.appendChild(div.firstChild.firstChild.childNodes[0]) 42 | } 43 | } 44 | 45 | var setTBodyAppendHtml = function (tbody, html) { 46 | var div = document.createElement('div') 47 | div.innerHTML = '' + html + ''; 48 | while (div.firstChild.firstChild.childNodes.length > 0) { 49 | tbody.appendChild(div.firstChild.firstChild.childNodes[0]) 50 | } 51 | } 52 | 53 | var isLowIe = function () {/*ie11以下为低版本*/ 54 | return window.ActiveXObject ? true : false; 55 | } 56 | /*获取注释节点*/ 57 | var getCommentNodes = function (value) { 58 | if (window.NodeFilter) { 59 | var objs = document.createTreeWalker(document, NodeFilter.SHOW_COMMENT, null, false); 60 | var o; 61 | while (o = objs.nextNode()) { 62 | if (o.nodeValue === (value + "")) { 63 | return o; 64 | } 65 | } 66 | } else { 67 | var doms = document.getElementsByTagName("!"); 68 | for (var i = 0; i < doms.length; i++) { 69 | if (doms[i].nodeValue === (value + "")) { 70 | return doms[i]; 71 | } 72 | } 73 | 74 | } 75 | return null; 76 | } 77 | 78 | if (!window.qclib) { 79 | window.qclib = {}; 80 | } 81 | qclib.setTBodyInnerHTML = setTBodyInnerHTML; 82 | qclib.setTBodyAppendHtml = setTBodyAppendHtml; 83 | qclib.isLowIe = isLowIe; 84 | qclib.getCommentNodes = getCommentNodes; 85 | })() -------------------------------------------------------------------------------- /src/core/other.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * other.js 4 | */ 5 | ; 6 | (function (qc) { 7 | var PREFIX = qc.PREFIX; 8 | //内部生成不重复数字函数 9 | var random = new Date().getTime(); 10 | 11 | var getRandom = function () { 12 | random++; 13 | return random; 14 | } 15 | 16 | /*针对IE6 17 | /*判断是否为空对象*/ 18 | var isNullObj = function (obj) { 19 | for (var i in obj) { 20 | if (obj.hasOwnProperty(i)) { 21 | return false; 22 | } 23 | } 24 | return true; 25 | } 26 | /* 27 | //获得属性值 28 | *moudel 属性所在模型 29 | * 属性p 有可能为 xxx.xxx 30 | * */ 31 | var valuePro = function (moudel, p) { 32 | var mou = moudel; 33 | p = p.substr(1, p.length - 2); 34 | p = p.mySplit("."); 35 | for (var i = 0; i < p.length; i++) { 36 | if (mou.hasOwnProperty(p[i])) { 37 | mou = mou[p[i]]; 38 | } else { 39 | mou = ""; 40 | break; 41 | } 42 | } 43 | if (mou == undefined || mou === null) { 44 | 45 | return ""; 46 | 47 | } else { 48 | 49 | return mou; 50 | 51 | } 52 | } 53 | /* 54 | * 55 | //获得属性值 并建立映射表 本文件私有方法 56 | *moudel 属性所在模型 57 | * 属性p 有可能为 xxx.xxx 58 | * uuid 属性唯一id 59 | * type 类型$visible attr css prop textarea value class text test select radio check widget 60 | * exp 表达式 比如{name}+':'+{age} 61 | * widget 是否为控件 62 | * */ 63 | var getValue = function (moudel, p, uuid, type, exp, widget) { 64 | var retValue; 65 | (function (mou) { 66 | p = p.substr(1, p.length - 2); 67 | p = p.mySplit("."); 68 | var parent1, parent2; 69 | var parentName1, parentName2; 70 | for (var i = 0; i < p.length; i++) { 71 | parentName1 = parentName2; 72 | parentName2 = p[i]; 73 | if (mou.hasOwnProperty(p[i])) { 74 | parent1 = parent2; 75 | parent2 = mou; 76 | mou = mou[p[i]]; 77 | } else if (i === p.length - 1) { 78 | parent1 = parent2; 79 | parent2 = mou; 80 | mou[p[i]] = ""; 81 | mou = mou[p[i]] 82 | } else { 83 | mou[p[i]] = {}; 84 | parent1 = parent2; 85 | parent2 = mou; 86 | mou = mou[p[i]]; 87 | 88 | } 89 | } 90 | retValue = mou; 91 | if (qclib.isArray(parent2)) { 92 | if (parent1 !== undefined) { 93 | if (!parent1.hasOwnProperty("$map")) { 94 | parent1.$map = {}; 95 | } 96 | if (!parent1.$map.hasOwnProperty(parentName1)) { 97 | parent1.$map[parentName1] = {}; 98 | } 99 | if (!parent1.$map[parentName1].hasOwnProperty(uuid)) { 100 | parent1.$map[parentName1][uuid] = []; 101 | } 102 | if (widget === undefined) { 103 | parent1.$map[parentName1][uuid].push({uuid: uuid, type: type, exp: exp, vm: moudel}); 104 | } else { 105 | parent1.$map[parentName1][uuid].push({ 106 | uuid: uuid, 107 | type: type, 108 | exp: exp, 109 | vm: moudel, 110 | widget: widget 111 | }); 112 | } 113 | } 114 | } else { 115 | if (parent2 !== undefined) { 116 | if (!parent2.hasOwnProperty("$map")) { 117 | parent2.$map = {}; 118 | } 119 | if (!parent2.$map.hasOwnProperty(parentName2)) { 120 | parent2.$map[parentName2] = {}; 121 | } 122 | if (!parent2.$map[parentName2].hasOwnProperty(uuid)) { 123 | parent2.$map[parentName2][uuid] = []; 124 | } 125 | if (widget === undefined) { 126 | parent2.$map[parentName2][uuid].push({uuid: uuid, type: type, exp: exp, vm: moudel}) 127 | } else { 128 | parent2.$map[parentName2][uuid].push({ 129 | uuid: uuid, 130 | type: type, 131 | exp: exp, 132 | vm: moudel, 133 | widget: widget 134 | }) 135 | } 136 | } 137 | } 138 | }) 139 | (moudel) 140 | if (retValue == null || retValue == undefined) { 141 | return "" 142 | } else { 143 | return retValue; 144 | } 145 | } 146 | 147 | /* 148 | 计算表达式值 149 | *moudel 表达式所在模型 150 | * expList 表达式如{name}+':'+{age} 151 | */ 152 | var count = function (moudel, expList) { 153 | var text = expList; 154 | var textList = []; 155 | for (var i = 0; i < text.length; i++) { 156 | if (text[i].indexOf("{") == 0) { 157 | textList.push({option: false, value: valuePro(moudel, text[i])}) 158 | } else { 159 | textList.push({option: true, value: text[i]}); 160 | } 161 | } 162 | try { 163 | var myValue = qclib.parse(textList); 164 | var t = typeof myValue; 165 | if (t == "string" || t == "number" || t == "boolean") { 166 | return myValue; 167 | } 168 | 169 | } catch (e) { 170 | return ""; 171 | } 172 | } 173 | 174 | /* //在biandata调用 比getValue高一级 175 | *moudel 属性所在模型 176 | * uuid 属性唯一id 177 | * type 类型$visible attr css prop textarea value class text test select radio check widget 178 | * exp 表达式 比如{name}+':'+{age} 179 | * widget 是否为控件 180 | * */ 181 | var expEval = function (moudel, expList, uuid, type, widget) { 182 | var text = expList; 183 | var textList = []; 184 | for (var i = 0; i < text.length; i++) { 185 | if (text[i].indexOf("{") == 0) { 186 | textList.push({option: false, value: getValue(moudel, text[i], uuid, type, text, widget)}) 187 | } else { 188 | textList.push({option: true, value: text[i]}); 189 | } 190 | } 191 | try { 192 | var myValue = qclib.parse(textList); 193 | var t = typeof myValue; 194 | if (t == "string" || t == "number" || t == "boolean") { 195 | return myValue; 196 | } 197 | 198 | } catch (e) { 199 | return ""; 200 | } 201 | } 202 | 203 | var getModel = function (o) { 204 | function _getModel(m) { 205 | var _o; 206 | if (qclib.isArray(m)) { 207 | _o = []; 208 | for (var i = 0; i < m.length; i++) { 209 | _o.push(_getModel(m[i])) 210 | } 211 | } else if (typeof m == "object") { 212 | _o = {}; 213 | for (var p in m) { 214 | if (typeof m[p] !== "function" && p.indexOf("$") < 0) { 215 | if (qclib.isArray(m[p])) { 216 | _o[p] = []; 217 | for (var i = 0; i < m[p].length; i++) { 218 | _o[p].push(_getModel(m[p][i])) 219 | } 220 | } else if (typeof m[p] == "object") { 221 | _o[p] = _getModel(m[p]); 222 | } else { 223 | _o[p] = m[p]; 224 | } 225 | } 226 | } 227 | } else { 228 | _o = m; 229 | } 230 | return _o; 231 | } 232 | 233 | return _getModel(o); 234 | } 235 | 236 | var innerText = function (bindText) {//此处为了兼容火狐不支持 innerText 237 | if (typeof bindText === "string") { 238 | bindText = bindText.replace(//g, ">"); 240 | bindText = bindText.replace(/\r\n/g, ""); 241 | bindText = bindText.replace(/\n/g, ""); 242 | } 243 | return bindText; 244 | } 245 | 246 | //垃圾回收 247 | var collection = function () { 248 | for (var cll in qc.vms) { 249 | var cllDom = document.querySelector("[" + PREFIX + "-id=\"" + cll + "\"" + "]"); 250 | if (cllDom === null) { 251 | delete qc.vms[cll]; 252 | } 253 | } 254 | } 255 | 256 | var load = function () { 257 | for (var i=0; i": ">", 64 | "=>": ">=", 65 | "<": "<", 66 | "=<": "<=" 67 | } 68 | 69 | var caseValue = function (pushStr, list) { 70 | switch (pushStr) { 71 | case "true": 72 | list.push({expType: 1, expValue: true}); 73 | break; 74 | case "false": 75 | list.push({expType: 1, expValue: false}); 76 | break; 77 | case "null": 78 | list.push({expType: 1, expValue: null}); 79 | break; 80 | default: 81 | if (pushStr !== "") { 82 | if (isNaN(pushStr)) { 83 | list.push({expType: 1, expValue: pushStr}); 84 | } else { 85 | list.push({expType: 1, expValue: pushStr * 1}); 86 | } 87 | } 88 | } 89 | } 90 | 91 | //1.针对火狐做的优化 火狐被调用的函数必须定义在调用前 92 | //2. 火狐在调用内联函数的时候 如果 外面有同名函数 会调用外面的 二不调用内联的 93 | 94 | var countExp = function (result, opt, value) { 95 | if (opt === "+") { 96 | result = (result + value); 97 | 98 | } else if (opt === "-") { 99 | result = (result - value); 100 | } else if (opt === "*") { 101 | result = (result * value); 102 | } 103 | else if (opt === "/") { 104 | result = (result / value); 105 | } 106 | else if (opt === "%") { 107 | result = (result % value); 108 | } 109 | else if (opt === "!") { 110 | result = (!value); 111 | } 112 | else if (opt === "&&") { 113 | result = (result && value); 114 | } 115 | else if (opt === "||") { 116 | result = (result || value); 117 | } 118 | else if (opt === "!=") { 119 | result = (result != value) 120 | } 121 | else if (opt === "!==") { 122 | result = (result !== value) 123 | } 124 | else if (opt === ">") { 125 | result = (result > value) 126 | } 127 | else if (opt === ">=") { 128 | result = (result >= value) 129 | } else if (opt === "<") { 130 | result = (result < value) 131 | } 132 | else if (opt === "<=") { 133 | result = (result <= value) 134 | } 135 | else if (opt === "==") { 136 | if (isArray(value)) { 137 | var index = -1; 138 | for (var v = 0; v < value.length; v++) { 139 | if (tree(value[v]) == result) { 140 | index = v; 141 | break; 142 | } 143 | } 144 | result = index; 145 | } else { 146 | result = (result == value) 147 | } 148 | } 149 | else if (opt === "===") { 150 | if (isArray(value)) { 151 | var index = -1; 152 | for (var v = 0; v < value.length; v++) { 153 | if (tree(value[v]) === result) { 154 | index = v; 155 | break; 156 | } 157 | } 158 | result = index; 159 | } else { 160 | result = (result === value) 161 | } 162 | } 163 | else if (opt === "?") { 164 | if (isArray(value)) { 165 | if (result === -1) { 166 | result = tree(value[value.length - 1]); 167 | } else { 168 | if (value.length > result) { 169 | result = tree(value[result]); 170 | } else { 171 | result = ""; 172 | } 173 | } 174 | } else { 175 | result = value; 176 | } 177 | } 178 | return result; 179 | } 180 | 181 | var trope = { 182 | "\\\\": "\\\\"//转义字符串 183 | } 184 | var tmpStr = function (arr, start, end) { 185 | var myA = []; 186 | for (var i = 0; i < arr.length; i++) { 187 | myA.push({option: arr[i].option, value: arr[i].value}) 188 | } 189 | var _arr = myA.splice(start, end); 190 | var retStr = ""; 191 | for (var i = 0; i < _arr.length; i++) { 192 | retStr += _arr[i].value; 193 | } 194 | return retStr; 195 | } 196 | var tmpSplice = function (arr, z) { 197 | var myA = []; 198 | for (var i = 0; i < arr.length; i++) { 199 | myA.push({option: arr[i].option, value: arr[i].value}) 200 | } 201 | var list = []; 202 | var temp = []; 203 | var isStr = ""; 204 | for (var i = 0; i < myA.length; i++) { 205 | var char = myA[i].value; 206 | if (myA[i].option) { 207 | if ((char === "\"" || char === "'" ) && isStr === "") { 208 | isStr = char; 209 | temp.push(myA[i]) 210 | } else if ((char === "\"" || char === "'" ) && isStr === char) { 211 | temp.push(myA[i]) 212 | isStr = ""; 213 | } else if (isStr !== "") { 214 | temp.push(myA[i]) 215 | } else { 216 | if (char === z) { 217 | list.push(temp); 218 | temp = []; 219 | } else { 220 | temp.push(myA[i]) 221 | } 222 | } 223 | } else { 224 | temp.push(myA[i]) 225 | } 226 | if (i === myA.length - 1 && temp.length > 0) { 227 | list.push(temp); 228 | temp = []; 229 | } 230 | } 231 | return list; 232 | } 233 | var tree = function (exp) { 234 | var list = [];//语法树存储 235 | var stack = 0; 236 | var stackQ = 0; 237 | var temp = []; 238 | var isStr = false; 239 | var fun = ""; 240 | var str = ""; 241 | var lock = true; 242 | for (var i = 0; i < exp.length; i++) { 243 | var char = exp[i].value; 244 | if (isStr) { 245 | if (temp.length > 0 && lock) { 246 | var tp = temp.pop(); 247 | if (trope.hasOwnProperty(tp + char)) { 248 | temp.push(char); 249 | lock = false; 250 | continue; 251 | } else { 252 | temp.push(tp); 253 | } 254 | } 255 | lock = true; 256 | if (char === str) { 257 | list.push({expType: 1, expValue: temp.join("")}); 258 | temp = []; 259 | str = ""; 260 | isStr = false; 261 | } else { 262 | temp.push(char); 263 | } 264 | } else { 265 | if (stack > 0) { 266 | if (char === "(") { 267 | stack++; 268 | } else if (char === ")") { 269 | stack--; 270 | } 271 | if (stack === 1) { 272 | if (fun === "") { 273 | list.push({expType: 1, expValue: tree(temp)}); 274 | } else { 275 | var argList = []; 276 | if (temp.length > 0) { 277 | argList = tmpSplice(temp, ","); 278 | for (var a = 0; a < argList.length; a++) { 279 | argList[a] = tree(argList[a]); 280 | } 281 | } 282 | if (qc.fun.hasOwnProperty(fun) && typeof qc.fun[fun] === "function") { 283 | var _value = qc.fun[fun].apply(qc.fun[fun], argList); 284 | if (_value === undefined) { 285 | _value = "\"\"" 286 | } else { 287 | _value = _value; 288 | } 289 | list.push({expType: 1, expValue: _value}); 290 | } else { 291 | window.console && console.log("%c函数" + fun + "未定义", "color:red") 292 | } 293 | fun = ""; 294 | } 295 | temp = []; 296 | stack = 0; 297 | } else { 298 | temp.push(exp[i]); 299 | } 300 | continue; 301 | } 302 | if (stackQ > 0) { 303 | if (char === "[") { 304 | stackQ++; 305 | } else if (char === "]") { 306 | stackQ--; 307 | } 308 | if (stackQ === 1) { 309 | list.push({expType: 1, expValue: tmpSplice(temp, ",")}); 310 | temp = []; 311 | stackQ = 0; 312 | } else { 313 | temp.push(exp[i]); 314 | } 315 | continue; 316 | } 317 | var optStr = ""; 318 | var opt = ""; 319 | var optIndex = 0; 320 | for (var p = temp.length - 1; p >= 0; p--) { 321 | optStr += temp[p].value; 322 | if (option.hasOwnProperty(optStr)) { 323 | opt = optStr; 324 | optIndex = p; 325 | } 326 | } 327 | if (!exp[i].option) { 328 | if (opt !== "") { 329 | var pushStr = tmpStr(temp, 0, optIndex); 330 | if(pushStr!=="") { 331 | caseValue(pushStr, list); 332 | } 333 | caseValue(pushStr, list); 334 | list.push({expType: 0, expValue: option[opt]}); 335 | list.push({expType: 1, expValue: char}); 336 | temp = []; 337 | } else { 338 | list.push({expType: 1, expValue: char}); 339 | temp = []; 340 | } 341 | continue; 342 | } 343 | if ((opt !== "") && (!option.hasOwnProperty(char + opt))) { 344 | var pushStr = tmpStr(temp, 0, optIndex); 345 | if(pushStr!=="") { 346 | caseValue(pushStr, list); 347 | } 348 | list.push({expType: 0, expValue: option[opt]}); 349 | temp = []; 350 | } 351 | if (char === "\"" || char === "'") { 352 | if (temp.length !== 0) { 353 | window.console && console.log("%c表达式:" + exp + "有误 ", "color:red"); 354 | return; 355 | } 356 | isStr = true; 357 | str = char; 358 | } else if (char === "(") { 359 | if (temp.length !== 0) { 360 | fun = tmpStr(temp, 0, temp.length); 361 | temp = []; 362 | } 363 | stack = 2; 364 | } else if (char === "[") { 365 | if (temp.length !== 0) { 366 | window.console && console.log("%c表达式:" + exp + "有误 ", "color:red"); 367 | return; 368 | } 369 | stackQ = 2; 370 | } else { 371 | if (char !== " ") { 372 | temp.push(exp[i]); 373 | } 374 | } 375 | } 376 | } 377 | if (temp.length > 0) { 378 | var endStr = tmpStr(temp, 0, temp.length); 379 | caseValue(endStr, list); 380 | temp = []; 381 | } 382 | 383 | var result; 384 | if (list.length === 0) { 385 | window.console && console.log("%c表达式为空", "color:red"); 386 | return; 387 | } 388 | if (list.length == 1) { 389 | result = list[0].expValue; 390 | } else { 391 | if (list[0].expType === 0) { 392 | if (list[0].expValue === "!") { 393 | result = !list[1].expValue 394 | } else if (list[0].expValue === "-") { 395 | result = -list[1].expValue 396 | } else { 397 | result = list[1].expValue 398 | } 399 | } else { 400 | result = list[0].expValue 401 | var i = 1; 402 | var len = list.length - 1; 403 | while (i < len) { 404 | if (len - i >= 2) { 405 | var opt = list[i + 2].expValue; 406 | var opt0 = list[i].expValue; 407 | if (opt !== "*" && opt !== "/" && opt !== "%") { 408 | result = countExp(result, opt0, list[i + 1].expValue); 409 | i = i + 2; 410 | } else { 411 | var temp = list[i + 1].expValue; 412 | i = i + 2; 413 | while (i < len) { 414 | temp = countExp(temp, list[i].expValue, list[i + 1].expValue); 415 | if (len - i >= 2) { 416 | var opt = list[i + 2].expValue; 417 | i = i + 2; 418 | if (opt !== "*" && opt !== "/" && opt !== "%") { 419 | break; 420 | } 421 | } else { 422 | i = i + 2; 423 | } 424 | } 425 | result = countExp(result, opt0, temp); 426 | } 427 | } else { 428 | result = countExp(result, list[i].expValue, list[i + 1].expValue); 429 | break; 430 | } 431 | } 432 | 433 | } 434 | } 435 | return result; 436 | } 437 | /*计算值*/ 438 | var _exp = []; 439 | for (var i = 0; i < exp.length; i++) { 440 | if (exp[i].option) { 441 | for (var j = 0; j < exp[i].value.length; j++) { 442 | _exp.push({option: true, value: exp[i].value.charAt(j)}); 443 | } 444 | } else { 445 | _exp.push(exp[i]); 446 | } 447 | } 448 | return tree(_exp); 449 | } 450 | if (!window.qclib) { 451 | window.qclib = {}; 452 | } 453 | window.qclib.isArray = isArray; 454 | window.qclib.parse = parse; 455 | })(qc) -------------------------------------------------------------------------------- /src/core/sweep.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by zhangyan on 2016/4/5. 3 | * sweep.js 4 | */ 5 | ;(function (qc) { 6 | var PREFIX = qc.PREFIX; 7 | var bindEvent = function (newDom, _this, vmName, vType, event, rec) { 8 | function getTarget(_this) { 9 | if (_this == null || _this == undefined) { 10 | return;//ie修复 11 | } 12 | var veType 13 | try { 14 | veType = _this.getAttribute(PREFIX + "-vetype"); 15 | } catch (e) { 16 | return;//ie问题修复 17 | } 18 | if ((veType !== undefined) && (veType !== null)) { 19 | if (veType === vType || qc.ve.hasOwnProperty(veType)) { 20 | var path = _this.getAttribute(PREFIX + "-path"); 21 | var veName = _this.getAttribute(PREFIX + "-vename"); 22 | if (qc.vms[vmName].$ve.hasOwnProperty(veName) && typeof qc.vms[vmName].$ve[veName] === "function") { 23 | path = path.split("."); 24 | var vm = qc.vms[path[0]]; 25 | for (var i = 1; i < path.length; i++) { 26 | var s = path[i]; 27 | if (s.indexOf("[") > -1) { 28 | var index = s.substr(s.indexOf("[")); 29 | index = index.substr(1, index.length - 2); 30 | index = index * 1; 31 | s = s.substr(0, s.indexOf("[")); 32 | vm = vm[s][index]; 33 | } else { 34 | vm = vm[s]; 35 | } 36 | } 37 | var run = (function (vmName, veName, _this, vm, event) { 38 | return function (action) { 39 | qc.vms[vmName].$ve[veName].call(_this, vm, event, action);//action 用于扩展组合事件 40 | } 41 | })(vmName, veName, _this, vm, event); 42 | if (veType === vType) { 43 | run(); 44 | } else { 45 | var extend = qc.ve[veType]; 46 | if (extend.hasOwnProperty(vType) && typeof extend[vType] === "function") { 47 | extend[vType].call(extend, run, event, _this); 48 | } 49 | } 50 | } 51 | } else if (_this !== newDom && _this.parentNode !== newDom && rec !== true) { 52 | getTarget(_this.parentNode) 53 | } 54 | } else if (_this !== newDom && _this.parentNode !== newDom) { 55 | getTarget(_this.parentNode) 56 | } 57 | } 58 | 59 | getTarget(_this); 60 | } 61 | 62 | var isMobile = function () { 63 | if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) { 64 | return true; 65 | } 66 | else { 67 | return false; 68 | } 69 | } 70 | //---------------扫描事件----------------// 71 | var sweep = function (_vm) { 72 | var dom = document.querySelector("[" + PREFIX + "-view='" + _vm + "']"); 73 | if (dom !== null) { 74 | var VDom = qclib.htmlToObj(dom); 75 | qc.vms[_vm].$path = _vm + ""; 76 | var outerHtml = qclib.bindData(qc.vms[_vm], VDom); 77 | dom.outerHTML = outerHtml; 78 | qclib.load(); 79 | //绑定事件 80 | var newDom = document.querySelector("[" + PREFIX + "-view='" + _vm + "']"); 81 | newDom.removeAttribute(PREFIX + "-view"); 82 | newDom.setAttribute(PREFIX + "-id", _vm); 83 | var isIn = function (dom) { 84 | var _flag; 85 | try { 86 | _flag = dom.getAttribute(PREFIX + "-id"); 87 | if (_flag !== undefined && _flag !== null) { 88 | return false; 89 | } else { 90 | if (dom.parentNode !== undefined && dom.parentNode !== null) { 91 | return isIn(dom.parentNode) 92 | } else { 93 | return true; 94 | } 95 | } 96 | } catch (e) { 97 | return true; 98 | } 99 | return true; 100 | } 101 | var isTemp = true; 102 | if (newDom.parentNode !== undefined && dom.parentNode !== null) { 103 | isTemp = isIn(dom.parentNode); 104 | } 105 | if (!isTemp) {//如果在容器内部 就不比绑定事件了 106 | return; 107 | } 108 | newDom.onclick = function (e) { 109 | var event = window.event || e; 110 | event.target = event.target ? event.target : event.srcElement;//兼容IE 111 | bindEvent(this, event.target, _vm, "click", event); 112 | } 113 | newDom.ondblclick = function (e) { 114 | var event = window.event || e; 115 | event.target = event.target ? event.target : event.srcElement; 116 | bindEvent(this, event.target, _vm, "dblclick", event); 117 | 118 | } 119 | newDom.onkeydown = function (e) { 120 | var event = window.event || e; 121 | event.target = event.target ? event.target : event.srcElement; 122 | bindEvent(this, event.target, _vm, "keydown", event); 123 | } 124 | newDom.onkeyup = function (e) { 125 | var event = window.event || e; 126 | event.target = event.target ? event.target : event.srcElement; 127 | bindEvent(this, event.target, _vm, "keyup", event); 128 | } 129 | if (isMobile()) {//移动 130 | newDom.addEventListener("touchstart", function (e) { 131 | var event = window.event || e; 132 | event.target = event.target ? event.target : event.srcElement; 133 | bindEvent(this, event.target, _vm, "touchstart", event); 134 | }) 135 | newDom.addEventListener("touchmove", function (e) { 136 | var event = window.event || e; 137 | event.target = event.target ? event.target : event.srcElement; 138 | bindEvent(this, event.target, _vm, "touchmove", event); 139 | }) 140 | newDom.addEventListener("touchend", function (e) { 141 | var event = window.event || e; 142 | event.target = event.target ? event.target : event.srcElement; 143 | bindEvent(this, event.target, _vm, "touchend", event); 144 | 145 | }) 146 | newDom.addEventListener("touchcancel", function (e) { 147 | var event = window.event || e; 148 | event.target = event.target ? event.target : event.srcElement; 149 | bindEvent(this, event.target, _vm, "touchcancel", event); 150 | 151 | }) 152 | 153 | } else {//pc 154 | newDom.onmousedown = function (e) { 155 | var event = window.event || e; 156 | event.target = event.target ? event.target : event.srcElement; 157 | bindEvent(this, event.target, _vm, "mousedown", event); 158 | 159 | } 160 | newDom.onmouseup = function (e) { 161 | var event = window.event || e; 162 | event.target = event.target ? event.target : event.srcElement; 163 | bindEvent(this, event.target, _vm, "mouseup", event); 164 | } 165 | newDom.onmousemove = function (e) { 166 | var event = window.event || e; 167 | event.target = event.target ? event.target : event.srcElement; 168 | bindEvent(this, event.target, _vm, "mousemove", event); 169 | } 170 | newDom.onmouseout = function (e) { 171 | var event = window.event || e; 172 | event.target = event.target ? event.target : event.srcElement; 173 | bindEvent(this, event.target, _vm, "mouseout", event); 174 | bindEvent(this, event.target, _vm, "mouseleave", event, true); 175 | } 176 | newDom.onmouseover = function (e) { 177 | var event = window.event || e; 178 | event.target = event.target ? event.target : event.srcElement; 179 | bindEvent(this, event.target, _vm, "mouseover", event); 180 | bindEvent(this, event.target, _vm, "mouseenter", event, true); 181 | } 182 | } 183 | } 184 | } 185 | qc.widget = {};//控件扩展 186 | qc.ve = {};//事件扩展 187 | qc.vms = {};//储存vm所有对象 188 | qc.vms = []; 189 | qc.load = []; 190 | qc.view = function (name, factory) {//初始化view并扫描 191 | qc.vms[name] = {}; 192 | qc.vms[name].$ve = {}; 193 | qc.vms[name].$watch = []; 194 | qc.vms[name].$ve.$watch = function (path, callback) { 195 | qc.vms[name].$watch.push({path: name + "." + path, callback: callback}) 196 | } 197 | factory(qc.vms[name], qc.vms[name].$ve);//vm对象 198 | delete qc.vms[name].$ve.$watch; 199 | sweep(name); 200 | return qc.vms[name]; 201 | } 202 | })(qc) -------------------------------------------------------------------------------- /src/event.js: -------------------------------------------------------------------------------- 1 | /*移动端事件扩展 2 | * 2016-3-30 3 | * event.js 4 | * */ 5 | ;(function (qc) { 6 | function hasClass(obj, cls) { 7 | return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)')); 8 | } 9 | 10 | function addClass(obj, cls) { 11 | if (!hasClass(obj, cls)) obj.className += " " + cls; 12 | } 13 | 14 | function removeClass(obj, cls) { 15 | if (hasClass(obj, cls)) { 16 | var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)'); 17 | obj.className = obj.className.replace(reg, ' '); 18 | } 19 | } 20 | 21 | /*点击事件*/ 22 | qc.extendEvent({ 23 | name: "tap", 24 | touchstart: function (run, event, element) { 25 | this.y = event.touches[0].pageY; 26 | this.x = event.touches[0].pageX; 27 | addClass(element, "active"); 28 | this.run = true; 29 | }, 30 | touchmove: function (run, event, element) { 31 | if (this.run) { 32 | if (Math.abs(event.touches[0].pageY - this.y) > 12 || Math.abs(event.touches[0].pageX - this.x) > 12) { 33 | this.run = false; 34 | removeClass(element, "active"); 35 | } else { 36 | event.preventDefault();//修复touchend不执行bug\ 37 | } 38 | } 39 | }, 40 | touchend: function (run, event, element) { 41 | removeClass(element, "active"); 42 | if (this.run) { 43 | run(); 44 | } 45 | }, 46 | touchcancel: function (run, event, element) { 47 | removeClass(element, "active"); 48 | } 49 | }); 50 | /*长按事件 51 | * 说明:因为长按时间要屏蔽掉系统的默认事件, 52 | * 所以在需要系统默认事件(比如滚动)的时候,不能使用长按时间 53 | * */ 54 | qc.extendEvent({ 55 | name: "longtap", 56 | touchstart: function (run, event, element) { 57 | event.preventDefault();//修复touchend不执行bug 58 | addClass(element, "active"); 59 | this.timer = setTimeout(function () { 60 | run(); 61 | }, 750) 62 | }, 63 | touchend: function (run, event, element) { 64 | removeClass(element, "active"); 65 | clearTimeout(run); 66 | }, 67 | touchcancel: function (run, event, element) { 68 | removeClass(element, "active"); 69 | clearTimeout(run); 70 | } 71 | }); 72 | /*滑动事件 73 | * 只有左滑(action=left)右滑(action=right)和点击(action=tap) 74 | * 和点击 75 | * */ 76 | qc.extendEvent({ 77 | name: "tapswipe", 78 | touchstart: function (run, event, element) { 79 | this.y = event.touches[0].pageY; 80 | this.x = event.touches[0].pageX; 81 | this.endX = event.touches[0].pageX; 82 | addClass(element, "active"); 83 | this.run = true; 84 | }, 85 | touchmove: function (run, event, element) { 86 | if (this.run) { 87 | if (Math.abs(event.touches[0].pageY - this.y) <= 12) { 88 | event.preventDefault();//修复touchend不执行bug 89 | this.endX = event.touches[0].pageX; 90 | } else { 91 | this.run = false; 92 | removeClass(element, "active"); 93 | } 94 | } 95 | }, 96 | touchend: function (run, event, element) { 97 | removeClass(element, "active"); 98 | if (this.run) { 99 | if (this.endX - this.x > 12) { 100 | run("right"); 101 | } else if (this.endX - this.x < -12) { 102 | run("left"); 103 | } else { 104 | run("tap"); 105 | } 106 | } 107 | }, 108 | touchcancel: function (run, event, element) { 109 | removeClass(element, "active"); 110 | } 111 | }); 112 | })(qc) 113 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | xxxx 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/js/test3.js: -------------------------------------------------------------------------------- 1 | need("$url:../mod/test1")(); 2 | -------------------------------------------------------------------------------- /test/mod/test1.js: -------------------------------------------------------------------------------- 1 | out=function () { 2 | console.log(111); 3 | need("$url:test2")(); 4 | } -------------------------------------------------------------------------------- /test/mod/test2.js: -------------------------------------------------------------------------------- 1 | out=function () { 2 | console.log("test2") 3 | } --------------------------------------------------------------------------------