【1】前期准备,兼容

  

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

  

  rich editor的原理无非是启用iframe的编辑模式或者div的contenteditable=true。然后使用document.execcommand来编辑选取文本。但会使用到selection操作和range。

查看api: msdn地址mozilla富文本编辑指引w3school range

  使用iframe作为编辑器的优势:独立的编辑document、不会与页面其他选择冲突,独立的redo undo操作。缺点,如果页面设置了document.domain,而编辑模式中的js无法执行,会造成权限错误,有加载失败的可能。

  使用div作为编辑器,轻量、加载不会失败、效率提升。但不适用于重量级、多功能文本处理,同时selection、range、undo的与页面元素共有。

  ie使用了跟w3c不一样的api,返回的结果类似,不兼容。

  创建range对象:

      

 var selection = ifrDoc.createRange ? ifrDoc.createRange() : ifrWin.getSelection();
var range = selection.createRange ? selection.createRange() : selection.getRangeAt(0)

  

  编辑器的基本原理不做叙述,这方面的博文很多,google一下即可

  

  同样,不同的浏览器对于回车按键的处理也不一致,ie浏览器会产生一个成对儿的<p></p>标签,chrome为<div></div>,firefox根据版本为p或者br。

  如何解决这个问题?将所有的换行设置为段落,或者设置为br

    firefox,使用命令insertBrOnReturn命令,最后参数为true,会产生br,为false则产生p标签

document.execCommand("insertBrOnReturn",false,'true');

    ie,默认的,产生成对的段落p标签(chrome为div标签,but,如果chrome中编辑器默认的元素为<p></p>,那么我大chrome则智能的把换行段落tag设置成了<p>) , 搜噶。。。统一为段落的p标签,就是这么easy。(firefix设置:document.execCommand("insertBrOnReturn",false,'false');ie是默认,chrome设置初始p tag)

    ps: 编辑器默认必须有html,ie可以为空,其他浏览器至少要有br元素,否则会出现focus无光标的问题。同样,如果用户设置了初始html,同时换行为段落P的tag,那么此时就需要给html内容套上一个p容器。同样,保证p标签内部不允许有p元素,如果有,则要产生新的段落,这部分,可以封装在一个 empty() 的方法。

 //当换行为br
editor.innerHTML = Util.msie ? '' : '<br />';
//当换行为段落
editor.innerHTML = '<p>' + (Util.msie ? '' : '<br />') + '</p>';

  

多数情况,设置为p标签,是最符合文章的编辑,毕竟,enter换行产生新的段落是那么的“语义”,哈哈。   但总有需要,换行需要设置为br。那么问题来了。firefox可以使用编辑器命令设置为br,其他浏览器,需要绑定事件,在按下回车的时候,删除当前选区的内容,插入一个<br/>&nbsp;的代码,同时设置光标选中空格,删除它,因为插入空格再文档末尾不可用。

代码:

if (e.keyCode == 13 && self._bindEnter == true) {
e.preventDefault ? e.preventDefault() : e.returnValue = false;
//如果insertHTML命令失败,手动添加br
var range = self.getRange().range;
self.insertHTML(range.pasteHTML ? '<br/>' : '<br/>&nbsp;');//不添加空格,在末尾无法有时候无法执行br
if (!range.pasteHTML) {
//chrome\ie9\ie19
var rangeData = self.getRange();
var range = rangeData.range;
range.setStart(range.startContainer, range.startOffset - 1);
var _selection = self.getRange().selection;
_selection.removeAllRanges();
_selection.addRange(range);
document.execCommand("Delete", false, null); }
}

  

  为了方便,会添加个insertHTML的方法,插入br、tab占位等,低版本的ie浏览器,直接使用range.pasteHTML即可,反之使用execCommand的insertHTML,如果命令失败,调用range.createContextualFragment,创建文档片段,range.insertNode,插入字符串html,最终再设置位置、添加到selection中,

发现bug,ie9移除了低版本的pasteHTML,但又未支持w3c的createContextualFragment方法,只好使用createDocumentFragment方法来创建文档碎片。

代码:

 execCommand: function(type, value) {
var result;
try {
//当ie调用无法执行的命令会报错
result = this.ifrDoc.execCommand(type, false, value);
} catch (e) {
}
this._console('execCommand', type, value, 'result:' + (result ? 'ok' : 'false'));
return result;
},
insertHTML: function(html, fn) {
var self = this;
if (!self.execCommand("insertHTML", html)) {
//ie不支持insertHTML
var rangeData = self.getRange();
var range = rangeData.range;
if (document.selection && range.pasteHTML) {
range.pasteHTML(html);//早期ie的方法
range.collapse(false);
} else {
range.deleteContents();//删除选择的内容.
//#bug ie9去除了pasteHTML,却没有createContextualFragment方法,ie10已添加
var rangeNode;
if (range.createContextualFragment) {
rangeNode = range.createContextualFragment(html)
} else {
rangeNode = document.createDocumentFragment();
var div = document.createElement("div");
rangeNode.appendChild(div);
div.outerHTML = html;
div = null;
}
range.insertNode(rangeNode);
range.collapse(false);
} }
}

最后奉上demo,虽然是rich editor教程,但第一篇是不包含任何针对文字的格式设置的编辑器,我们是在做准备工作,哼哼。阅读api是少不了滴. 同样添加了n多工具方法。

点我下载demo

update @2013-11-27 12:55:14

BY henry

mail : liyaohui.henry@gmail.com

  

【原创】【1】rich editor系列教程。前期准备,兼容的更多相关文章

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

    [原创][2]rich editor系列教程.了解document.execommand操作,保存丢失的range,实时反馈样式给工具栏 索引目录:http://www.cnblogs.com/hen ...

  2. [原创]K8_Delphi源码免杀系列教程

    [原创]K8_Delphi源码免杀系列教程[2014] 虽是2014年的,但免杀思路方法并未过时 比如函数动态调用\代码注释法等至今依然有效 链接:https://pan.baidu.com/s/1H ...

  3. Android Studio系列教程四--Gradle基础

    Android Studio系列教程四--Gradle基础 2014 年 12 月 18 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzhang ...

  4. Android Studio系列教程三--快捷键

    Android Studio系列教程三--快捷键 2014 年 12 月 09 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://stormzhang.com/ ...

  5. Spring Boot 2.x 系列教程:WebFlux 系列教程大纲(一)

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! WebFlux 系列教程大纲 一.背景 大家都知道,Sprin ...

  6. CRL快速开发框架系列教程十三(嵌套查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  7. C#微信公众号开发系列教程三(消息体签名及加解密)

    http://www.cnblogs.com/zskbll/p/4139039.html C#微信公众号开发系列教程一(调试环境部署) C#微信公众号开发系列教程一(调试环境部署续:vs远程调试) C ...

  8. C#微信公众号开发系列教程二(新手接入指南)

    http://www.cnblogs.com/zskbll/p/4093954.html 此系列前面已经更新了两篇博文了,都是微信开发的前期准备工作,现在切入正题,本篇讲解新手接入的步骤与方法,大神可 ...

  9. C#微信公众号开发系列教程四(接收普通消息)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

随机推荐

  1. MySQL数据库--连接

    MySQL数据库的概念: MySQL数据库,包括客户端和服务端.客户端就是操作数据库的终端(命令行.navicat),服务端就是安装有MySQL软件的主机(本机或者服务器),MySQL数据库的端口一般 ...

  2. Scrapy爬豆瓣电影Top250并存入MySQL数据库

    d:进入D盘 scrapy startproject douban创建豆瓣项目 cd douban进入项目 scrapy genspider douban_spider movie.douban.co ...

  3. 借助全新 MATLAB® 适配器代码示例读取英特尔® 实感™ 摄像头数据流

    下载源代码请访问原文地址:借助全新 MATLAB® 适配器代码示例读取英特尔® 实感™ 摄像头数据流 简介 该可下载代码示例简要介绍了如何使用英特尔® 实感™ SDK 和 MATLAB 的图像采集工具 ...

  4. MAC清理DS_Store和._文件

    打开终端输入 find . -name .DS_Store -type f -delete ; find . -type d | xargs dot_clean

  5. HP Vitrual Connect 配置快速参考

    使用任意浏览器,在地址栏输入VC的管理地址(如果不知道VC的管理地址请从OA中进入) 输入用户名和密码登入VC,验证成功后将进入VM的配置向导 点击"Next"继续,将先进行Dom ...

  6. Openstack 10 云环境安装

    概述 资源规划 Undercloud Installation Overcloud Installation Trouble Shooting 附录 本指南介绍了如何使用 Red Hat OpenSt ...

  7. AirSim的搭建和使用

    由于自己使用设备拍摄的数据质量太差,所以决定使用AirSim这个框架来生成数据.之所以使用这个框架,是因为之前同事用其生成了一些有效数据. 当然,我是不可能把我搭建的步骤一一写出来的,一来是因为太麻烦 ...

  8. [T-ARA][HUE]

    歌词来源:http://music.163.com/#/song?id=22704406 wa du seu mo geum to yo do ga tae 어딜가도 스페셜한게 없어 [eo-dil ...

  9. <力荐>非常好的正则表达式的详解<力荐>

    正则表达式(regular expression)描述了一种字符串匹配的模式,可以用来检查一个串是否含有某种子串.将匹配的子串做替换或者从某个串中取出符合某个条件的子串等. 列目录时, dir *.t ...

  10. Minimum Sum of Array(map迭代器)

    You are given an array a consisting of n integers a1, ..., an. In one operation, you can choose 2 el ...