knockout contentEditable binding

eno*_*ixi 15 knockout.js

我编写了一个自定义绑定处理程序,可以切换元素是否为contentEditable.我还希望在编辑元素的内容时更新任何html绑定,因此它会侦听输入事件并更新html绑定(如果可用).

ko.bindingHandlers.contentEditable = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.unwrap(valueAccessor());
        element.contentEditable = value;

        var $element = $(element);

        if (value) {
            var allBindings = allBindingsAccessor();
            var htmlBinding = allBindings.html;

            if (ko.isWriteableObservable(htmlBinding)) {
                $element.on("input", function (event) {
                    htmlBinding(element.innerHTML);
                });
            }
        } else {
            $element.off("input");
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

但是,问题出在这里:

  • 用户在元素中键入内容
  • 触发输入事件
  • html绑定已更新
  • 元素的innerHTML已更新
  • 元素中的光标位置返回到开头

一个jsfiddle说千言万语...... http://jsfiddle.net/93eEr/1/

关于如何处理这件事,我有点难过.

Tom*_*lak 19

ko.bindingHandlers.htmlLazy = {
    update: function (element, valueAccessor) {
        var value = ko.unwrap(valueAccessor());
        
        if (!element.isContentEditable) {
            element.innerHTML = value;
        }
    }
};
ko.bindingHandlers.contentEditable = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.unwrap(valueAccessor()),
            htmlLazy = allBindingsAccessor().htmlLazy;
        
        $(element).on("input", function () {
            if (this.isContentEditable && ko.isWriteableObservable(htmlLazy)) {
                htmlLazy(this.innerHTML);
            }
        });
    },
    update: function (element, valueAccessor) {
        var value = ko.unwrap(valueAccessor());
        
        element.contentEditable = value;
        
        if (!element.isContentEditable) {
            $(element).trigger("input");
        }
    }
};

var viewModel = {
    editable: ko.observable(false),
    content: ko.observable("<i>This</i> is the initial content!")
};

ko.applyBindings(viewModel);
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<label>Editable: <input type="checkbox" data-bind="checked: editable"/></label>
<hr>
<div data-bind="contentEditable: editable, htmlLazy: content"></div>
<hr>
<pre data-bind="text: content"></pre>
Run Code Online (Sandbox Code Playgroud)

以最小的改变来做这个伎俩 见http://jsfiddle.net/93eEr/3/

你可以调用绑定处理程序htmlEditable,也许这比调用它"懒惰"更好.由你决定.

请注意,"输入"事件实际上并不需要每次都被绑定.当元素不满足时,它不会发射.

  • +1这非常有用.注意,如果你将`contentEditable`处理程序中的绑定更改为以下内容,它也适用于IE:`$(element).on("输入模糊键盘粘贴复制剪切鼠标",函数(){`[etc] (2认同)
  • 如果您决定在DOM上设置`contentEditable ='true'`,这将无法正常工作.为了解决这个问题,我添加了:`element.innerHTML = htmlLazy();`到contentEditable init处理程序. (2认同)