模板的发明是编程史上的一大里程碑,让我们摆脱了烦锁且易出错的字符串拼接,维护性大大提高。

都在JSP,ASP时代,人们已经学会使用include等语句,将多个页面片断拼接成一个页面。
此外,为了将数据库中的数据或业务中用到的变量输出到页面,我们需要将页面某个地方标记一下,将变量塞到里面去。
最后,出于方便循环输出一组数据,就需要将each语句从HTML里撕开一道口子,加上其他什么if语句,页面上其实变撕裂成两部分
一种是与后端语言相近的逻辑部分,一个是够为纯净的HTML部分,到最后,模板引擎就发展出来。

在jQuery王朝的后期,业务逻辑不断往前搬,前端模板也发明出来了。这些模板我统称为静态模板或字符串模板,特征是模板是放在
一个script标签或textarea标签里。静态模板的好处是统一管理,我们从script标签等抽取内容时,它是原汁原味,没有被窜改。
缺点是破坏原有的结构。MVVM时代,knockout, ember等率先发明动态模板,或叫DOM模块,特点是通过在元素节点上标记一些特殊属性,注明此元素里面会输出什么内容
或此元素的子元素是作用循环体要循环多少次,当然if等输出不输出很小儿科。缺点是,需要对文档的整体或某一区域进行扫描,这里耗时比静态模板多上几倍,并且定界符(用于输出变量的标记)可能离奇失踪。但这也没什么大不了,现在流行的两种定界符形式≈lt&;, %>{{ }}在IE10+或W3C浏览器活得好好的,IE6-9,我们只要避开大于小于号就行了。
此外动态模板与静态模板最大的不同在于,它是没有编译函数,而是通过扫描文档,根据节点上的定界符与绑定属性实现循环输出,填空等功能。

我们看一下avalon是怎么做的。大致分两块,定义VM,添加绑定。VM是我们操作的主体,绑定是将页面变成模板的关键。

VM的定义

avalon.define("test",function(vm){
vm.aaa = "司徒正美"
})

avalon.define是用来定义VM,第一个参数为VM的ID名,这是用于在页面圈定作用域的范围,对应的绑定属性是ms-controller。因为一个页面可能有多人负责,就存在多个VM了,而VM相当于一个数据据,它们都用于不同的区域,这里就需要用ID来区分了。

添加绑定,我们随便往body一塞就行了

<body>{{aaa}}</body>

这里的{{ }}是定界符,放在文本节点里。我们可以用过avalon.config({interpolate: ["{?", "?}"]})来设置定界符。

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"> </script>
<script>
avalon.define("test", function(vm){
vm.aaa = "司徒正美"
})
</script>
</head>
<body ms-controller="test">
<h3>{{aaa}}</h3>
{{aaa}}
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"> </script>

<script>
avalon.define("test", function(vm){
vm.aaa = "司徒正美"
})
</script>
</head>
<body ms-controller="test">
<h3>{{aaa}}</h3>
{{aaa}}
</body>
</html>

运行代码

但世界上没有这么简单的页面,比如我们要输出一个列表,是不是要这样干呢?

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
avalon.define("test", function(vm) {
vm.a = "2014预言:阿里死磕港交所"
vm.b = "马云进军游戏背后:恐失势电商"
vm.c = "支付宝信息泄露揭大公司管理困境"
vm.d = "盘点2013:智能手机开启的新场景"
})
</script>
</head>
<body ms-controller="test">
<ol>
<li>{{a}}</li>
<li>{{b}}</li>
<li>{{c}}</li>
<li>{{d}}</li>
</ol>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
avalon.define("test", function(vm) {
vm.a = "2014预言:阿里死磕港交所"
vm.b = "马云进军游戏背后:恐失势电商"
vm.c = "支付宝信息泄露揭大公司管理困境"
vm.d = "盘点2013:智能手机开启的新场景"
})
</script>
</head>
<body ms-controller="test">
<ol>
<li>{{a}}</li>
<li>{{b}}</li>
<li>{{c}}</li>
<li>{{d}}</li>
</ol>
</body>
</html>

运行代码

当然不行,这要定义多少个变量啊!这时就需用到循环绑定,ms-repeat!

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
avalon.define("test", function(vm) {
vm.array = ["2014预言:阿里死磕港交所",
"马云进军游戏背后:恐失势电商",
"支付宝信息泄露揭大公司管理困境", "盘点2013:智能手机开启的新场景"]
})
</script>
</head>
<body ms-controller="test">
<ol>
<li ms-repeat="array">{{el}}</li>
</ol>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
avalon.define("test", function(vm) {
vm.array = ["2014预言:阿里死磕港交所",
"马云进军游戏背后:恐失势电商",
"支付宝信息泄露揭大公司管理困境", "盘点2013:智能手机开启的新场景"]
})
</script>
</head>
<body ms-controller="test">
<ol>
<li ms-repeat="array">{{el}}</li>
</ol>
</body>
</html>

运行代码

ms-repeat相当于ms-each-el,后面的-el是可配置可省略。比如改成ms-repeat-elem,那么对应的位置要改成{{elem}}。

我们还可以输出2维数组

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
avalon.define("test", function(vm) {
vm.array = [[1, 2], [4, 5], [7, 8]]
})
</script>
</head>
<body ms-controller="test">
<table width="80%" border="1">
<tr ms-repeat-item="array">
<td ms-repeat="item">{{el}}</td>
</tr>
</table>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
avalon.define("test", function(vm) {
vm.array = [[1, 2], [4, 5], [7, 8]]
})
</script>
</head>
<body ms-controller="test">
<table width="80%" border="1">
<tr ms-repeat-item="array">
<td ms-repeat="item">{{el}}</td>
</tr>
</table>
</body>
</html>

运行代码

输出对象数组

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
var model = avalon.define("test", function(vm) {
vm.array = [{name: 111}, {name: 222}, {name: 333}]
})
</script> </head>
<body ms-controller="test">
<ul>
<li ms-repeat-me="array">{{me.name}}</li>
</ul>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
var model = avalon.define("test", function(vm) {
vm.array = [{name: 111}, {name: 222}, {name: 333}]
})
</script>

</head>
<body ms-controller="test">
<ul>
<li ms-repeat-me="array">{{me.name}}</li>
</ul>
</body>
</html>

运行代码

现在大家算是对ms-repeat算是有一个大体的了解吧。那么我们学一点高级的。avalon.define会返回一个VM对象,我们通过操作它就能实现页面的操作数据即操作DOM!!!,比如vmodel.array.push。另,我们想输出每个元素对应的索引值,可以使用$index这个变量。

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
var model = avalon.define("test", function(vm) {
vm.array = [{name: 111}, {name: 222}, {name: 333}]
})
var array = model.array
setInterval(function(){
array.push({name: Math.random().toString(32).substr(4,14)})
if(array.length > 10){
array.shift()
}
},500)
</script> </head>
<body ms-controller="test">
<ul>
<li ms-repeat="array">{{$index}}--{{el.name}}</li>
</ul>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
var model = avalon.define("test", function(vm) {
vm.array = [{name: 111}, {name: 222}, {name: 333}]
})
var array = model.array
setInterval(function(){
array.push({name: Math.random().toString(32).substr(4,14)})
if(array.length > 10){
array.shift()
}
},500)
</script>

</head>
<body ms-controller="test">
<ul>
<li ms-repeat="array">{{$index}}--{{el.name}}</li>
</ul>
</body>
</html>

运行代码

之所以 能有这样神奇的效果,是因为avalon会将VM中的数组转换为监控数组,它拥有以下方法:

push, shift, unshift, pop, slice, splice, remove, removeAt, removeAll, clear, ensure, sort, reverse, set

现在我们跳前一步,学一下ms-on-*绑定,实现一个更复杂的效果。ms-on-*的*对应一个事件名,属性值为VM中一个函数名,与元素onkeypress, onclick一样,它的第一个参数默认是事件对象,this指向元素节点,不同的是我们已经对IE6-8下的事件对象做了兼容处理。

<!DOCTYPE HTML>
<html>
<head>
<title>ms-repeat</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
avalon.define("test", function(vm) {
vm.array = ["1", "2", "3", "4"]
"push,unshift,remove,ensure".replace(/\w+/g, function(method) {
vm[method] = function(e) {
if (this.value && e.which == 13) {//this为input元素
vm.array[method](this.value);
this.value = "";
}
}
}) vm.removeAt = function(e) {
if (isFinite(this.value) && e.which == 13) {//this为input元素
var a = ~~this.value
vm.array.removeAt(a)
this.value = "";
}
}
"pop,shift,sort,reverse".replace(/\w+/g, function(method) {
vm[method] = function(e) {
vm.array[method]();
}
})
}); </script>
</head>
<body ms-controller="test">
<p>监控数组拥有以下方法,我们可以操作它们就能同步对应的区域</p>
<blockquote>
push, shift, unshift, pop, slice, splice, remove, removeAt, removeAll, clear, ensure, sort, reverse, set
</blockquote>
<ul>
<li ms-repeat="array">数组的第{{$index+1}}个元素为{{el}}</li>
</ul>
<p>对数组进行push操作,并回车<input ms-on-keypress="push"></p>
<p>对数组进行unshift操作,并回车<input ms-on-keypress="unshift"></p>
<p>对数组进行ensure操作,并回车<input ms-on-keypress="ensure"><br/>
(只有数组不存在此元素才push进去)</p>
<p>对数组进行remove操作,并回车<input ms-on-keypress="remove"></p>
<p>对数组进行removeAt操作,并回车<input ms-on-keypress="removeAt"></p>
<p><button type="button" ms-on-click="sort">对数组进行sort操作</button></p>
<p><button type="button" ms-on-click="reverse">对数组进行reverse操作</button></p>
<p><button type="button" ms-on-click="shift">对数组进行shift操作</button></p>
<p><button type="button" ms-on-click="pop">对数组进行pop操作</button></p>
<p>当前数组的长度为<span style="color:red">{{array.size()}}</span>,注意 我们无法修改数组length的固有行为,因此它无法同步视图,需要用size方法。</p>
</body>
</html>

<!DOCTYPE HTML>
<html>
<head>
<title>ms-repeat</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
avalon.define("test", function(vm) {
vm.array = ["1", "2", "3", "4"]
"push,unshift,remove,ensure".replace(/\w+/g, function(method) {
vm[method] = function(e) {
if (this.value && e.which == 13) {//this为input元素
vm.array[method](this.value);
this.value = "";
}
}
})

vm.removeAt = function(e) {
if (isFinite(this.value) && e.which == 13) {//this为input元素
var a = ~~this.value
vm.array.removeAt(a)
this.value = "";
}
}
"pop,shift,sort,reverse".replace(/\w+/g, function(method) {
vm[method] = function(e) {
vm.array[method]();
}
})
});

</script>
</head>
<body ms-controller="test">
<p>监控数组拥有以下方法,我们可以操作它们就能同步对应的区域</p>
<blockquote>
push, shift, unshift, pop, slice, splice, remove, removeAt, removeAll, clear, ensure, sort, reverse, set
</blockquote>
<ul>
<li ms-repeat="array">数组的第{{$index+1}}个元素为{{el}}</li>
</ul>
<p>对数组进行push操作,并回车<input ms-on-keypress="push"></p>
<p>对数组进行unshift操作,并回车<input ms-on-keypress="unshift"></p>
<p>对数组进行ensure操作,并回车<input ms-on-keypress="ensure"><br/>
(只有数组不存在此元素才push进去)</p>
<p>对数组进行remove操作,并回车<input ms-on-keypress="remove"></p>
<p>对数组进行removeAt操作,并回车<input ms-on-keypress="removeAt"></p>
<p><button type="button" ms-on-click="sort">对数组进行sort操作</button></p>
<p><button type="button" ms-on-click="reverse">对数组进行reverse操作</button></p>
<p><button type="button" ms-on-click="shift">对数组进行shift操作</button></p>
<p><button type="button" ms-on-click="pop">对数组进行pop操作</button></p>
<p>当前数组的长度为<span style="color:red">{{array.size()}}</span>,注意 我们无法修改数组length的固有行为,因此它无法同步视图,需要用size方法。</p>
</body>
</html>

运行代码

有了批量输出的ms-repeat及通过调用监控数组的方法就能实现对应节点的删除添加排序,那么实现grid简直易如反掌。

<!DOCTYPE HTML>
<html>
<head>
<title>ms-repeat</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
if (!Date.now) {
Date.now = function() {
return new Date - 0;
}
}
avalon.define('test', function(scope) {
scope.selected = "name"
scope.options = ["name", "size", "date"]
scope.trend = 1
scope.data = [
{name: "aaa", size: 213, date: Date.now() + 20},
{name: "bbb", size: 4576, date: new Date - 4},
{name: "ccc", size: 563, date: new Date - 7},
{name: "eee", size: 3713, date: 9 + Date.now()},
{name: "555", size: 389, date: Date.now() - 20}
];
scope.$watch("selected", function(v) {
var t = parseFloat(scope.trend)
scope.data.sort(function(a, b) {
var ret = a[v] > b[v] ? 1 : -1
return t * ret
})
})
scope.$watch("trend", function(t) {
var v = scope.selected, t = parseFloat(t)
scope.data.sort(function(a, b) {
var ret = a[v] > b[v] ? 1 : -1
return t * ret
})
})
}); </script>
</head>
<body ms-controller="test">
<p>
<select ms-duplex="selected">
<option ms-repeat="options">{{el}}</option>
</select>
<select ms-duplex="trend">
<option value="1">up</option>
<option value="-1">down</option>
</select>
</p>
<table width="500px" border="1">
<tbody >
<tr ms-repeat="data">
<td>{{el.name}}</td> <td>{{el.size}}</td> <td>{{el.date}}</td>
</tr>
</tbody>
</table>
</body>
</html>

<!DOCTYPE HTML>
<html>
<head>
<title>ms-repeat</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
if (!Date.now) {
Date.now = function() {
return new Date - 0;
}
}
avalon.define('test', function(scope) {
scope.selected = "name"
scope.options = ["name", "size", "date"]
scope.trend = 1
scope.data = [
{name: "aaa", size: 213, date: Date.now() + 20},
{name: "bbb", size: 4576, date: new Date - 4},
{name: "ccc", size: 563, date: new Date - 7},
{name: "eee", size: 3713, date: 9 + Date.now()},
{name: "555", size: 389, date: Date.now() - 20}
];
scope.$watch("selected", function(v) {
var t = parseFloat(scope.trend)
scope.data.sort(function(a, b) {
var ret = a[v] > b[v] ? 1 : -1
return t * ret
})
})
scope.$watch("trend", function(t) {
var v = scope.selected, t = parseFloat(t)
scope.data.sort(function(a, b) {
var ret = a[v] > b[v] ? 1 : -1
return t * ret
})
})
});

</script>
</head>
<body ms-controller="test">
<p>
<select ms-duplex="selected">
<option ms-repeat="options">{{el}}</option>
</select>
<select ms-duplex="trend">
<option value="1">up</option>
<option value="-1">down</option>
</select>
</p>
<table width="500px" border="1">
<tbody >
<tr ms-repeat="data">
<td>{{el.name}}</td> <td>{{el.size}}</td> <td>{{el.date}}</td>
</tr>
</tbody>
</table>
</body>
</html>

运行代码

这里用到了ms-duplex, $watch,大家可以到《入门教程》看看,都是很简单的东西。

接着我们再看看如何循环输出对象吧,它也是用ms-repeat,不过里面的变量为$key, $val。不用多言,看例子。

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
var model = avalon.define("test", function(vm) {
vm.object = {
grape: "葡萄",
coconut: "椰子",
pitaya: "火龙果",
orange: "橙子"
} }) </script> </head>
<body ms-controller="test">
<ul>
<li ms-repeat="object">{{$key}}--{{$val}}</li>
</ul>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
var model = avalon.define("test", function(vm) {
vm.object = {
grape: "葡萄",
coconut: "椰子",
pitaya: "火龙果",
orange: "橙子"
}

})

</script>

</head>
<body ms-controller="test">
<ul>
<li ms-repeat="object">{{$key}}--{{$val}}</li>
</ul>
</body>
</html>

运行代码

好了,循环输出就到这里。我们最后看一下如何实现其他模板引擎的if语句。它的名字为ms-if,如果值为真就输出,否则不输出。

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
var model = avalon.define("test", function(vm) {
vm.toggle = true
vm.click = function(){
vm.toggle = !vm.toggle
}
vm.text = "捉迷藏" }) </script> </head>
<body ms-controller="test">
<p ms-if="toggle">{{text}} </p>
<button type="button" ms-on-click="click">点我{{toggle ? '隐藏' : "显示"}}</button>
</body>
</html>

<!DOCTYPE html>
<html>
<head>
<title>avalon</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script src="http://files.cnblogs.com/rubylouvre/avalon20130929.js"></script>
<script>
var model = avalon.define("test", function(vm) {
vm.toggle = true
vm.click = function(){
vm.toggle = !vm.toggle
}
vm.text = "捉迷藏"

})

</script>
</head>
<body ms-controller="test">
<p ms-if="toggle">{{text}} </p>
<button type="button" ms-on-click="click">点我{{toggle ? '隐藏' : "显示"}}</button>
</body>
</html>

运行代码

{{}}, ms-repeat, ms-if这就是动态模板相对静态模板的所有功能了,但由于动态模板在扫描之后,得到所有要处理的节点的引用,这也意味着,以后我们要做一小部分的更新,不用像静态模板那样大规模替换,而是细化到每一个元素节点,特性节点或文本节点。这就是所谓的“最小化刷新”技术。一般的,只有ms-if等少量绑定才影响到元素节点那一层面,更多的时候, 我们是在刷新特性节点的value值,文本节点的data值,这也意味着,我们的刷新不会引起reflow。加之,能得到元素节点本上,我们就可以轻松实现绑定事件,操作样式,修改属性等功能。这也是为什么大多数MVVM框架选择动态模板的缘故,jQuery原来可以做的,我们全部通过绑定属性或定界符在HTML里搞定。 这也意味着,我们实现了完美的分层架构,JS里面是纯粹的模型层(包括model与viewmodel),HTML里是学习成本与维护成本极低的视图层。这已经不是多了一个模板引擎这么简单的事,我们抢到了 一直以来属性于后端的禁脔——分层架构

迷你MVVM框架 avalonjs 沉思录 第3节 动态模板的更多相关文章

  1. 迷你MVVM框架 avalonjs 沉思录 第2节 DOM操作的三大问题

    jQuery之所以击败Prototype.js,是因为它自一开始就了解这三大问题,并提出完善的解决方案. 第一个问题,DOM什么时候可用.JS不像C那样有一个main函数,里面的逻辑不分主次.但JS是 ...

  2. 迷你MVVM框架 avalonjs 沉思录 第1节 土耳其开局

    #cnblogs_post_body p{ text-indent:2em; margin-top: 1em; } 正如一切传说的开端那样,有一远古巨神开天辟地,然后就是其他半神喧宾夺主.我们对最巨贡 ...

  3. 迷你MVVM框架 avalonjs 0.95发布

    迷你MVVM框架 avalonjs 0.95发布 本版本最主要的改进是ms-with 深层绑定的实现,至少,avalon1.0所有重要的feature已经开发完毕,之后就是小补小漏,性能优化了. ms ...

  4. 迷你MVVM框架 avalonjs 0.85发布

    迷你MVVM框架 avalonjs 0.85发布 本版本对循环绑定做了巨大改进,感谢@soom, @limodou, @ztz, @Gaubee 提供的大量测试文件. fix scanNodes, 在 ...

  5. 迷你MVVM框架 avalonjs 0.82发布

    迷你MVVM框架 avalonjs 0.82发布 本版本最大的改进是启用全新的parser. parser是用于干什么的?在视图中,我们通过绑定属性实现双向绑定,比如ms-text="fir ...

  6. 迷你MVVM框架 avalonjs 1.3.9发布

    本次升级,avalon改进了许多内部方法,大大提升性能,并且带来异步刷新视图的新功能. ms-html内部不再使用异步 head元素中的avalon元素加入ms-skip指令 重构计算属性,现在超级轻 ...

  7. 迷你MVVM框架 avalonjs 1.3.8发布

    avalon1.3.8主要是在ms-repeat. ms-each. ms-with等循环绑定上做重大性能优化,其次是对一些绑定了事件的指令添加了roolback,让其CG回收更顺畅. 重构ms-re ...

  8. 迷你MVVM框架 avalonjs 1.3.7发布

    又到每个月的15号了,现在avalon已经固定在每个月的15号发布新版本.这次发布又带来许多新特性,让大家写码更加轻松,借助于"操作数据即操作DOM"的核心理念与双向绑定机制,现在 ...

  9. 迷你MVVM框架 avalonjs 1.3.6发布

    本版本是一次重要的升级,考虑要介绍许多东西,也有许多东西对大家有用,也发到首页上来了. 本来是没有1.36的,先把基于静态收集依赖的1.4设计出来后,发现改动太多,为了平缓升级起见,才减少了一部分新特 ...

随机推荐

  1. phython

    转载 http://www.cnblogs.com/chenny7/p/4062693.html

  2. Web开发框架之权限管理系统

    Web开发框架之权限管理系统 记得我在很早之前,开始介绍我的Winform开发框架和我的WCF开发框架之初,我曾经给出下面的视图,介绍我整理的一个框架体系,其中包含有WInform开发框架以及我的We ...

  3. bzoj2442

    题解: 单调队列+dp f[i]=max(f[j-1]+sum[i]-sum[j]) 然后维护f[j-1]-sum[j]单调性 代码: #include<bits/stdc++.h> us ...

  4. Hibernate结合JPA编写通用泛型多条件查询

    项目中使用Hibernate和JPA对数据库对象进行实例化,但是生成的方法不支持多条件查询.而如果针对每一个数据库对象进行多条件查询编码,则会变得很麻烦,而且一旦以后发生表结构发生变化,这些方法可能还 ...

  5. 第十一次作业 - Alpha 事后诸葛亮

    拖鞋旅游队团队事后诸葛亮会议 前言 队名:拖鞋旅游队 组长博客:https://www.cnblogs.com/Sulumer/p/10054510.html 时间:2018-12-1 20:00 地 ...

  6. fusionjs 学习二 核心概念

    核心概念 middleware 类似express 的中间件模型(实际上是构建在koa中间件模型上的),但是和koa 的中间件有差异 fusionjs 的中间件同时可以运行在浏览器页面加载的时候 se ...

  7. 在Outlook中修改脱机文件(.ost)的保存位置

    方法一 少读者所在公司的邮箱客户端都在使用微软 Exchange Server 的“缓存 Exchange 模式”.Outlook会默认将脱机文件(.ost文件)保存在C盘上. 但很多读者不希望Out ...

  8. 静态链接ffmpeg库注意的问题(转)

    1. 最近使用ffmpeg静态库进行链接,提示 undefined reference,排查发现静态库的顺序导致的,静态库对先后顺序有严格要求 2. 使用ffmpeg库时,在链接时,需要加上-lm - ...

  9. volatile的本质

    1. 编译器的优化 在本次线程内, 当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中:以后,再取变量值时,就直接从寄存器中取值:当变量值在本线程里改变时,会同时把变量的新 ...

  10. iis 更改asp.net 版本设置

    参考来源: https://github.com/neo2018/ZYFC/blob/2e20009097c1e837a6e667a3dffd4224e28f4411/MderFc/Classes/I ...