参考文章:
http://www.cnblogs.com/lhb25/p/html5-wysisyg-inline-editor.html
http://guoliangheyuqin.iteye.com/blog/1676688
编写了一个简单的文本编辑器,使用document.execCommand命令对可编辑区域进行字体的加粗 斜体 对齐以及插入图片和超链接等操作。document.execCommand的用法可参考这篇文章。
相关代码如下:
textEditor.js
(function(){
var $options = null;
var $containerObj = null;
$.fn.textEditor = function(){
var options;
if(arguments != undefined ){
if(arguments.length == 1 && typeof(arguments[0]) == 'object'){//选项参数 options = arguments[0]; }else if(arguments.length>0 && typeof(arguments[0]) == 'string'){//调用方法 dispatchMethod(arguments); }
}
$containerObj = $(this);
var $defaults = {
"undo":true,//默认显示
"redo":true,//默认显示
"repeat":true,
"bold":true,
"italic":true,
"underline":true,
"strikeThrough":true,//加删除线
"justifyLeft":true,
"justifyCenter":true,
"justifyRight":true,
"justifyFull":true,
"indent":true,//缩进
"outdent":true,//不缩进
"insertUnorderedList":true,
"insertOrderedList":true,
"h1":true,
"h2":true,
"p":true,
"subscript":true, //下标?
"superscript":true, //上标?
"removeFormat":true
,"fontSize":true
,"fontColor":true //字体颜色
,"hyperlink":true //超链接
,"picture":true // 图片
,"getHtmlText":true //获取html
};
$options = $.extend($defaults,options);
if(!$containerObj.hasClass('customed-textEditor-cls')){
$containerObj.addClass('customed-textEditor-cls');
}
var htmlStr = '<div class="content">'
+ '<div class="container-fluid">'
+ '<div id="pad-wrapper">'
+ '<div id="editparent">'
+ '<div class="span9 editControlsCls" style="padding:5px;">';
//根据选项设置 添加格式按钮
//撤销 重做
htmlStr += '<div class="btn-group">';
if($options.undo){
htmlStr += "<a class='btn' title='撤销' data-role='undo' href='javascript:void(0);'>"
+ "<i class='icon-undo'></i>"
+ "</a>";
}
if($options.redo){
htmlStr += "<a class='btn' title='重做' data-role='redo' href='javascript:void(0);'><i class='icon-repeat'></i></a>";
}
htmlStr += '</div>';
//20170327 add
//字体大小 字体颜色
htmlStr += '<div class="btn-group">';
if($options.fontSize){
htmlStr += "<a id='fontSizeLink' class='btn' title='选择字体' data-role='fontSize' href='javascript:void(0);'><i class='icon-font'></i>"
+ "</a>";
}
if($options.fontColor){//选择字体颜色
htmlStr += "<a id='fontColorLink' class='btn' title='选择字体颜色' data-role='foreColor' href='javascript:void(0);'><i class='icon-table'></i>"
+ "</a>";
}
htmlStr += '</div>';
//粗体 斜体 下划线 删除线
htmlStr += '<div class="btn-group">';
if($options.bold){
htmlStr += "<a class='btn' title='加粗' data-role='bold' href='javascript:void(0);'><b>Bold</b></a>";
}
if($options.italic){
htmlStr += "<a class='btn' title='斜体' data-role='italic' href='javascript:void(0);'><em>Italic</em></a>";
}
if($options.underline){
htmlStr += "<a class='btn' title='下划线' data-role='underline' href='javascript:void(0);'><u><b>U</b></u></a>";
}
if($options.strikeThrough){
htmlStr += "<a class='btn' title='删除线' data-role='strikeThrough' href='javascript:void(0);'><strike>abc</strike></a>";
}
htmlStr += '</div>';
//左端对齐 中间对齐 右端对齐 两端对齐
htmlStr += '<div class="btn-group">';
if($options.justifyLeft){
htmlStr += "<a class='btn' title='左对齐' data-role='justifyLeft' href='javascript:void(0);'><i class='icon-align-left'></i></a>";
}
if($options.justifyCenter){
htmlStr += "<a class='btn' title='居中' data-role='justifyCenter' href='javascript:void(0);'><i class='icon-align-center'></i></a>";
}
if($options.justifyRight){
htmlStr += "<a class='btn' title='右对齐' data-role='justifyRight' href='javascript:void(0);'><i class='icon-align-right'></i></a>";
}
if($options.justifyFull){
htmlStr += "<a class='btn' title='两端对齐' data-role='justifyFull' href='javascript:void(0);'><i class='icon-align-justify'></i></a>";
}
htmlStr += '</div>';
//缩进 不缩进
htmlStr += '<div class="btn-group">';
if($options.indent){
htmlStr += "<a class='btn' title='向右缩进' data-role='indent' href='javascript:void(0);'><i class='icon-indent-right'></i></a>";
}
if($options.outdent){
htmlStr += "<a class='btn' title='向左缩进' data-role='outdent' href='javascript:void(0);'><i class='icon-indent-left'></i></a>";
}
htmlStr += '</div>';
//插入有序列表 无序列表
htmlStr += '<div class="btn-group">';
if($options.insertUnorderedList){
htmlStr += "<a class='btn' title='无序列表' data-role='insertUnorderedList' href='javascript:void(0);'><i class='icon-list-ul'></i></a>";
}
if($options.insertOrderedList){
htmlStr += "<a class='btn' title='有序列表' data-role='insertOrderedList' href='javascript:void(0);'><i class='icon-list-ol'></i></a>";
}
htmlStr += '</div>';
//插入 h1 h2 p
htmlStr += '<div class="btn-group">';
if($options.h1){
htmlStr += "<a class='btn' title='一级标题' data-role='h1' href='javascript:void(0);'>h<sup>1</sup></a>";
}
if($options.h2){
htmlStr += "<a class='btn' title='二级标题' data-role='h2' href='javascript:void(0);'>h<sup>2</sup></a>";
}
if($options.p){
htmlStr += "<a class='btn' title='正文' data-role='p' href='javascript:void(0);'>p</a>";
}
htmlStr += '</div>';
//20170328 插入图片和超链接
htmlStr += '<div class="btn-group">';
if($options.subscript){
htmlStr += "<a class='btn' title='插入图片' data-role='insertImage' href='javascript:void(0);'><i class='icon-picture'></i></a>";
}
if($options.superscript){
htmlStr += "<a class='btn' title='插入超链接' data-role='createLink' href='javascript:void(0);'><i class='icon-link'></i></a>";
}
htmlStr += '</div>';
//插入上标 下标
htmlStr += '<div class="btn-group">';
if($options.subscript){
htmlStr += "<a class='btn' title='下标' data-role='subscript' href='javascript:void(0);'><i class='icon-subscript'></i></a>";
}
if($options.superscript){
htmlStr += "<a class='btn' title='上标' data-role='superscript' href='javascript:void(0);'><i class='icon-superscript'></i></a>";
}
htmlStr += '</div>';
//清除格式 removeFormat
htmlStr += '<div class="btn-group">';
if($options.removeFormat){
htmlStr += "<a class='btn' title='清除格式' data-role='removeFormat' href='javascript:void(0);'><i class='icon-check-empty'></i></a>";
}
//获取编辑器中html文本
if($options.getHtmlText){
htmlStr += "<a class='btn' title='获取HTML文本' data-role='getHtmlText' href='javascript:void(0);'><i class='icon-download-alt'></i></a>";
}
htmlStr += '</div>';
//编辑区域
htmlStr += "<div class='editor-content-cls' contenteditable>"
+ "<h1>世界上最简单的文本编辑器!</h1>"
+ "<p>梦想天空博客关注<b>前端开发</b>技术,分享各种增强网站用户体验的 <b>jQuery</b> 插件,展示前沿的 <b>HTML5</b> 和 <b>CSS3</b> 技术应用,推荐优秀的网页设计案例,共享精美的设计素材和优秀的 <b>Web</b> 开发工具,希望这些精心整理的前端技术文章能够帮助到您。</p>"
+ "</div>";
htmlStr += '</div></div></div></div></div>';
//字体弹出框
htmlStr += "<div class='fontSizeDlgCls' style='z-index:20000;display:none;'><ul><li><a href='javascript:void(0);' onclick='onclickFontSizeItem(this)'>1</a></li><li><a href='javascript:void(0);' onclick='onclickFontSizeItem(this)'>2</a></li>"
+ "<li><a href='javascript:void(0);' onclick='onclickFontSizeItem(this)'>3</a></li><li><a href='javascript:void(0);' onclick='onclickFontSizeItem(this)'>4</a></li>"
+ "<li><a href='javascript:void(0);' onclick='onclickFontSizeItem(this)'>5</a></li><li><a href='javascript:void(0);' onclick='onclickFontSizeItem(this)'>6</a></li>"
+"<li><a href='javascript:void(0);' onclick='onclickFontSizeItem(this)'>7</a></li></ul></div>";
//颜色表
htmlStr += '<div class="colorTableDIVCls" style="z-index:20000;"></div>';
/*
//图片地址输入框
htmlStr += '<div class="pictureInputDIVCls" style="z-index:20000;display:none;"><div class="tipCls">请输入图片地址:</div>'
+ '<input class="inputTextCls"/>'
+ '<div><button class="btn" onclick="submitPictureInput()" style="margin-left:100px;margin-right:30px;">确定</button><button class="btn" onclick="cancelPictureInput()">取消</button></div>'
+ '</div>';
//超链接输入框
htmlStr += '<div class="linkInputDIVCls" style="z-index:20000;position:fixed;top:0px;left:0px;width:100%;height:100%;display:none;"><div class="tipCls">请输入超链接地址:</div>'
+ '<input class="inputTextCls"/>'
+ '<button class="btn" onclick="submitLinkInput()" style="margin-left:100px;margin-right:30px;">确定</button><button class="btn" onclick="cancelLinkInput()">取消</button>'
+ '</div>';
*/
$containerObj.html(htmlStr);
//20170328 颜色表
var $colorTable = getColorTable('colorTableCls');
$(".colorTableDIVCls").append($colorTable);
$colorTable.onclick = setColor;//定义表格的点击事件
$colorTable.style.display = "none";
/*
//表格颜色的点击事件
$("table.colorTableCls td").click(function(){ //console.log("setColor evt: " ); //console.log(evt); var obj = this; if(obj.tagName == "TD" && obj.title){ console.log("obj.title: " + obj.title); console.log("obj.style.backgroundColor: " + obj.style.backgroundColor); var clickColor = obj.title; console.log(document); //this.style.display = "none"; document.designMode = "on"; document.contentEditable=true; window.focus(); alert(document.execCommand('foreColor',false, clickColor)); alert(document.execCommand('foreColor',false, "#f00")); } });
*/
//定义编辑框各个按钮的点击事件
$(".customed-textEditor-cls div.editControlsCls a ").click(function(e){ //console.log("$(this).data('role'): " + $(this).data('role')); //console.log("$(this).attr('data-role'): " + $(this).attr('data-role')); //console.log("$(this).prop('data-role'): " + $(this).prop('data-role'));//undefined switch($(this).data('role')){ //字号 case 'fontSize': var temp = getXY(document.getElementById("fontSizeLink")); var dlgLeft = temp.left + 2 +'px'; var dlgTop = temp.top + 30 + 'px'; $("div.fontSizeDlgCls").css('position', 'absolute'); $("div.fontSizeDlgCls").css('top', dlgTop); $("div.fontSizeDlgCls").css('left', dlgLeft); $("div.fontSizeDlgCls").css('display', ''); break; //字体颜色 case 'foreColor': var fontColorPosition = getXY(this); var colorTableLeft = fontColorPosition.left + 2 + 'px'; var colorTableTop = fontColorPosition.top + 30 + 'px'; $($colorTable).css('position', 'absolute'); $($colorTable).css('top', colorTableTop); $($colorTable).css('left', colorTableLeft); toggle($colorTable,"display","block","none"); break; case "insertImage": /*console.log($("a[data-role='insertImage']")[0]); var tempImage = getXY($("a[data-role='insertImage']")[0]); var dlgImageLeft = tempImage.left + 2 +'px'; var dlgImageTop = tempImage.top + 30 + 'px'; $("div.pictureInputDIVCls").css('position', 'absolute'); $("div.pictureInputDIVCls").css('top', dlgImageTop); $("div.pictureInputDIVCls").css('left', dlgImageLeft); var inputObjPicture = $(".pictureInputDIVCls")[0]; $("div.pictureInputDIVCls input").val(""); toggle(inputObjPicture,"display","block","none");*/ var imageUrl = prompt("请输入图片地址!","http://"); var result = document.execCommand('insertImage', false, imageUrl); if(!result){ alert("图片插入失败"); } break; case "createLink": /*var inputObjLink = $(".linkInputDIVCls")[0]; console.log(inputObjLink); toggle(inputObjLink,"display","block","none");*/ var linkUrl = prompt("请输入超链接地址!","http://"); var result = document.execCommand('createLink', false, linkUrl); if(!result){ alert("超链接插入失败"); } break; case 'getHtmlText'://获取HTML文本 var htmlText = dispatchMethod(['getHtmlText']); alert("htmlText: " + htmlText); break; case 'h1': case 'h2': case 'p': //formatblock 添加html标签块 /* * 添加一个HTML块式标签在包含当前选择的行, 如果已经存在了, * 更换包含该行的块元素 (在 Firefox中, BLOCKQUOTE 是一个例外 -它将包含任何包含块元素). * 需要提供一个标签名称字符串作为参数。几乎所有的块样式标签都可以使用(例如. "H1", "P", "DL", "BLOCKQUOTE"). * (IE浏览器仅仅支持标题标签 H1 - H6, ADDRESS, 和 PRE,使用时还必须包含标签分隔符 < >, 例如 "<H1>".) * */ document.execCommand('formatBlock',false, '<' + $(this).data('role') + '>'); break; default: //执行命令 document.execCommand($(this).data('role'),false,null); break; } });//click
/* $("div.fontSizeDlgCls ul li").click(function(e){ var childrenArr = $(this).children(); var linkObj = childrenArr[0]; var selectedFontSize = linkObj.innerText; alert("selectedFontSize: " + selectedFontSize); //执行设置字号命令 //执行命令 document.execCommand('fontSize', false, selectedFontSize); //$("div.fontSizeDlgCls").css('display', 'none'); });*/
//20170328 生成颜色表节点
function getColorTable(classname){
var table = document.createElement("table");
//创建标题
table.createCaption().appendChild(document.createTextNode("颜色表"));
table.cellspacing = 0;
table.cellpadding = 0;
table.className = classname;
var row = table.insertRow(0);
for(var i=0; i<12; i++){ for(var j=0;j<18;j++){ var cell = row.insertCell(row.cells.length); //之前将setColor定义为td的onclick相应函数 但是不起作用 之后将setColor设置为<a>的onclick事件 cell.innerHTML= '<a style="width:12px;height:20px;display:inline-block;"' +'href="javascript:void(0);" onclick="setColor(this);"> </a>'; var g = fixColor((j>6)?((j%6)*3):(j*3)); var b = fixColor((i>6)?((i%6)*3):(i*3)); var r = parseInt(j/6)*3; if(i>5) {r+=9;} r = fixColor(r); var color = '#' + r + g + b; cell.childNodes[0].style.backgroundColor = color; cell.childNodes[0].title = color; } row = table.insertRow(table.rows.length); } row = table.insertRow(table.rows.length); return table; } function fixColor(c){ var hexNum = [0,1,2,3,4,5,6,7,8,9,"A","B","C","D","E","F"]; c = parseInt(c); return hexNum[c]?hexNum[c]:0; } //切换元素css特性 function toggle(obj,css,val1,val2){ obj.style[css] = (obj.style[css] == val1 ? val2:val1); } //根据方法名调用相应方法 function dispatchMethod(arguments){ console.log(arguments); var method = arguments[0]; switch(method){ case "getHtmlText": var htmlText = $containerObj.find(".editor-content-cls").html(); return htmlText; break; default: throw new Error("方法【" + method + "】未定义!"); break; } } };//$.fn //20170302 返回obj位置 function getXY(obj){ //getBoundingClientRect()用于获取某个元素相对于视窗的位置集合。集合中有top, right, bottom, left等属性 var rect = obj.getBoundingClientRect(); //获取滑动条位置 var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft; var isIE = !(!document.all)?2:0; var position = {}; position.left = rect.left - isIE + scrollLeft; position.top = rect.top - isIE + scrollTop; return position; } }()); //点击字号超链接 <a>响应事件 function onclickFontSizeItem(obj){ var selectedFontSize = obj.innerText; document.execCommand('fontSize', false, selectedFontSize); $("div.fontSizeDlgCls").css('display', 'none'); } function setColor(obj){ //console.log("setColor evt: " ); //console.log(evt); //evt = evt || window.event; //var obj = evt.target || evt.srcElement;//获取点击td //console.log(obj); if(obj.title){ console.log("obj.title: " + obj.title); console.log("obj.style.backgroundColor: " + obj.style.backgroundColor); var clickColor = obj.title; document.execCommand('foreColor',false, clickColor); console.log("obj.parentNode.parentNode.parentNode: "); console.log(obj.parentNode.parentNode.parentNode); obj.parentNode.parentNode.parentNode.parentNode.style.display = 'none'; } } /* //确定或取消图片 以及 超链接输入 function submitPictureInput(){ var inputValue = $("div.pictureInputDIVCls input").val(); if(inputValue == ""){ alert("请输入图片url地址!"); return; } var result = document.execCommand('insertImage', false, inputValue); if(!result){ alert("图片插入失败"); } $("div.pictureInputDIVCls").css("display","none"); } function cancelPictureInput(){ $("div.pictureInputDIVCls").css("display","none"); } function submitLinkInput(){ var inputValue = $("div.linkInputDIVCls input").val(); if(inputValue == ""){ alert("请输入超链接url地址!"); return; } var result = document.execCommand('createLink', false, inputValue); if(!result){ alert("超链接插入失败"); } $("div.linkInputDIVCls").css("display","none"); } function cancelLinkInput(){ $("div.linkInputDIVCls").css("display","none"); } */
textEditor.css
.customed-textEditor-cls .editor-content-cls{
resize:vertical;
overflow:auto;
border:1px solid silver;
border-radius:5px;
min-height:200px;
box-shadow: inset 0 0 10px silver;
padding:1em;
}
/*图片的最大大小*/
div.customed-textEditor-cls img{
max-width:70%;
max-height:70%;
margin-left:15%;
}
.customed-textEditor-cls .content {
margin: 100px;
}
/*字体选择框*/
.fontSizeDlgCls ul{
border:1px solid #ddd;
width:40px;
margin-left:0px;
background-color:#fff;
}
.fontSizeDlgCls li{
list-style:none;
}
.fontSizeDlgCls li a{
color:#000;
width:40px;
display:inline-block;
}
.fontSizeDlgCls li:hover{
background-color:#0b569e;
}
.fontSizeDlgCls li:hover a{
color:#fff;
}
/* 20170328 颜色表*/
table.colorTableCls {
border:2px solid #eee;
}
table.colorTableCls td{
width:12px;
height:12px;
cursor:pointer;
padding:0px;
margin:0px;
}
/*颜色表*/
div.colorTableDIVCls {
background-color:#fff;
}
/*图片地址输入框和超链接输入框*/
div.tipCls{
font-size:15px;
font-weight:600;
margin-top:15px;
margin-bottom:10px;
}
input.inputTextCls{
margin-left:20px;
width:300px;
height:28px;
border-radius:5px;
margin-bottom:15px;
}
div.pictureInputDIVCls{
border:2px solid #eee;
width:400px;
height:120px;
padding-bottom:20px;
background-color:#fff;
}
div.linkInputDIVCls{
border:2px solid #eee;
width:400px;
height:120px;
padding-bottom:20px;
background-color:#fff;
}
textEditor.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>文本编辑器插件</title>
<!-- bootstrap.min.css -->
<!-- 通过<div class="Container-fluid">创建流式布局 适合应用于程序和文档类的网站-->
<link rel="stylesheet" th:href="@{/bootstrap/bootstrap-combined.min.css}" />
<!-- font-awesome 提供了大量的字体图标 可供使用 -->
<link rel="stylesheet" th:href="@{/css/font-awesome/font-awesome.css}" />
<link rel="stylesheet" th:href="@{/css/customedPlugins/textEditor.css}" />
<style type="text/css">
</style>
</head>
<body>
<h2>
文本编辑框测试
</h2>
<div id="textEditorDIV" class="customed-textEditor-cls">
</div>
<!--[if !IE]><!-->
<script th:src="@{/jquery/2.1.4/jquery-2.1.4.min.js}"></script>
<!--<![endif]-->
<!--[if IE]><!-->
<script th:src="@{/jquery/1.11.0/jquery-1.11.0.min.js}"></script>
<!--<![endif]-->
<script th:src="@{/bootstrap/3.3.5/js/bootstrap.min.js}"></script>
<script th:src="@{/js/customedPlugins/textEditor.js}"></script>
<script th:inline="javascript">
/*<![CDATA[*/
$("#textEditorDIV").textEditor();
/*]]>*/
</script>
</body>
</html>
效果展示: