【问题标题】:contenteditable and non button elementscontenteditable 和非按钮元素
【发布时间】:2010-12-01 13:48:26
【问题描述】:

如果使用按钮,我可以轻松地对 contenteditable 选择执行 execcommand。但是,使用任何其他元素都会失败。

http://jsbin.com/atike/edit

为什么会这样以及如何使用 div 元素使其工作。

谢谢。

【问题讨论】:

  • 不错的完整测试用例。
  • stackoverflow 使用的 WMD 编辑器在单击工具栏按钮时设法保持文本框中的选择。这些按钮被实现为 <li> 元素,与您的示例没有什么不同。当然,它没有使用contenteditable,但仍然保留了选择。可能有兴趣,github上的WMD编辑器:github.com/derobins/wmd/blob/master/wmd.js
  • 我查看了 WMD 编辑器,其中有代码可以在单击工具栏按钮时记住选择,然后重新应用该选择。在 textarea 中操作选择要简单一些,因为它只是一个开始和结束数字,而不是一个范围对象。但它看起来像是对我有用的原则。

标签: javascript contenteditable


【解决方案1】:

您可以通过在正在使用的元素上使用mousedown 事件而不是按钮来保存选择,并在关注click 事件中的可编辑元素后再次恢复它。

我修改了示例代码:http://jsbin.com/atike/40/edit。代码如下:

function saveSelection() {
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            var ranges = [];
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                ranges.push(sel.getRangeAt(i));
            }
            return ranges;
        }
    } else if (document.selection && document.selection.createRange) {
        return document.selection.createRange();
    }
    return null;
}

function restoreSelection(savedSel) {
    if (savedSel) {
        if (window.getSelection) {
            sel = window.getSelection();
            sel.removeAllRanges();
            for (var i = 0, len = savedSel.length; i < len; ++i) {
                sel.addRange(savedSel[i]);
            }
        } else if (document.selection && savedSel.select) {
            savedSel.select();
        }
    }
}

$(function() {
  var savedSel;

  $('.bold').mousedown(function () {
    savedSel = saveSelection();
  });

  $('.bold').click(function () {
    $('#hello').focus();
    if (savedSel) {
      restoreSelection(savedSel);
    }
    document.execCommand("bold", false, null);    
  });
});

【讨论】:

  • 非常感谢 - 有一个赏金。我现在有一个带有工作按钮的富文本编辑器。我不能使用 unselectable/mousedown 覆盖的原因是富文本编辑器中的某些控件,例如插入链接,实际上需要能够获得文本焦点。
【解决方案2】:

大多数(如果不是全部)所见即所得的编辑器都使用iframe 元素以避免丢失选择。另一种方法(虽然我没有尝试过)是在mouseup 事件触发后存储在该页面上所做的每个选择。

看看这个关于Midas的页面,Gecko 的内置富文本编辑器。

【讨论】:

  • 嗯,这绝对不是全部。许多编辑器,包括 google 文档,不使用 iframe。他们必须以某种方式做到这一点。
  • 我检查并意识到我想到的编辑器之一只是使用按钮。
  • @Mark 是哪一个?如果我选择使用按钮,我需要弄清楚如何设置它们的样式。
  • 样式化 HTML 按钮并不难:tyssendesign.com.au/articles/css/styling-form-buttons.
【解决方案3】:

发生的情况是,当您单击文本节点时,浏览器想要选择该文本。按钮不是文本流的一部分,因此不会触发新的选择。

您所要做的就是阻止浏览器执行重新选择。当您当前正在观察的click 事件运行时,选择已经发生,现在采取行动为时已晚。对于除 MSIE 之外的所有浏览器,该操作开始在 mousedown 上发生,它具有特殊的选择事件。

这适用于跨浏览器的我:

jQuery('.bold')
  .attr('unselectable','on') // prevents selection in MSIE
  .bind('mousedown',function (e) {
    document.execCommand("bold", false, null);
    e.preventDefault(); // prevents selection in all but MSIE
  });

使用 MSIE 的选择事件有一些复杂性(例如还必须阻止拖动),因此使用专用属性 unselectable(需要值“on”)。

您显然仍然可以在click 事件中执行execCommand 处理,只需在所有用作“按钮”的元素上运行选择阻止代码:

jQuery('.buttonlike')
  .attr('unselectable','on') // prevents selection in MSIE
  .bind('mousedown',function (e) {
    e.preventDefault(); // prevents selection in all but MSIE
  });

jQuery('#edit-bold').click(function(){
  document.execCommand("bold", false, null);
});

【讨论】:

    【解决方案4】:

    NicEdit 使用方法的组合。

    • 大多数工具栏元素都设置了“不可选择”属性 - 这适用于 Internet Explorer。

    • 在相同的元素上,它会注册“mousedown”事件并覆盖默认操作 - 这会阻止文本解决方案和焦点。这仅适用于 IE 以外的浏览器。

    • 一些工具栏元素需要能够接收文本焦点并进行选择,例如用于插入链接或图像的字段。对于这些,它会在编辑器失去焦点之前保存选择,然后在用户完成编辑并需要进行更改后恢复它。

      关于如何实现它,请查看 NicEdit 的代码。搜索函数名称:

      • getSel
      • getRng
      • selRng
      • 保存
      • restoreRng

      ...

      这使用浏览器的 getSelection() 或 document.selection 获取选择,getRangeAt() 将其转换为范围,并使用 addRange() 或 select() 将该范围恢复为选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-16
      • 2011-04-04
      • 1970-01-01
      • 2013-10-17
      • 1970-01-01
      • 2017-05-05
      • 1970-01-01
      相关资源
      最近更新 更多