execCommand:从当前行向下更改所有内容?

execCommand: change everything from the current line down?

不知道这种编辑怎么叫,以前好像在哪里见过。假设您有一篇带有标题、body 和页脚的文章。在您自己的所见即所得编辑器中,每个文章部分都有三个按钮,或者可能有一个包含这些选项的下拉菜单。

当您将文章内容粘贴到编辑器中时,您想使用一个接一个的按钮将内容分成您想要的部分。首先,单击要定义为标题的行。您单击该行的任何部分都没有关系。现在您单击标题按钮,它会将您当前所在的行 及其下方的任何内容 定义为标题。现在单击要定义为 body 的行,然后单击 body 按钮。同样,线上 及其下方 上的所有内容都定义为 body。你对页脚做同样的事情。

execCommand 可以实现类似的功能吗?

开源库 wysiwyg.js 负责处理内容丰富的 div 等繁重工作,并允许您创建适合您需要的前端。你只需要为你需要的功能编写代码,你可以在上面放上你自己的 CSS 样式。我使用下面的 jQuery 版本的库编写了一些示例代码,但上面链接的文档中有大量信息和示例。如果您更容易使用,他们也有纯 JavaScript 变体。

<button id="header">Header</button>
<button id="footer">Footer</button>
<textarea id="editor">Lorem ipsum dolor sit amet</textarea>

<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="http://path/to/wysiwyg.min.js"></script>
<script src="http://path/to/wysiwyg-editor.min.js"></script>

<script>
$(document).ready(function () {
    var editor = $("#editor").wysiwyg();

    $("#header").click(function () {
        editor.wysiwyg("shell").bold().fontSize(30);
    });

    $("#footer").click(function () {
        editor.wysiwyg("shell").italic();
    });
});
</script>

如果你想让它更简单,Quill is a good option. It's still not as "heavy" as CKEditor and has an elegant interface. It also has built-in functionality for styling presets, such as headers and footers. This functionality also doesn't require you to highlight the line(s) you want to format, unlike wysiwyg.js. Though, this could be added into a wysiwyg.js solution with a custom function similar to this

var editor = document.getElementById('editor');
var output = document.getElementById('output');
var format = document.getElementById('format');

var handleCursorChange = function () {
    //track cursor movement
}

editor.onclick = handleCursorChange;
editor.onkeydown = handleCursorChange;
editor.onfocus = handleCursorChange;

format.addEventListener("click", function (e) {
    if(e.target.id === "heading"){
        
        //format based on your requirement
    }
    if(e.target.id === "body"){
        
        //format based on your requirement
    }
    if(e.target.id === "footer"){
        
        //format based on your requirement
    }
});
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>
  <textarea name="editor" id="editor" cols="30" rows="10"></textarea>
  <div id="format">
    <button id="heading">heading</button>
    <button id="body">body</button>
    <button id="footer">footer</button>
  </div>
  <div id="output"></div>
</body>

</html>

为了您自己的理智,最好选择流行的所见即所得编辑器库之一,但如果您坚持自己动手,可以在 JavaScript 中完成。使用 getSelection and getRangeAt 确定光标位置,然后向上冒泡到其父块。将该父级包装在编辑器下方的新 div 节点中。

说明:单击其中一个段落,然后单击其中一个按钮。您将需要 Web 浏览器的开发人员工具栏来注意差异。

离完美还有很长的路要走;当你从上到下工作时效果最好。并且无法处理复杂的嵌套场景;如果您 select 一个段落嵌套在另一个段落的中间,它可能无法捕获到最后。

window.wrap = function(section) {
    var isBlock = function(node) {
        return node.nodeType == 1 &&
               window.getComputedStyle(node).display == 'block';
    };
    var editor = document.getElementById('editor');
    var sel = window.getSelection();
    var range = sel && sel.rangeCount > 0 && sel.getRangeAt(0);
    if (range) {
        for (var node = range.startContainer;
             node && node.parentNode && node.parentNode !== editor &&
             (!isBlock(node) || node === node.parentNode.firstChild);
             node = node.parentNode);
        if (node && node.parentNode && isBlock(node)) {
            var wrapper = document.createElement('div');
            wrapper.className = section;
            var parent = node.parentNode;
            while (parent !== editor && parent === parent.parentNode.lastChild) {
                parent = parent.parentNode;   // break out of earlier wrapper
            } 
            while (node) {
                var next = node.nextSibling;
                wrapper.appendChild(node);
                node = next;
            }
            parent.appendChild(wrapper);
        }   
    }
}
<div>        
<button type="button" onclick="wrap('heading');">heading</button>
<button type="button" onclick="wrap('body');">body</button>
<button type="button" onclick="wrap('footer');">footer</button>
</div>      
<div id="editor" contenteditable="true" style="border:thin black solid; padding:4px">
<p>This is a sample article.</p>
<p>Of course, you can copy/paste your own content here.</p>
<p>But for your convenience, this content will work out of the box.</p>
<p>Let this be our footer.</p>
</div>