KnockoutJS 3.X API 第五章 高级应用(5) 使用预处理扩展Knockout绑定语法
注意:这是一种高级技术,通常仅在创建可重用绑定或扩展语法的库时使用。 这不是你通常需要做的时候使用Knockout构建应用程序。
从Knockout 3.0开始,开发人员可以通过提供在绑定过程中重写DOM节点和绑定字符串的回调来定义自定义语法。
预处理绑定字符串
您可以通过为特定绑定处理程序(例如click,visible或任何自定义绑定处理程序)提供绑定预处理程序,来挂钩Knockout的逻辑来解释数据绑定属性。
为此,将预处理函数附加到绑定处理程序:
ko.bindingHandlers.yourBindingHandler.preprocess = function(stringFromMarkup) { // Return stringFromMarkup if you don't want to change anything, or return // some other string if you want Knockout to behave as if that was the // syntax provided in the original HTML }
具体参数请参见本页后面的API参考。
示例1:设置绑定的默认值
如果你抛弃一个绑定的值,它的默认绑定到未定义。 如果要为绑定具有不同的默认值,可以使用预处理器。 例如,您可以允许通过将uniqueName的默认值设置为true来绑定不带值的值:
ko.bindingHandlers.uniqueName.preprocess = function(val) { return val || 'true'; }
现在你可以这样绑定:
<input data-bind="value: someModelProperty, uniqueName" />
示例2:将表达式绑定到事件
如果您希望能够将表达式绑定到单击事件(而不是Knockout期望的函数引用),则可以为单击处理程序设置预处理器以支持此语法:
ko.bindingHandlers.click.preprocess = function(val) { return 'function($data,$event){ ' + val + ' }'; }
现在你可以这样绑定click:
<button type="button" data-bind="click: myCount(myCount()+1)">Increment</button>
绑定预处理器引用
ko.bindingHandlers.<name>.preprocess(value, name, addBindingCallback)
如果定义,在评估绑定之前,将为每个<name>绑定调用此函数。
参数:
-
value
: Knockout尝试解析绑定值之前的语法(例如,对于Binding:1 + 1,关联值为“1 + 1”作为字符串)。 -
name
: 绑定的名称(例如,对于您的Binding:1 + 1,名称是“yourBinding”作为字符串)。 -
addBinding
: 一个回调函数,您可以选择使用在当前元素上插入另一个绑定。 这需要两个参数,名称和值。 例如,在你的预处理函数中,调用addBinding('visible','acceptsTerms()'); 使Knockout表现得好像该元素上有一个visible:acceptsTerms()绑定。
返回值:
您的预处理函数必须返回要解析并传递到绑定的新字符串值,或返回undefined以删除绑定。
例如,如果你返回'value +“.toUpperCase()”'作为字符串,那么你的Binding:“Bert”会被解释为标记包含你的Binding:“Bert”.toUpperCase()。 Knockout将以正常方式解析返回的值,因此它必须是一个合法的JavaScript表达式。
不返回非字符串值。 这没有意义,因为标记总是一个字符串。
预处理DOM节点
你可以通过提供一个节点预处理器来钩入Knockout的逻辑来遍历DOM。 这是一个函数,Knockout将为它遍历的每个DOM节点调用一次,无论是在UI首次绑定时,还是在注入任何新的DOM子树(例如,通过foreach绑定)时。
为此,请在绑定提供程序上定义preprocessNode函数:
ko.bindingProvider.instance.preprocessNode = function(node) { // Use DOM APIs such as setAttribute to modify 'node' if you wish. // If you want to leave 'node' in the DOM, return null or have no 'return' statement. // If you want to replace 'node' with some other set of nodes, // - Use DOM APIs such as insertChild to inject the new nodes // immediately before 'node' // - Use DOM APIs such as removeChild to remove 'node' if required // - Return an array of any new nodes that you've just inserted // so that Knockout can apply any bindings to them }
示例3:虚拟模板元素
如果你通常使用虚拟元素包含模板内容,正常的语法可以感觉有点冗长。 使用预处理,您可以添加使用单个注释的新模板格式:
ko.bindingProvider.instance.preprocessNode = function(node) { // Only react if this is a comment node of the form <!-- template: ... --> if (node.nodeType == 8) { var match = node.nodeValue.match(/^\s*(template\s*:[\s\S]+)/); if (match) { // Create a pair of comments to replace the single comment var c1 = document.createComment("ko " + match[1]), c2 = document.createComment("/ko"); node.parentNode.insertBefore(c1, node); node.parentNode.replaceChild(c2, node); // Tell Knockout about the new nodes so that it can apply bindings to them return [c1, c2]; } } }
现在,您可以在视图中包含一个模板,如下所示:
<!-- template: 'some-template' -->
预处理API
ko.bindingProvider.instance.preprocessNode(node)
如果已定义,将在处理绑定之前为每个DOM节点调用此函数。 该功能可以修改,删除或替换节点。 任何新节点必须在节点之前立即插入,并且如果添加了任何节点或节点被删除,则函数必须返回现在在文档中代替节点的新节点的数组。