百度富文本编辑器(UEditor)
UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码。
基本demo
- 进入ueditor官网下载压缩包,解压后就是ueditor的基本demo,包含了ueditor所需要的js css等文件
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>完整demo</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<script type="text/javascript" charset="utf-8" src="ueditor.config.js"></script>
<script type="text/javascript" charset="utf-8" src="ueditor.all.min.js"> </script>
<!--建议手动加在语言,避免在ie下有时因为加载语言失败导致编辑器加载失败-->
<!--这里加载的语言文件会覆盖你在配置项目里添加的语言类型,比如你在配置项目里配置的是英文,这里加载的中文,那最后就是中文-->
<script type="text/javascript" charset="utf-8" src="lang/zh-cn/zh-cn.js"></script>
<style type="text/css">
div{
width:100%;
}
</style>
</head>
<body>
<div>
<script id="editor" type="text/plain" style="width:1024px;height:500px;">
</script>
</div>
<script type="text/javascript">
//实例化编辑器
//建议使用工厂方法getEditor创建和引用编辑器实例,如果在某个闭包下引用该编辑器,直接调用UE.getEditor('editor')就能拿到相关的实例
var ue = UE.getEditor('editor');
</script>
</body>
</html>
基本API
- 获得整个html的内容
UE.getEditor('editor').getAllHtml()
- 获得内容(带有元素标签 但是不包含整个html)
UE.getEditor('editor').getContent()
- 写入内容
UE.getEditor('editor').setContent('欢迎使用ueditor')
- 追加内容
UE.getEditor('editor').setContent('欢迎使用ueditor', true)
- 获得纯文本
UE.getEditor('editor').getContentTxt()
- 获得带格式的纯文本(空格,换行)
UE.getEditor('editor').getPlainTxt()
- 判断是否有内容
UE.getEditor('editor').hasContents()
- 使编辑器获得焦点
UE.getEditor('editor').focus();
- 使编辑器获得焦点
UE.getEditor('editor').focus();
- 编辑器是否获得焦点
UE.getEditor('editor').isFocus()
- 编辑器失去焦点
UE.getEditor('editor').blur()
- 获得当前选中的文本
//当你点击按钮时编辑区域已经失去了焦点,如果直接用getText将不会得到内容,所以要在选回来,然后取得内容
var range = UE.getEditor('editor').selection.getRange();
range.select();
var txt = UE.getEditor('editor').selection.getText();
- 插入给定的内容
UE.getEditor('editor').execCommand('insertHtml', '<div>插入给定的内容</div>')
- 其他
//可以编辑
UE.getEditor('editor').setEnabled()
//不可编辑
UE.getEditor('editor').setDisabled('fullscreen');
//隐藏编辑器
UE.getEditor('editor').setHide()
//显示编辑器
UE.getEditor('editor').setShow()
//设置高度为300默认关闭了自动长高
UE.getEditor('editor').setHeight(300)
//获取草稿箱内容
UE.getEditor('editor').execCommand( "getlocaldata" )
//清空草稿箱
UE.getEditor('editor').execCommand( "clearlocaldata" )
其余相关api请参考UEditor Docs
拓展相关
- 图片上传配置
在页面中配置你的图片上传路径
UE.Editor.prototype._bkGetActionUrl = UE.Editor.prototype.getActionUrl;
UE.Editor.prototype.getActionUrl = function(action) {
if (action == 'uploadimage' || action == 'uploadscrawl' || action == 'uploadimage') {
// 为方法imgUpload的访问地址
return '你的上传路径';
} else if (action == 'uploadfile' ){
//上传附件的访问地址
return '你的上传路径';
}else {
return this._bkGetActionUrl.call(this, action);
}
}
在config.json中配置图片相关配置信息
/* 上传图片配置项 */
"imageActionName": "uploadimage", /* 执行上传图片的action名称 */
"imageFieldName": "upfile", /* 提交的图片表单名称 */
"imageMaxSize": 2048000, /* 上传大小限制,单位B */
"imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], /* 上传图片格式显示 */
"imageCompressEnable": true, /* 是否压缩图片,默认是true */
"imageCompressBorder": 1600, /* 图片压缩最长边限制 */
"imageInsertAlign": "none", /* 插入的图片浮动方式 */
"imageUrlPrefix": "", /* 图片访问路径前缀 */
"imagePathFormat": "/ueditor/jsp/upload/image/{yyyy}{mm}{dd}/{time}{rand:6}", /* 上传保存路径,可以自定义保存路径和文件名格式 */
/* {filename} 会替换成原文件名,配置这项需要注意中文乱码问题 */
/* {rand:6} 会替换成随机数,后面的数字是随机数的位数 */
/* {time} 会替换成时间戳 */
/* {yyyy} 会替换成四位年份 */
/* {yy} 会替换成两位年份 */
/* {mm} 会替换成两位月份 */
/* {dd} 会替换成两位日期 */
/* {hh} 会替换成两位小时 */
/* {ii} 会替换成两位分钟 */
/* {ss} 会替换成两位秒 */
/* 非法字符 \ : * ? " < > | */
/* 具请体看线上文档: fex.baidu.com/ueditor/#use-format_upload_filename */
- 工具栏配置toolbars
修改 ueditor.config.js 里面的 toolbars;
实例化编辑器的时候传入 toolbars 参数;
UE.getEditor('editor', {
toolbars: [[//工具条
]]
});
其他相关前端配置配置详见demo中的ueditor.config.js里面相关配置有具体注释
- 自定义按钮
UE.registerUI('button', function(editor, uiName) {
//注册按钮执行时的command命令,使用命令默认就会带有回退操作
editor.registerCommand(uiName, {
execCommand: function() {
alert('execCommand:' + uiName)
}
});
//创建一个button
var btn = new UE.ui.Button({
//按钮的名字
name: uiName,
//提示
title: uiName,
//添加额外样式,指定icon图标,这里默认使用一个重复的icon
cssRules: 'background-position: -500px 0;',
//点击时执行的命令
onclick: function() {
//这里可以不用执行命令,做你自己的操作也可
editor.execCommand(uiName);
}
});
//当点到编辑内容上时,按钮要做的状态反射
editor.addListener('selectionchange', function() {
var state = editor.queryCommandState(uiName);
if (state == -1) {
btn.setDisabled(true);
btn.setChecked(false);
} else {
btn.setDisabled(false);
btn.setChecked(state);
}
});
//因为你是添加button,所以需要返回这个button
return btn;
});
- 配置默认项
ue.ready(function(){
ue.options.imageMaxSize = 10240000;
ue.options.imageAllowFiles = [".png", ".jpg", ".jpeg", ".gif"];
ue.options.imageManagerListSize = 3;
ue.options.fileMaxSize = 10240000;
ue.setHeight(400);
ue.execCommand('fontfamily','宋体'); //字体
ue.execCommand('fontsize', '12px');
ue.execCommand('indent', true);
});
实际在config文件中配置无效 需要在ready中配置
注意事项
- 当插入一段带有style标签样式的html 富文本会对这部分css样式顾虑掉
解决:关闭ueditor.all.js中的xssFilter相关配置(这可能引发相关xss等安全问题,需要在后端对富文本内容做处理) - 当有段带样式的文本删除后,在不点击其他位置后,再输入依然会沿用之前样式
解决:目前暂未找到直接处理方式,可以用blur(),focus()解决 - 因为这个富文本编辑器初始化是异步的,所以有时候赋值操作会无效
解决: 在ready方法中赋值
UE.getEditor('editor').ready(function() {
//this是当前创建的编辑器实例
this.setContent('内容')
})
Summernote
一款基于jQuery 和 Bootstrap 构建,轻巧、友好、易于集成、使用方便的富文本编辑器
基本demo
进入官网下载最新的js css等文件
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="UTF-8">
<title>Summernote</title>
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css"rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script>
<link href="./summernote.css" rel="stylesheet">
<script src="./summernote.js"></script>
</head>
<body>
<div id="summernote"><p>Hello Summernote</p></div>
<script>
$(document).ready(function(){
$('#summernote').summernote();
});
</script>
</body>
</html>
基本api
- 设置编辑器高度
$('#summernote').summernote({
height:300, // set editor height
minHeight:null, // set minimum height of editor
maxHeight:null, // set maximum height of editor
focus:true // set focus to editable area after initializing summernote
});
- 设置代码
$('#summernote').summernote('code','设置代码');
- 获取代码
$('#summernote').summernote('code');
更多api请参考官网
扩展相关
- 图片上传
callbacks: {
onImageUpload: function(files) {
// upload image to server and create imgNode...
let imgNode = document.createElement('img');
imgNode.setAttribute("src", './t.png')
$("#summernote").summernote('insertNode', imgNode);
}
}
该上传方法定义在回调方法中,还有像onChange,onEnter,onKeyup, onKeydown,onMouseDown,onMouseUp,onPaste 这些方法也都是这样使用
- 自定义按钮
var helloButton=function(context){
var ui=$.summernote.ui;
// create button
var button=ui.button({
contents:'<i class="fa fa-child"/> Hello',
tooltip:'hello',
click:function(){
// invoke insertText method with 'hello' on editor module.
context.invoke('editor.insertText','hello');
}
});
return button.render(); // return button as jquery object
}
//定义在toolbar中
$('.summernote').summernote({
toolbar:[
['mybutton',['hello']]
],
buttons:{
hello:HelloButton
}
});
Froala
一款用Javascript编写的轻量级所见即所得的HTML编辑器
基本demo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css">
<link rel="stylesheet" href="./css/froala_editor.css">
<link rel="stylesheet" href="./css/froala_style.css">
<link rel="stylesheet" href="./css/plugins/code_view.css">
<link rel="stylesheet" href="./css/plugins/draggable.css">
<link rel="stylesheet" href="./css/plugins/colors.css">
<link rel="stylesheet" href="./css/plugins/emoticons.css">
<link rel="stylesheet" href="./css/plugins/image_manager.css">
<link rel="stylesheet" href="./css/plugins/image.css">
<link rel="stylesheet" href="./css/plugins/line_breaker.css">
<link rel="stylesheet" href="./css/plugins/table.css">
<link rel="stylesheet" href="./css/plugins/char_counter.css">
<link rel="stylesheet" href="./css/plugins/video.css">
<link rel="stylesheet" href="./css/plugins/fullscreen.css">
<link rel="stylesheet" href="./css/plugins/file.css">
<link rel="stylesheet" href="./css/plugins/quick_insert.css">
<link rel="stylesheet" href="./css/plugins/help.css">
<link rel="stylesheet" href="./css/third_party/spell_checker.css">
<link rel="stylesheet" href="./css/plugins/special_characters.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.3.0/codemirror.min.css">
<style>
body {
text-align: center;
}
div#editor {
width: 81%;
margin: auto;
text-align: left;
}
.ss {
background-color: red;
}
</style>
</head>
<body>
<div id="editor">
<div id='edit' style="margin-top: 30px;">
</div>
</div>
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.3.0/codemirror.min.js"></script>
<script type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.3.0/mode/xml/xml.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.2.7/purify.min.js"></script>
<script type="text/javascript" src="./js/froala_editor.min.js"></script>
<script type="text/javascript" src="./js/plugins/align.min.js"></script>
<script type="text/javascript" src="./js/plugins/char_counter.min.js"></script>
<script type="text/javascript" src="./js/plugins/code_beautifier.min.js"></script>
<script type="text/javascript" src="./js/plugins/code_view.min.js"></script>
<script type="text/javascript" src="./js/plugins/colors.min.js"></script>
<script type="text/javascript" src="./js/plugins/draggable.min.js"></script>
<script type="text/javascript" src="./js/plugins/emoticons.min.js"></script>
<script type="text/javascript" src="./js/plugins/entities.min.js"></script>
<script type="text/javascript" src="./js/plugins/file.min.js"></script>
<script type="text/javascript" src="./js/plugins/font_size.min.js"></script>
<script type="text/javascript" src="./js/plugins/font_family.min.js"></script>
<script type="text/javascript" src="./js/plugins/fullscreen.min.js"></script>
<script type="text/javascript" src="./js/plugins/image.min.js"></script>
<script type="text/javascript" src="./js/plugins/image_manager.min.js"></script>
<script type="text/javascript" src="./js/plugins/line_breaker.min.js"></script>
<script type="text/javascript" src="./js/plugins/inline_style.min.js"></script>
<script type="text/javascript" src="./js/plugins/link.min.js"></script>
<script type="text/javascript" src="./js/plugins/lists.min.js"></script>
<script type="text/javascript" src="./js/plugins/paragraph_format.min.js"></script>
<script type="text/javascript" src="./js/plugins/paragraph_style.min.js"></script>
<script type="text/javascript" src="./js/plugins/quick_insert.min.js"></script>
<script type="text/javascript" src="./js/plugins/quote.min.js"></script>
<script type="text/javascript" src="./js/plugins/table.min.js"></script>
<script type="text/javascript" src="./js/plugins/save.min.js"></script>
<script type="text/javascript" src="./js/plugins/url.min.js"></script>
<script type="text/javascript" src="./js/plugins/video.min.js"></script>
<script type="text/javascript" src="./js/plugins/help.min.js"></script>
<script type="text/javascript" src="./js/plugins/print.min.js"></script>
<script type="text/javascript" src="./js/third_party/spell_checker.min.js"></script>
<script type="text/javascript" src="./js/plugins/special_characters.min.js"></script>
<script type="text/javascript" src="./js/plugins/word_paste.min.js"></script>
<script>
$(function(){
//超大屏幕的功能按钮
let toolbarButtons = ['fullscreen', 'bold', 'italic', 'underline', 'strikeThrough', 'subscript', 'superscript',
'fontFamily', 'fontSize', '|', 'color', 'emoticons', 'inlineStyle', 'paragraphStyle', '|',
'paragraphFormat', 'align', 'formatOL', 'formatUL', 'outdent', 'indent', 'quote', 'insertHR',
'-', 'insertLink', 'insertImage', 'insertVideo', 'insertFile', 'insertTable', 'undo', 'redo', 'clearFormatting', 'selectAll', 'html' ,'clear'];
//大屏幕的功能按钮
let toolbarButtonsMD = ['fullscreen', 'bold', 'italic', 'underline', 'fontFamily', 'fontSize', 'color',
'paragraphStyle', 'paragraphFormat', 'align', 'formatOL', 'formatUL', 'outdent', 'indent',
'quote', 'insertHR', 'insertLink', 'insertImage', 'insertVideo', 'insertFile', 'insertTable', 'undo', 'redo', 'clearFormatting'];
//小屏幕的功能按钮
let toolbarButtonsSM = ['fullscreen', 'bold', 'italic', 'underline', 'fontFamily', 'fontSize',
'insertLink', 'insertImage', 'insertTable', 'undo', 'redo'];
//手机的功能按钮
let toolbarButtonsXS = ['bold', 'italic', 'fontFamily', 'fontSize', 'undo', 'redo'];
edit = new FroalaEditor("#edit",{
fontSizeDefaultSelection: '18',
fontSizeSelection: true,
// fullPage: true,
placeholderText: '请输入内容', //默认填充内容
charCounterCount : true,//默认 显示字数
saveInterval : 0,//不自动保存,默认10000,0为不自动保存
//theme : "dark",//主题:dark,red,gray,royal,注意需要引入对应主题的css
height : "600px",
toolbarBottom : false,//默认
toolbarButtons : toolbarButtons,
toolbarInline : false,//true选中设置样式,默认false
imageUploadMethod : 'POST',
heightMin: 450,
tabSpaces: 4,
charCounterMax: -1, //最大字数限制,-1为不限制
// saveURL: '${ctx}/webmana/article/saveArticle', //自动保存的地址(body参数为html内容)
// saveParams: { postId: '1'}, //保存内容时传的参数
spellcheck: false, //是否允许浏览器对输入内容进行拼写检查
imageUploadURL: '/feditor/upload',//上传到本地服务器
imageUploadParams: {name: new Date().getTime() + Math.ceil(Math.random()*100000) + ".jpg"}, //上传图片时带的参数
imageDefaultWidth: 400, //上传图片后的默认大小
//imageResizeWithPercent: true,//不设置这个,imageDefaultWidth的单位为像素,设置后为%
videoUploadURL:'/feditor/upload',
videoUploadParams: {name: new Date().getTime() + ".mp4"}, //上传图片时带的参数
// enter: $.FroalaEditor.ENTER_BR, //设置回车键功能
language: 'zh_cn',
})
});
</script>
</body>
</html>
基本api
- 获取编辑器内容
$('#edit').froalaEditor.html.get(true);
- 编辑器插入内容
$('#edit').froalaEditor.html.insert('插入内容');
其他相关api可以参考官网
扩展相关
- 相关事件监听
events: {
'image.beforeUpload': function (images) {
// Return false if you want to stop the image upload.
},
'image.uploaded': function (response) {
// Image was uploaded to the server.
},
'image.inserted': function ($img, response) {
// Image was inserted in the editor.
},
'image.replaced': function ($img, response) {
// Image was replaced in the editor.
},
initialized: function () {
// console.log(init_html)
},
//<img data-fr-image-pasted="true" data-id="image-id">
contentChanged: function () {
}
}
- 图片/视频上传
imageUploadURL: '/feditor/upload',//上传到本地服务器
imageUploadParams: {name: new Date().getTime() + Math.ceil(Math.random()*100000) + ".jpg"}, //上传图片时带的参数
imageDefaultWidth: 400, //上传图片后的默认大小
//imageResizeWithPercent: true,//不设置这个,imageDefaultWidth的单位为像素,设置后为%
videoUploadURL:'/feditor/upload',
videoUploadParams: {name: new Date().getTime() + ".mp4"}, //上传图片时带的参数
- 自定义工具栏按钮
FroalaEditor.DefineIcon('clear', {NAME: 'remove', SVG_KEY: 'remove'});
FroalaEditor.RegisterCommand('clear', {
title: '清空内容',
focus: false,
undo: true,
refreshAfterCallback: true,
callback: function () {
this.html.set('');
this.events.focus();
}
});
注意事项
- 图片无法拖拽上传
解决:拖拽后只会有路径url 需要在change监听事件中处理图片 - 因为该富文本不是免费的所以在部署到服务上后会有权限相关提示,内容中也会有
解决:通过js隐藏,删除