【原创】【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"]
其中有上一篇用到的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
其中有些命令与我们预期的不一样:
- fontsize,预期可以设置px、em文本大小,但浏览器却统一口径,只给了<font size="[0-7]"></font>,font未来要被废弃,而且无法设置自定义大小,需求兼容修正
- undo、redo,如果是使用iframe作为编辑器,iframe的document的undo、redo是“完整的”,如果是div,那么将与页面的操作重叠,需要定制一套undo、redo功能
- 待续
当鼠标选择了编辑器以外的内容,这时候选择已经丢失了,使用插入图片、文本格式,如何保证操作的是编辑器的最后选择的选区呢?
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