如何做一个富文本编辑器
很久以前就想做一个富文本编辑器,但是感觉比较难,一直没有实现。直到了解了html5的contenteditable属性可以设置一个div为可编辑状态,利用这个特性做富文本编辑器就比较简单了
首先 认识一下 contenteditable 它是一个属性 可以这样使一个DIV的编辑状态被激活
<div contenteditable="true"></div>
然后这个div就可以被编辑了 而我们要想获得它的html源码可以使用innerHTML来取得
举个例子如下:
如果我们想在页面上修改CSS属性值而让它所控制的元素实时变化,就可以这样做:
先在head里的style设置body里面的style元素是显示的 这样我们才可以编辑 style元素放在body区域默认是不显示的
<style> body style{ display:block; padding:0.6em 0.8em; border:1px dashed #ccc; background-color:#f5f5f5; color:#000; font-family:Monaco, monospace; font-size:12px; white-space:pre-wrap; word-wrap:break-word; } </style>
这样我们body里的style元素就显示出来了
然后我们在body里面定义style 可能像下面这样 设置它为可编辑的
<body> <style contenteditable="true"> .main{ background: #444; font-size: 2em; border: 1px solid #0f0; border-radius: 3px; color: #46b8da; } </style>
在页面上跑一下 是不是发现 所有使用main class的元素都会随着你的CSS值改变而实时改变
言归正传 继续看富文本编辑器如何实现
想象一下我们在富文本编辑器中如何改变文本的style 首先第一步就是如何取得当前选中的内容
如何获得选择文字 首先应该了解一下Range对象
所谓"Range"
,是指HTML文档中任意一段内容。一个Range
的起始点和结束点位置任意,甚至起始点和结束点可以是一样的(也就是空Range
)。最常见的Range
是用户文本选择范围(user text selection)。当用户选择了页面上的某一段文字后,你就可以把这个选择转为Range
。当然,你也可以直接用程序定义Range
。
而且Range也有三种版本 W3C Mozilla Microsoft
W3C Range对象
是唯一官方指定。基本上其是将Range
作为包含DOM的文档片段。Mozilla Selection对象
显得有些多余,其存在是为了向后兼容Netscape 4。其类似于W3C Range对象
,也是基于DOM树的。Microsoft Text Range
因为其是基于字符串的。事实上,Text Range
包含的字符串是很难一下子跳变成DOM节点的。
具体也就不解释了 直接看代码吧 如何获得选中文字
var userSelection; if (window.getSelection) { //现代浏览器 userSelection = window.getSelection(); } else if (document.selection) { //IE浏览器 userSelection = document.selection.createRange(); }
随便console.log(userSelection)一下 就会发现选中的内容真的被打印出来了
接下就是如何设置选中文本的样式了,这里要掌握的是 document.execCommand()方法处理Html数据
document.execCommand()方法处理Html数据时常用语法格式如下: 复制内容到剪贴板 代码: document.execCommand(sCommand[,交互方式, 动态参数]) 其中:sCommand为指令参数(如下例中的”2D-Position”),交互方式参数如果是true的话将显示对话框,如果为false的话,则不显示对话框(下例中的”false”即表示不显示对话框),动态参数一般为一可用值或属性值(如下例中的”true”)。 document.execCommand(”2D-Position”,”false”,”true”); 调用execCommand()可以实现浏览器菜单的很多功能. 如保存文件,打开新文件,撤消、重做操作…等等. 有了这个方法,就可以很容易的实现网页中的文本编辑器. 如果灵活运用,可以很好的辅助我们完成各种项目. 下面列出的是指令参数及意义 //相当于单击文件中的打开按钮 document.execCommand(”Open”); //将当前页面另存为 document.execCommand(”SaveAs”); //剪贴选中的文字到剪贴板; document.execCommand(”Cut”,”false”,null); //删除选中的文字; document.execCommand(”Delete”,”false”,null); //改变选中区域的字体; document.execCommand(”FontName”,”false”,sFontName); //改变选中区域的字体大小; document.execCommand(”FontSize”,”false”,sSize|iSize); //设置前景颜色; document.execCommand(”ForeColor”,”false”,sColor); //使绝对定位的对象可直接拖动; document.execCommand(”2D-Position”,”false”,”true”); //使对象定位变成绝对定位; document.execCommand(”AbsolutePosition”,”false”,”true”); //设置背景颜色; document.execCommand(”BackColor”,”false”,sColor); //使选中区域的文字加粗; document.execCommand(”Bold”,”false”,null); //复制选中的文字到剪贴板; document.execCommand(”Copy”,”false”,null); //设置指定锚点为书签; document.execCommand(”CreateBookmark”,”false”,sAnchorName); //将选中文本变成超连接,若第二个参数为true,会出现参数设置对话框; document.execCommand(”CreateLink”,”false”,sLinkURL); //设置当前块的标签名; document.execCommand(”FormatBlock”,”false”,sTagName); //相当于单击文件中的打开按钮 document.execCommand(”Open”); //将当前页面另存为 document.execCommand(”SaveAs”); //剪贴选中的文字到剪贴板; document.execCommand(”Cut”,”false”,null); //删除选中的文字; document.execCommand(”Delete”,”false”,null); //改变选中区域的字体; document.execCommand(”FontName”,”false”,sFontName); //改变选中区域的字体大小; document.execCommand(”FontSize”,”false”,sSize|iSize); //设置前景颜色; document.execCommand(”ForeColor”,”false”,sColor); //使绝对定位的对象可直接拖动; document.execCommand(”2D-Position”,”false”,”true”); //使对象定位变成绝对定位; document.execCommand(”AbsolutePosition”,”false”,”true”); //设置背景颜色; document.execCommand(”BackColor”,”false”,sColor); //使选中区域的文字加粗; document.execCommand(”Bold”,”false”,null); //复制选中的文字到剪贴板; document.execCommand(”Copy”,”false”,null); //设置指定锚点为书签; document.execCommand(”CreateBookmark”,”false”,sAnchorName); //将选中文本变成超连接,若第二个参数为true,会出现参数设置对话框; document.execCommand(”CreateLink”,”false”,sLinkURL); //设置当前块的标签名; document.execCommand(”FormatBlock”,”false”,sTagName);
这么一大堆的命令都可以使用 只需要调用它就可以动态修改文本的style了
理论到这里就讲完了 接下来就是做了 我把写好的直接贴出来供参考吧 虽然写得不好 但是比较好懂
如果你感觉我这样写不好 也可以看
bootstrap-wysiwyg
代码如下 为了方便全部在一个文件 你不能这么做
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="description" content="Rich Editor"> <meta name="keywords" content="HTML5, CSS3,JavaScript,Bootstrap,jQuery,Web"> <meta name="author" content="BaiQiang"> <title> 富文本编辑器 </title> <!--为了方便开发我引入了bootstrap和jQuery 但它们和本项目没有任何必须依赖关系。 你可以自己布局 也可以使用原生JavaScript操作--> <!-- 最新 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="http://cdn.bootcss.com/twitter-bootstrap/3.0.3/css/bootstrap.min.css"> <!-- jQuery文件。务必在bootstrap.min.js 之前引入 --> <script src="http://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script> <!-- 最新的 Bootstrap 核心 JavaScript 文件 --> <script src="http://cdn.bootcss.com/twitter-bootstrap/3.0.3/js/bootstrap.min.js"></script> <style contenteditable> #editor { max-height: 450px; height: 350px; background-color: white; border-collapse: separate; border: 1px solid rgb(204, 204, 204); padding: 4px; box-sizing: content-box; -webkit-box-shadow: rgba(0, 0, 0, 0.0745098) 0px 1px 1px 0px inset; box-shadow: rgba(0, 0, 0, 0.0745098) 0px 1px 1px 0px inset; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; border-top-left-radius: 3px; overflow: scroll; outline: none; } .btn { font-family: "微软雅黑"; } </style> </head> <body> <!--我需要一个工具栏--> <div class="btn-group"> <button type="button" class="btn btn-deault">字体</button> <button type="button" class="btn btn-deault dropdown-toggle" data-toggle="dropdown"> <span class="caret"></span> <span class="sr-only">Toggle Dropdown</span> </button> <ul class="dropdown-menu family" role="menu"> <li><a href="#" data-edit="微软雅黑" style="font-family: '微软雅黑'">微软雅黑</a></li> <li><a href="#" data-edit="Serif" style="font-family: 'Serif'">Serif</a></li> <li><a href="#" data-edit="Courier New" style="font-family:'Courier New'">Courier New</a></li> <li><a href="#" data-edit="Lucida Sans" style="font-family: 'Lucida Sans'">Lucida Sans</a></li> <li><a href="#" data-edit="Times" style="font-family: Times">Times</a></li> </ul> </div> <div class="btn-group"> <button type="button" class="btn btn-deault">大小</button> <button type="button" class="btn btn-deault dropdown-toggle" data-toggle="dropdown"> <span class="caret"></span> <span class="sr-only">Toggle Dropdown</span> </button> <ul class="dropdown-menu size" role="menu"> <li><a href="#" data-edit="7">H1</a></li> <li><a href="#" data-edit="5">H2</a></li> <li><a href="#" data-edit="4">H3</a></li> <li><a href="#" data-edit="3">H4</a></li> <li><a href="#" data-edit="2">H5</a></li> <li><a href="#" data-edit="1">H6</a></li> </ul> </div> <div class="btn-group style"> <a href="#" class="btn btn-default" data-edit="bold">B</a> <a href="#" class="btn btn-default" data-edit="italic">I</a> <a href="#" class="btn btn-default" data-edit="strikethrough">S</a> <a href="#" class="btn btn-default" data-edit="underline">U</a> </div> <div class="btn-group list"> <a href="#" class="btn btn-default" data-edit="InsertUnorderedList">UL</a> <a href="#" class="btn btn-default" data-edit="InsertOrderedList">OL</a> <a href="#" class="btn btn-default" data-edit="indent">TAB</a> </div> <div class="btn-group position"> <a href="#" class="btn btn-default" data-edit="JustifyLeft">Left</a> <a href="#" class="btn btn-default" data-edit="JustifyCenter">Middle</a> <a href="#" class="btn btn-default" data-edit="JustifyRight">Right</a> </div> <div class="btn-group tool"> <a href="#" class="btn btn-default" data-edit="SaveAs">Save</a> <a href="#" class="btn btn-default" data-edit="Copy">Copy</a> <a href="#" class="btn btn-default" data-edit="Delete">Delete</a> </div> <div class="btn-group"> <button class="btn btn-default" id="clear">清理</button> </div> <div contenteditable="true" id="editor"> </div> <script> var userSelection; if (window.getSelection) { //现代浏览器 userSelection = window.getSelection(); } else if (document.selection) { //IE浏览器 userSelection = document.selection.createRange(); } function editStyle(cmd, bool, value) { document.execCommand(cmd, bool, value); } $(function () { //editor use it's to clear html $.fn.cleanHtml = function () { var html = $(this).html(); return html && html.replace(/(<br>|\s|<div><br><\/div>| )*$/, ''); }; $(".size>li>a").click(function (e) { editStyle("FontSize", false, $(e.target).attr("data-edit")); e.preventDefault(); }); $(".family>li>a").click(function (e) { editStyle("FontName", false, $(e.target).attr("data-edit")); e.preventDefault(); }); $(".style>a").click(function (e) { editStyle($(e.target).attr("data-edit"), false); e.preventDefault(); }); $(".list>a").click(function (e) { editStyle($(e.target).attr("data-edit"), false); e.preventDefault(); }); $(".position>a").click(function (e) { editStyle($(e.target).attr("data-edit"), false); e.preventDefault(); }); $(".tool>a").click(function (e) { /*对于拷贝到剪切板和另存为网页只有IE支持*/ editStyle($(e.target).attr("data-edit"), false); e.preventDefault(); }); $("#clear").click(function () { var html = $("#editor").cleanHtml(); console.log(html); }); }); </script> </body> </html>
最终效果图: