• [译] 通过 contentEditable 属性创建一个所见即所得的编辑器(富文本编辑器)


    译者注

    这只是一篇入门教程,介绍了一些基础知识,仅供参考,切不可因此觉得富文本编辑器很简单。

    创建富文本编辑器是一个非常复杂的工程,需要考虑到方方面面,也有很多坑(请参考原文第一条评论)。

    为免误导大家,特此说明。

    格式说明:链接名词命令


    原文:Create a WYSIWYG Editor With the contentEditable Attribute

    WYSIWYG 编辑器非常常用,你或许在某个时候也使用过。

    WYSIWYG:What You See Is What You Get,所见即所得。

    通过一些第三方库,你可以快速地创建自己的编辑器,但也有一些明显的缺陷。首先,它们很重,许多特性你压根就用不到。另外,定制外观也非常蛋疼。

    本文中,我们将按自己喜欢的风格,创建一个拥有基本格式化功能的、轻量的所见即所得编辑器。

    我们将从介绍 execCommand 开始,因为在实现编辑器的过程中,我们会大量使用到该方法。

    Document.execCommand()

    execCommand 是 document 对象的一个方法,它提供了操作可编辑区域的内容的能力,和 contentEditable 配合使用,就可以实现一个富文本编辑器(rich-text editor)。

    execCommand 方法可以进行各种编辑操作,如 添加链接、选中文本 加粗 或 斜体,修改 字体字体颜色,使用语法如下:

    document.execCommand(CommandName, ShowDefaultUI, ValueArgument);

    CommandName:DOMString,指定所要执行的命令。

    ShowDefaultUI:Boolean,指定是否显示用户界面,该选项还未完全实现,一般设置为 false。

    ValueArgument:提供命令的附加参数,如图片URL或颜色值。不需要附加参数时,设置为 null。

    我们将使用不同的命令来实现各种功能,下面逐一介绍。

    无附加参数的命令

    部分命令不需要附加参数(ValueArgument),如加粗(bold)、对齐(justify)、撤销(undo)、重做(redo),使用下面的语法:

    document.execCommand(commandName, false, null);

    CommandName 为命令名,如 justifyCenterjustifyRightbold 等。

    带附加参数的命令

    部分命令需要传入相应的附加参数,如插入图片(insertImage)、创建链接(createLink)、字体颜色(foreColor),使用下面的语法:

    document.execCommand(commandName, false, value);

    commandName insertImage 时,value 为将要插入的图片的 URL。

    commandName foreColor 时,value 为颜色值字符串,如 #FF9966、blue。

    添加块样式标签的命令

    添加 HTML 块样式标签(Block-Style Tags),需要将 commandName 指定为 formatBlockValueArgument 设置为标签名(tag name),使用下面的语法:

    document.execCommand('formatBlock', false, tagName);

    该命令将为当前选中行添加一个 HTML 块样式标签,如果本身已带有标签,则将被替换掉。

    tagName 为块样式标签名,如标题标签(h1-h6)、段落标签(p)或块引用(blockquote)。

    上面是一些最常用的命令,更多信息请参考 document.execCommand API 文档,那里有所有可用命令的列表。

    创建一个工具栏

    了解了基础知识,下面我们来创建一个工具栏,工具栏的按钮我使用了 Font Awesome 图标。

    大家可能也注意到了,除了少数区别,所有的 execCommand 命令都有类似的结构,基于这个特点,我们可以使用下面的节点结构来定义工具栏的按钮:

    <a href="#" data-command='commandName'><i class='fa fa-icon'></i></a>

    通过这种方式,当用户点击按钮时,我们可以从 data-command 属性中获取到 execCommand 所要执行的命令。

    例如下面这些例子:

    <a href="#" data-command='h2'>H2</a>
    <a href="#" data-command='undo'><i class='fa fa-undo'></i></a>
    <a href="#" data-command='createlink'><i class='fa fa-link'></i></a>
    <a href="#" data-command='justifyLeft'><i class='fa fa-align-left'></i></a>
    <a href="#" data-command='superscript'><i class='fa fa-superscript'></i></a>

    第一个按钮的 data-command 属性值为 h2,在 JavaScript 中获取到这个值后,我们将使用 execCommand 方法的 添加块样式标签的命令。同样的,最后一个按钮,superscript 则表示应该使用 无附加参数的命令

    创建字体颜色(foreColor)和背景颜色(backColor)按钮则是另外一种实现方法,这里主要有两个问题。

    第一个问题是,提供给用户选择的颜色越多,需要编写的代码就越多,很麻烦而且容易出错。可以使用下面的 JavaScript 来处理这个问题:

    var colorPalette = ['000000', 'FF9966', '6699FF', '99FF66','CC0000', '00CC00', '0000CC', '333333', '0066FF', 'FFFFFF'];
                         
    var forePalette = $('.fore-palette');
     
    for (var i = 0; i < colorPalette.length; i++) {
      forePalette.append('<a href="#" data-command="forecolor" data-value="' + '#' + colorPalette[i] + '" style="background-color:' + '#' + colorPalette[i] + ';" class="palette-item"></a>');
    }

    注意这里我也给每个颜色值设置了一个 data-value 属性,后面可以作为 execCommand 方法的 ValueArgument 参数。

    第二个问题是,我们总不能一直显示那么多颜色块吧,这样会占用很大的空间,给用户带来不好的体验。通过一些简单的 CSS,就可以实现一个不错的效果:只有当用户把鼠标移上按钮时,才会显示调色板。

    按钮的节点结构需要调整为:

    <div class="fore-wrapper"><i class='fa fa-font'></i>
      <div class="fore-palette">
      </div>
    </div>

    要让按钮在鼠标移上时才显示,我们需要添加以下 CSS:

    .fore-palette,
    .back-palette {
      display: none;
    }
     
    .fore-wrapper:hover .fore-palette,
    .back-wrapper:hover .back-palette {
      display: block;
      float: left;
      position: absolute;
    }

    在 CodePen 的 示例 中,还有许多其它的 CSS 代码用于美化工具栏,但核心功能所需的就只有上面这些。

    给编辑器添加功能

    现在,是时候来实现我们的编辑器的功能了。所需的代码惊人的少:

    $('.toolbar a').click(function(e) {
         
      var command = $(this).data('command');
       
      if (command == 'h1' || command == 'h2' || command == 'p') {
        document.execCommand('formatBlock', false, command);
      }
       
      if (command == 'forecolor' || command == 'backcolor') {
        document.execCommand($(this).data('command'), false, $(this).data('value'));
      }
       
      if (command == 'createlink' || command == 'insertimage') {
        url = prompt('Enter the link here: ','http://');
        document.execCommand($(this).data('command'), false, url);
      }
       
      else document.execCommand($(this).data('command'), false, null);
       
    });

    我们侦听了工具栏上所有按钮的点击事件,当按钮被点击时,将其 data-commond 属性的值保存到变量 commond 中,用于后面执行 execCommand 方法的相应命令,避免重复获取,也使代码更加简洁。

    设置字体颜色(foreColor)和背景颜色(backColor)时,使用了 data-value 属性的值作为第三个参数。

    对于创建链接(createLink)和插入图片(insertImage)命令所需的 url 参数,使用了一个提示弹框(prompt)来获取用户输入的值。当然你也可以添加一些额外的逻辑来检测 url 的有效性。

    如果 command 变量不满足上面所有的 if 条件,则执行默认的 execCommand 命令。

    这个就是我们实现出来的 WYSIWYG 编辑器

    你也可以使用我 上个教程 介绍的 localStorage 来实现自动保存功能。

    跨浏览器差异

    对于 execCommand,不同的浏览器会有不同的实现。例如 formatBlock,IE 只支持标题标签(h1-h6)、addresspre,甚至在指定 commandName 时还需要包含标签符,如 <h3>

    也不是所有的浏览器都支持所有的命令,IE 就不支持 insertHTMLhiliteColorinsertBrOnReturn 只有 Firefox 支持。

    更多浏览器差异,可以参考 这个 GitHub 页面

    最后的感想

    创建自己的 WYSIWYG 编辑器是一个非常好的学习过程,在本篇教程中,讨论了许多 execCommand 命令,使用了一些 CSS 来处理基础外观。作为练习,建议大家通过文本选择器(text selection)实现一个工具栏按钮,用于设置字体(font),实现方法和字体颜色(foreColor)按钮类似。

    希望大家喜欢这篇教程,并能从中学到一些新的东西。

  • 相关阅读:
    在IIS中浏览网站时出现:无法打开登录所请求的数据库 "***",登录失败
    Java中的深拷贝和浅拷贝(转载)
    Java的Final和C#的Const,Readonly比较分析(转载)
    C#中的Sealed和J#中的Final比较(转载)
    Java全系列帮助文档下载
    The Willpower Instinct(自控力,意志力)
    瓦片地图的前世今生(转载)
    创建CUDA项目
    CUDA warning C4819的消除
    并行调用
  • 原文地址:https://www.cnblogs.com/kainanhong/p/6606748.html
Copyright © 2020-2023  润新知