首页 > 代码库 > 如何做一个富文本编辑器

如何做一个富文本编辑器

很久以前就想做一个富文本编辑器,但是感觉比较难,一直没有实现。直到了解了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>|&nbsp;)*$/, ‘‘);
        };
        $(".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>

 

最终效果图: