【www.bbyears.com--js教程】
最近在使用Knockoutjs开发移动端,初次搞移动端的前端,碰到了许多问题,现在讲讲创建自定义bindings(不知道怎么翻译这个单词好,索性用英文了)。
在开发的过程中,起初没有考虑click事件在移动端会存在延迟300ms的问题(其实我一开始也知道这个问题,打算先把功能做完再处理这个问题)。做完之后发现click事件的用户体验实在是太差了,然后换成touchstart事件,但发现touchstart事件在用户滑动页面时容易误触发,所以找了一个tap事件的插件https://github.com/pukhalski/tap。
于是我需要将页面中的data-bind="click:fn"替换成data-bind="event:{tap:fn}",替换的地方太多了,而且这样写看的不爽,就不能直接将click替换成tap吗?,于是我想起了Knockoutjs的自定义Bindings,按照官方文档的介绍,增加了tapbinding:
ko.bindingHandlers.tap = { init : function (element, valueAccessor, allBindings, viewModel, bindingContext) { $(element).on("tap", function () { valueAccessor()(viewModel, $(this)); }); } }
于是,页面中的data-bind="tap:fn"可以正常运行。
如果模型是这样的:
var model = { fn:function(data,event){ /// www.xiaoboy.com原创... } }
于是我在想,能不能做到和click传过来的参数一模一样(其实这样已经满足了我的业务需求了)?查看了一下Knockoutjs的源代码,看了类似click的实现方法,其中有一段代码:
function makeEventHandlerShortcut(eventName) { ko.bindingHandlers[eventName] = { 'init' : function (element, valueAccessor, allBindings, viewModel, bindingContext) { var newValueAccessor = function () { var result = {}; result[eventName] = valueAccessor(); return result; }; return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext); } } }
从该函数可以看出,data-bind="click:fn"其实就是data-bind="event:{click:fn}"的快捷方式,如果需要添加tap的快捷方式,只需要给makeEventHandlerShortcut方法传入tap参数即可,最终tap的自定义binding的实现方法如下:
ko.bindingHandlers.tap = { init : function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { var newValueAccessor = function () { return { tap : valueAccessor() }; }; return ko.bindingHandlers['event']['init'].call(this, element, newValueAccessor, allBindings, viewModel, bindingContext); } };
此时tap与click传递的参数是一模一样的。