• 【原创】【2】rich editor系列教程。了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏


    【原创】【2】rich editor系列教程。了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏

    索引目录:http://www.cnblogs.com/henryli/p/3439642.html

      浏览器提供了document.execommand的一系列命令来实现文本、格式、插入等操作,当然,浏览器厂商支持不一致、或者跟预想结果不一样。导致了前端coder需要耗费更大的精力去实现一个兼容、统一的富文本编辑。

      使用较多的浏览器api:

    • execCommand  ,设置格式样式等命令
    • queryCommandState,查询命令返回结果。ps(根据这个,可以实现当前选区格式的实时反馈)
    • queryCommandEnabled,返回布尔值,查询execCommand 命令是否可用,也就是是否可以成功执行当前命令
    • queryCommandSupported 返回表明当前命令是否在当前区域上支持的 Boolean 值。

      execCommand 命令总共有这些:

    1 var CommandList = ["2D-Position", "absolutePosition", "backColor", "blockDirLTR", "blockDirRTL", "bold", "browseMode", "clearAuthenticationCache", "contentReadOnly", "copy", "createBookmark", "createLink", "cut", "decreaseFontSize", "delete", "dirLTR", "dirRTL", "editMode", "fontName", "fontSize", "foreColor", "formatBlock", "enableInlineTableEditing", "enableObjectResizing", "forwardDelete", "heading", "increaseFontSize", "indent", "inlineDirLTR", "inlineDirRTL", "insertButton", "insertFieldset", "insertIFrame", "insertInputButton", "insertInputCheckbox", "insertInputFileUpload", "insertInputHidden", "insertInputImage", "insertInputPassword", "insertInputRadio", "insertInputReset", "insertInputSubmit", "insertInputText", "insertMarquee", "insertBrOnReturn", "insertHorizontalRule", "insertImage", "insertHTML", "insertLineBreak", "insertOrderedList", "insertUnorderedList", "insertParagraph", "insertSelectDropdown", "insertSelectListbox", "insertTextArea", "insertText", "italic", "justifyCenter", "justifyLeft", "justifyRight", "justifyFull", "justifyNone", "liveResize", "multipleSelection", "open", "overWrite", "outdent", "paste", "playImage", "print", "redo", "removeFormat", "refresh", "removeParaFormat", "selectAll", "saveAs", "sizeToControl", "sizeToControlHeight", "sizeToControlWidth", "stop", "stopImage", "strikeThrough", "subscript", "superscript", "unBookmark", "underline", "undo", "unlink", "useCSS", "hiliteColor", "unselect", "styleWithCSS"]
    View Code

      其中有上一篇用到的insertBrOnReturn和insertHTML。有了命令列表我们可以做一个测试页,测试命令是否受浏览器支持。当然其中还是一部分是暂时还没有任何浏览器支持的,rich editor也只用到其中的一部分命令。

      命令styleWithCSS,设置为true,如果浏览器支持,则改变格式使用表情的行内元素设置,反之使用b、i、u、font等标签设置,对于富文本来说,自然是使用标签来设置,行内样式权重过大,也不“语义”。

      设置文本、段落格式、样式需要用到:bold、italic、underline、strikethrough、superscript、subscript、removeformat、forecolor、backcolor、fontfamily、fontsize、justifyleft、justifycenter、justifyright、indent、outdent

      链接相关:createlink、unlink

      插入设置内容:insertorderedlist、insertunorderedlist、insertImage、insertHTML、insertText

      常用操作: selectAll、redo、undo、paste、print、copy

      其中有些命令与我们预期的不一样:

    1. fontsize,预期可以设置px、em文本大小,但浏览器却统一口径,只给了<font size="[0-7]"></font>,font未来要被废弃,而且无法设置自定义大小,需求兼容修正
    2. undo、redo,如果是使用iframe作为编辑器,iframe的document的undo、redo是“完整的”,如果是div,那么将与页面的操作重叠,需要定制一套undo、redo功能
    3. 待续

      

      当鼠标选择了编辑器以外的内容,这时候选择已经丢失了,使用插入图片、文本格式,如何保证操作的是编辑器的最后选择的选区呢?

      ie总是考虑的更加完善,给开发者提供了很好的api。提供了bookmark的功能;同时,ie提供了onbeforedeactivate和onactivate,来监听blur之前、focus之前的操作,在这个时间段,来获取书签和设置选区的书签最好不过了

      支持标准selection、range的浏览器就稍微麻烦了,需要我们把光标更改的时候,保存range到变量中,在需要的时候,设置回来。chrome跟ie 本身就支持document.onselectionchange,首选由ie支持的,绑定此方法,就可以监听选区改变了,

      

        //ie绑定获取书签,设置书签方法
        if ('onbeforedeactivate' in ifrWinOrEditor && document.selection) {
            var ieRangeBookMark;
            ifrWinOrEditor.attachEvent('onbeforedeactivate', function() {
                doc.selection.getBookmark();
            });
            ifrWinOrEditor.attachEvent('onactivate', function() {
                doc.selection.moveToBookmark(ieRangeBookMark);
            });
        } else {
            //反之当选区更改的时候保存range
            self._console('bind selectionchange');
            if ('onselectionchange' in doc) {
                Utils.bind(doc, 'selectionchange', function() {
                    self.saveRange();
                });
            } else {
                Utils.bind(doc, 'mouseup', function() {
                    self.saveRange();
                });
                Utils.bind(doc, 'keyup', function(e) {
                    self.saveRange();
                });
            }
        }
     1 saveLastRange: function() {
     2     this.getRange() && (this.lastRange = this.getRange().range);
     3 },
     4 setLastRange: function() {
     5     if (this.lastRange && this.getRange()) {
     6         var selection = this.getRange().selection;
     7         if (selection.removeAllRanges) {
     8             selection.removeAllRanges();
     9             selection.addRange(this.lastRange);
    10         }
    11     }
    12 }

      最终还需要判断当前的selection是否在编辑器中,因为当div作为编辑器,此时的选区可能在页面其他地方。ie支持Element.contains来判断是否包含某元素,而w3c使用compareDocumentPosition来判断,判断的代码直接放在getRange中,这样非编辑器中的选区,返回的是null。代码如下:

    //如果是div编辑器,要判断range是否在编辑器中
    if (this.editor != node) {
         var isChild;
         if (this.editor.contains) {
            isChild = this.editor.contains(node);
         } else {
            isChild = this.editor.compareDocumentPosition(node) == 20;
         }
         if (!isChild) {
            range = text = selection = null;
         }
    }

     demo已完成;点击下载

    预览图:

    update @ 2013-11-25 15:37:11

    BY henry

    mail : liyaohui.henry@gmail.com

  • 相关阅读:
    Swift3.0 函数闭包与 Block
    深入理解RunLoop
    Autorelease对象什么时候释放?
    Mysql数据库分库分表Springboot+mybatis+druid+shardingsphere
    Mysql数据库读写分离Springboot+mybatis+druid+shardingsphere
    docker-compose安装mysql主从集群
    监听ZK节点数据变化的几种方式
    c语言替换avx指令集,Dlib支持CPU指令集编译问题(SSE4.2或者AVX)
    centos7防火墙
    centOS7安装nginx及nginx配置
  • 原文地址:https://www.cnblogs.com/henryli/p/3441312.html
Copyright © 2020-2023  润新知