[译] 通过 contentEditable 属性创建一个所见即所得的编辑器(富文本编辑器)
译者注
这只是一篇入门教程,介绍了一些基础知识,仅供参考,切不可因此觉得富文本编辑器很简单。
创建富文本编辑器是一个非常复杂的工程,需要考虑到方方面面,也有很多坑(请参考原文第一条评论)。
为免误导大家,特此说明。
格式说明:链接,名词,命令
原文:Create a WYSIWYG Editor With the contentEditable Attribute
WYSIWYG 编辑器非常常用,你或许在某个时候也使用过。
WYSIWYG:What You See Is What You Get,所见即所得。
通过一些第三方库,你可以快速地创建自己的编辑器,但也有一些明显的缺陷。首先,它们很重,许多特性你压根就用不到。另外,定制外观也非常蛋疼。
本文中,我们将按自己喜欢的风格,创建一个拥有基本格式化功能的、轻量的所见即所得编辑器。
我们将从介绍 execCommand 开始,因为在实现编辑器的过程中,我们会大量使用到该方法。
Document.execCommand()
execCommand 是 document 对象的一个方法,它提供了操作可编辑区域的内容的能力,和 contentEditable 配合使用,就可以实现一个富文本编辑器(rich-text editor)。
execCommand 方法可以进行各种编辑操作,如 添加链接、选中文本 加粗 或 斜体,修改 字体 或 字体颜色,使用语法如下:
document.execCommand(CommandName, ShowDefaultUI, ValueArgument);
CommandName:DOMString,指定所要执行的命令。
ShowDefaultUI:Boolean,指定是否显示用户界面,该选项还未完全实现,一般设置为 false。
ValueArgument:提供命令的附加参数,如图片URL或颜色值。不需要附加参数时,设置为 null。
我们将使用不同的命令来实现各种功能,下面逐一介绍。
无附加参数的命令
部分命令不需要附加参数(ValueArgument),如加粗(bold)、对齐(justify)、撤销(undo)、重做(redo),使用下面的语法:
document.execCommand(commandName, false, null);
CommandName 为命令名,如 justifyCenter、justifyRight、bold 等。
带附加参数的命令
部分命令需要传入相应的附加参数,如插入图片(insertImage)、创建链接(createLink)、字体颜色(foreColor),使用下面的语法:
document.execCommand(commandName, false, value);
commandName 为 insertImage 时,value 为将要插入的图片的 URL。
commandName 为 foreColor 时,value 为颜色值字符串,如 #FF9966、blue。
添加块样式标签的命令
添加 HTML 块样式标签(Block-Style Tags),需要将 commandName 指定为 formatBlock、ValueArgument 设置为标签名(tag name),使用下面的语法:
document.execCommand('formatBlock', false, tagName);
该命令将为当前选中行添加一个 HTML 块样式标签,如果本身已带有标签,则将被替换掉。
tagName 为块样式标签名,如标题标签(h1-h6)、段落标签(p)或块引用(blockquote)。
上面是一些最常用的命令,更多信息请参考 document.execCommand API 文档,那里有所有可用命令的列表。
创建一个工具栏
了解了基础知识,下面我们来创建一个工具栏,工具栏的按钮我使用了 Font Awesome 图标。
大家可能也注意到了,除了少数区别,所有的 execCommand 命令都有类似的结构,基于这个特点,我们可以使用下面的节点结构来定义工具栏的按钮:
<a href="#" data-command='commandName'><i class='fa fa-icon'></i></a>
通过这种方式,当用户点击按钮时,我们可以从 data-command 属性中获取到 execCommand 所要执行的命令。
例如下面这些例子:
<a href="#" data-command='h2'>H2</a>
<a href="#" data-command='undo'><i class='fa fa-undo'></i></a>
<a href="#" data-command='createlink'><i class='fa fa-link'></i></a>
<a href="#" data-command='justifyLeft'><i class='fa fa-align-left'></i></a>
<a href="#" data-command='superscript'><i class='fa fa-superscript'></i></a>
第一个按钮的 data-command 属性值为 h2,在 JavaScript 中获取到这个值后,我们将使用 execCommand 方法的 添加块样式标签的命令。同样的,最后一个按钮,superscript 则表示应该使用 无附加参数的命令。
创建字体颜色(foreColor)和背景颜色(backColor)按钮则是另外一种实现方法,这里主要有两个问题。
第一个问题是,提供给用户选择的颜色越多,需要编写的代码就越多,很麻烦而且容易出错。可以使用下面的 JavaScript 来处理这个问题:
var colorPalette = ['000000', 'FF9966', '6699FF', '99FF66','CC0000', '00CC00', '0000CC', '333333', '0066FF', 'FFFFFF']; var forePalette = $('.fore-palette'); for (var i = 0; i < colorPalette.length; i++) {
forePalette.append('<a href="#" data-command="forecolor" data-value="' + '#' + colorPalette[i] + '" style="background-color:' + '#' + colorPalette[i] + ';" class="palette-item"></a>');
}
注意这里我也给每个颜色值设置了一个 data-value 属性,后面可以作为 execCommand 方法的 ValueArgument 参数。
第二个问题是,我们总不能一直显示那么多颜色块吧,这样会占用很大的空间,给用户带来不好的体验。通过一些简单的 CSS,就可以实现一个不错的效果:只有当用户把鼠标移上按钮时,才会显示调色板。
按钮的节点结构需要调整为:
<div class="fore-wrapper"><i class='fa fa-font'></i>
<div class="fore-palette">
</div>
</div>
要让按钮在鼠标移上时才显示,我们需要添加以下 CSS:
.fore-palette,
.back-palette {
display: none;
} .fore-wrapper:hover .fore-palette,
.back-wrapper:hover .back-palette {
display: block;
float: left;
position: absolute;
}
在 CodePen 的 示例 中,还有许多其它的 CSS 代码用于美化工具栏,但核心功能所需的就只有上面这些。
给编辑器添加功能
现在,是时候来实现我们的编辑器的功能了。所需的代码惊人的少:
$('.toolbar a').click(function(e) { var command = $(this).data('command'); if (command == 'h1' || command == 'h2' || command == 'p') {
document.execCommand('formatBlock', false, command);
} if (command == 'forecolor' || command == 'backcolor') {
document.execCommand($(this).data('command'), false, $(this).data('value'));
} if (command == 'createlink' || command == 'insertimage') {
url = prompt('Enter the link here: ','http:\/\/');
document.execCommand($(this).data('command'), false, url);
} else document.execCommand($(this).data('command'), false, null); });
我们侦听了工具栏上所有按钮的点击事件,当按钮被点击时,将其 data-commond 属性的值保存到变量 commond 中,用于后面执行 execCommand 方法的相应命令,避免重复获取,也使代码更加简洁。
设置字体颜色(foreColor)和背景颜色(backColor)时,使用了 data-value 属性的值作为第三个参数。
对于创建链接(createLink)和插入图片(insertImage)命令所需的 url 参数,使用了一个提示弹框(prompt)来获取用户输入的值。当然你也可以添加一些额外的逻辑来检测 url 的有效性。
如果 command 变量不满足上面所有的 if 条件,则执行默认的 execCommand 命令。
这个就是我们实现出来的 WYSIWYG 编辑器:
你也可以使用我 上个教程 介绍的 localStorage 来实现自动保存功能。
跨浏览器差异
对于 execCommand,不同的浏览器会有不同的实现。例如 formatBlock,IE 只支持标题标签(h1-h6)、address 和 pre,甚至在指定 commandName 时还需要包含标签符,如 <h3>。
也不是所有的浏览器都支持所有的命令,IE 就不支持 insertHTML 和 hiliteColor,insertBrOnReturn 只有 Firefox 支持。
更多浏览器差异,可以参考 这个 GitHub 页面。
最后的感想
创建自己的 WYSIWYG 编辑器是一个非常好的学习过程,在本篇教程中,讨论了许多 execCommand 命令,使用了一些 CSS 来处理基础外观。作为练习,建议大家通过文本选择器(text selection)实现一个工具栏按钮,用于设置字体(font),实现方法和字体颜色(foreColor)按钮类似。
希望大家喜欢这篇教程,并能从中学到一些新的东西。
[译] 通过 contentEditable 属性创建一个所见即所得的编辑器(富文本编辑器)的更多相关文章
- html5中contenteditable属性如果过滤标签,过滤富文本样式
在div中使用contenteditable=”true”可以达到模拟输入框的效果,但是当我们复制其他网页内容进去的时候,会发现连带的样式也一起复制进去了.很明显我们不需要复制富文本样式,那么如何 ...
- 从零开始, 开发一个 Web Office 套件 (1): 富文本编辑器
这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Office 套件, 包括: 文档, 表格, 幻灯片... 等等. 富文本编辑器 万里长征 ...
- [前端随笔][JavaScript] 制作一个富文本编辑器
写在前面 现在网上有很多现成的富文本编辑器,比如百度家的UEditor,kindeditor,niceditor等等,功能特别的多,API也很多,要去熟悉他的规则也很麻烦,所以想自己了解一下原理,做一 ...
- ASP.NET MVC + 百度富文本编辑器 + EasyUi + EntityFrameWork 制作一个添加新闻功能
本文将交大伙怎么集成ASP.NET MVC + 百度富文本编辑器 + EasyUi + EntityFrameWork来制作一个新闻系统 先上截图: 添加页面如下: 下面来看代码部分 列表页如下: @ ...
- 基于ABP做一个简单的系统——实战篇:4.基于富文本编辑器,Razor模板引擎生成内容并导出Word 填坑记录
起因 需求是这样的,有一种协议需要生成,协议的模板是可配置的,在生成过程中,模板中的内容可以根据约定的标记进行替换(就像mvc的razor模板一样).生成后的内容还需要导出成word或pdf. 常见的 ...
- 从零开始, 开发一个 Web Office 套件 (2): 富文本编辑器
书接前文: 从零开始, 开发一个 Web Office 套件 (1): 富文本编辑器 这是一个系列博客, 最终目的是要做一个基于HTML Canvas 的, 类似于微软 Office 的 Web Of ...
- linq to sql用partial扩展属性,创建一个部分类(用于多表连接)
1.在窗体中创建dataGridView显示表: using System; using System.Collections.Generic; using System.ComponentModel ...
- 一个简单的Android富文本TextView实现
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 24.0px Helvetica; color: #555555 } p.p2 { margin: 0.0p ...
- 实现一个最简单的VIM文本编辑器(可能有bug,随便写了一个)
简单的写了一个文本编辑器,功能很简单,但足以把文件IO相关的操作熟悉了,可能功能或者分配的大小还不够完善.请参考参考: #include <stdio.h> #include <co ...
随机推荐
- Selenium2+python自动化14-iframe【转载】
前言 有很多小伙伴在拿163作为登录案例的时候,发现不管怎么定位都无法定位到,到底是什么鬼呢,本篇详细介绍iframe相关的切换 以http://mail.163.com/登录页面10为案例,详细介绍 ...
- [BZOJ2152]聪聪可可 点分治/树形dp
2152: 聪聪可可 Time Limit: 3 Sec Memory Limit: 259 MB Submit: 3602 Solved: 1858 [Submit][Status][Discu ...
- 利用JavaScript打印出Fibonacci数(不使用全局变量)
从汤姆大叔的博客里看到了6个基础题目:本篇是第4题 - 利用JavaScript打印出Fibonacci数(不使用全局变量) 解题关键: 1.Fibonacci数列的规律 2.递归 解点1:Fibon ...
- POJ 3735 Training little cats(矩阵乘法)
[题目链接] http://poj.org/problem?id=3735 [题目大意] 有一排小猫,给出一系列操作,包括给一只猫一颗花生, 让某只猫吃完所有的花生以及交换两只猫的花生, 求完成m次操 ...
- unity3d 场景配置文件生成代码
using UnityEngine; using UnityEditor; using System.IO; using System; using System.Text; using System ...
- 利用.net4.0的dynamic特性制造的超级简单的微信SDK
1.基础支持API /*-------------------------------------------------------------------------- * BasicAPI.cs ...
- sql server 带有OUTPUT的INSERT,DELETE,UPDATE
原文:sql server 带有OUTPUT的INSERT,DELETE,UPDATE OUTPUT是SQL SERVER2005的新特性.可以从数据修改语句中返回输出.可以看作是"返回结果 ...
- ubuntu安装KVM
1. vmware安装ubuntu-14.04.1-server-amd64.iso.2. 安装完成后关机--右键虚拟机--setting--hardware--Processors--将 virtu ...
- ife2015-task2-1-2-3
task2-1.html <!DOCTYPE html><html><head lang="en"> <meta charset=&quo ...
- yaffs和jffs2简单比较
转:http://blog.chinaunix.net/uid-27675161-id-3392636.html 相关知识引用<嵌入式 Linux 应用开发 完全手册> Nand F ...