【问题标题】:How can I get Knockout JS to data-bind on keypress instead of lost-focus?如何让 Knockout JS 在按键上进行数据绑定而不是失去焦点?
【发布时间】:2011-05-22 03:23:14
【问题描述】:

knockout js 的这个示例有效,因此当您编辑字段并按 TAB 时,视图模型数据以及字段下方的文本都会更新。

如何更改此代码,以便每次按键都更新视图模型数据?

<!doctype html>
<html>
    <title>knockout js</title>
    <head>
        <script type="text/javascript" src="js/knockout-1.1.1.debug.js"></script>
        <script type="text/javascript">
        window.onload= function() {

            var viewModel = {
                firstName : ko.observable("Jim"),
                lastName : ko.observable("Smith")
            };
            viewModel.fullName = ko.dependentObservable(function () {
                return viewModel.firstName() + " " + viewModel.lastName();
            });

            ko.applyBindings(viewModel);
       }
        </script>
    </head>
    <body>
        <p>First name: <input data-bind="value: firstName" /></p>
        <p>Last name: <input data-bind="value: lastName" /></p>
        <h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
    </body>
</html>

【问题讨论】:

标签: javascript knockout.js


【解决方案1】:
<body>
        <p>First name: <input data-bind="value: firstName, valueUpdate: 'afterkeydown'" /></p>
        <p>Last name: <input data-bind="value: lastName, valueUpdate: 'afterkeydown'" /></p>
        <h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
</body>

来自documentation

附加参数

  • 值更新

    如果您的绑定还包含一个名为 valueUpdate 的参数,则此 定义 KO 应该使用哪个浏览器事件来检测更改。这 以下字符串值是最常用的选择:

    • "change" (默认) - 当用户更新你的视图模型 将焦点移动到不同的控件,或者在 元素,在任何更改后立即

    • "keyup" - 当用户释放一个键时更新你的视图模型

    • "keypress" - 当用户输入一个 钥匙。与 keyup 不同,这会在用户持有密钥时重复更新 下

    • "afterkeydown" - 一旦用户更新你的视图模型 开始输入一个字符。这通过捕获浏览器的 keydown 事件并异步处理事件。

在这些选项中,“afterkeydown”是您想要的最佳选择 实时更新您的视图模型。

【讨论】:

  • from the docs in knockout.js: // 语法“after”的意思是“在事件发生后异步运行处理程序” // 这很有用,例如,捕获“keydown”浏览器更新控件后的事件
  • 有没有办法让 valueUpdate:'afterkeydown' 成为 default?
  • 对于某些输入框,浏览器会显示“自动填充”值(例如输入字段名为“名字”)。从自动填充中选择不适用于“afterkeydown”。有没有办法抓住这个?
  • @Anton 除了自动填充值之外,还应该捕获屏幕上的键盘单击和鼠标粘贴事件。使用afterkeydown 是一个糟糕的解决方案。
  • 此答案的作者,请更新以包括 Salvador Dali 的答案,从 3.2 开始添加的 textInput 是一个更好的解决方案,因为它与移动浏览器具有更好的兼容性(自动完成之类的功能更好)
【解决方案2】:

在3.2版中,您可以简单地使用textinput binding.:

<input data-bind="textInput: userName" />

它做了两件重要的事情:

  • 立即更新
  • 处理剪切、拖动、自动完成的浏览器差异...

因此不需要额外的模块、自定义控件和其他东西。

【讨论】:

  • 这很好用,正是我需要替换值:字段,valueUpdate: 'input change' 我通过我的应用程序... :) 谢谢。
  • 有没有办法在用户点击新的 HTML5 搜索输入字段上的“x”图标时捕获事件,并在输入为空的情况下采取行动?
【解决方案3】:

如果您希望它“默认”更新afterkeydown,您可以在value 绑定处理程序中注入valueUpdate 绑定。只需提供一个新的allBindingsAccessor 供处理程序使用,其中包括afterkeydown。

(function () {
    var valueHandler = ko.bindingHandlers.value;
    var getInjectValueUpdate = function (allBindingsAccessor) {
        var AFTERKEYDOWN = 'afterkeydown';
        return function () {
            var allBindings = ko.utils.extend({}, allBindingsAccessor()),
                valueUpdate = allBindings.valueUpdate;

            if (valueUpdate === undefined) {
                return ko.utils.extend(allBindings, { valueUpdate: AFTERKEYDOWN });
            } else if (typeof valueUpdate === 'string' && valueUpdate !== AFTERKEYDOWN) {
                return ko.utils.extend(allBindings, { valueUpdate: [valueUpdate, AFTERKEYDOWN] });
            } else if (typeof valueUpdate === 'array' && ko.utils.arrayIndexOf(valueUpdate, AFTERKEYDOWN) === -1) {
                valueUpdate = ko.utils.arrayPushAll([AFTERKEYDOWN], valueUpdate);
                return ko.utils.extend(allBindings, {valueUpdate: valueUpdate});
            }
            return allBindings;
        };
    };
    ko.bindingHandlers.value = {
        // only needed for init
        'init': function (element, valueAccessor, allBindingsAccessor) {
            allBindingsAccessor = getInjectValueUpdate(allBindingsAccessor);
            return valueHandler.init(element, valueAccessor, allBindingsAccessor);
        },
        'update': valueHandler.update
    };
} ());

如果您不习惯“覆盖”value 绑定,您可以为覆盖的自定义绑定指定一个不同的名称并使用该绑定处理程序。

ko.bindingHandlers.realtimeValue = { 'init':..., 'update':... };

demo

这样的解决方案适用于 Knockout 2.x 版。 Knockout 团队通过 Knockout 版本 3 及更高版本中的 textInput 绑定,为类似文本的输入提供了更完整的绑定。它旨在处理文本输入和textarea 的所有文本输入方法。它甚至可以处理实时更新,从而有效地使这种方法过时。

【讨论】:

  • 这种方式让我的标记更加整洁。此外,除了“afterkeydown”之外,还可以添加“input”和“paste”事件来处理粘贴/拖放操作。
  • 在上述解决方案中,我认为“typeof valueUpdated === 'array'”需要替换为“Object.prototype.toString.call(valueUpdate) === '[object Array]' ”。见stackoverflow.com/questions/4775722/…
【解决方案4】:

Jeff Mercado 的回答非常棒,但不幸的是被 Knockout 3 打破了。

但我在完成 Knockout 3 更改时找到了 ko 开发人员建议的答案。请参阅https://github.com/knockout/knockout/pull/932 的底部 cmets。他们的代码:

//automatically add valueUpdate="afterkeydown" on every value binding
(function () {
    var getInjectValueUpdate = function (allBindings) {
        return {
            has: function (bindingKey) {
                return (bindingKey == 'valueUpdate') || allBindings.has(bindingKey);
            },
            get: function (bindingKey) {
                var binding = allBindings.get(bindingKey);
                if (bindingKey == 'valueUpdate') {
                    binding = binding ? [].concat(binding, 'afterkeydown') : 'afterkeydown';
                }
                return binding;
            }
        };
    };

    var valueInitHandler = ko.bindingHandlers.value.init;
    ko.bindingHandlers.value.init = function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        return valueInitHandler(element, valueAccessor, getInjectValueUpdate(allBindings), viewModel, bindingContext);
    };
}());

http://jsfiddle.net/mbest/GKJnt/

编辑 Ko 3.2.0 现在有了一个更完整的解决方案,带有新的“textInput”绑定。查看 SalvidorDali 的回答

【讨论】:

  • 感谢您将答案更新到 3.0!
  • @GrahamT 在 KO 3.2 中你甚至不需要它。是just one line
  • 对于我们这些在 KO 3.2 开始时不了解 TextInput 并且无法更新整个系统中的每个输入的人来说非常好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-25
  • 2013-06-13
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
  • 2021-07-05
  • 2015-07-05
相关资源
最近更新 更多