TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有:UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等。
经过多番对比(界面好看),认定Tinymce功能更加完善,并且具备可扩展特性,功能完善,遂采用。
下面是tinymce实例化的例子,通过id绑定,渲染页面。tinymce可以嵌入到任意web项目中。编辑内容的保存可以通过post表单的形式提交,也可以自己获取内容提交。
<!DOCTYPE html> <html> <head> </head> <body> <h1>TinyMCE快速开始示例</h1> <form method="post"> <textarea id="demo">Hello, World!</textarea> </form> </body <script src='tinymce.min.js'></script> <script> tinymce.init({ selector: '#demo'//ID绑定 //此处可添加更多特性 }); </script> </html>支持图片、视频
tinymce.init({ selector: '#content',//绑定渲染区 height: 600, plugins: 'paste importcss code table advlist fullscreen imagetools textcolor colorpicker hr autolink link image lists preview media wordcount', toolbar: 'styleselect | formatselect | fontsizeselect | forecolor backcolor | bold italic underline strikethrough | image media | table | alignleft aligncenter alignright alignjustify | outdent indent | numlist bullist | preview removeformat hr | paste code link | undo redo | fullscreen', skin: 'oxide', language: 'zh_CN',//汉化 convert_urls: false, // relative_urls : true, images_upload_url: '../tmmedia/upload',//图片上传地址 images_upload_credentials: true, image_dimensions: false, image_class_list: [ {title: '无', value: ''}, {title: '预览', value: 'preview'}, ], // images_upload_base_path: '/', forced_root_block: 'p', force_p_newlines: true, importcss_append: true, content_style: ` * { padding:0; margin:0; } html, body { height:100%; } img { max-width:100%; display:block;height:auto; } a { text-decoration: none; } iframe { width: 100%; } p { line-height:1.6; margin: 0px; } table { word-wrap:break-word; word-break:break-all; max-width:100%; border:none; border-color:#999; } .mce-object-iframe { width:100%; box-sizing:border-box; margin:0; padding:0; } ul,ol { list-style-position:inside; } `, insert_button_items: 'image link | inserttable', // CONFIG: Paste paste_retain_style_properties: 'all', paste_word_valid_elements: '*[*]', // word需要它 paste_data_images: true, // 粘贴的同时能把内容里的图片自动上传 paste_convert_word_fake_lists: false, // 插入word文档需要该属性 paste_webkit_styles: 'all', paste_merge_formats: true, nonbreaking_force_tab: false, paste_auto_cleanup_on_paste: false, // CONFIG: Font fontsize_formats: '10px 11px 12px 14px 16px 18px 20px 24px', // CONFIG: StyleSelect style_formats: [ { title: '首行缩进', block: 'p', styles: {'text-indent': '2em'} }, { title: '行高', items: [ {title: '1', styles: {'line-height': '1'}, inline: 'span'}, {title: '1.5', styles: {'line-height': '1.5'}, inline: 'span'}, {title: '2', styles: {'line-height': '2'}, inline: 'span'}, {title: '2.5', styles: {'line-height': '2.5'}, inline: 'span'}, {title: '3', styles: {'line-height': '3'}, inline: 'span'} ] } ], // Tab tabfocus_elements: ':prev,:next', object_resizing: true, // Image imagetools_toolbar: 'rotateleft rotateright | flipv fliph | editimage imageoptions', file_picker_types: 'media', media_live_embeds: true, //be used to add custom file picker to those dialogs that have it. file_picker_callback: function (cb, value, meta) { if (meta.filetype == 'media') { //创建一个隐藏的type=file的文件选择input let input = document.createElement('input'); input.setAttribute('type', 'file'); input.onchange = function(){ let file = this.files[0];//只选取第一个文件。如果要选取全部,后面注意做修改 let xhr, formData; xhr = new XMLHttpRequest(); xhr.open('POST', '../tmmedia/upload');//自定义文件上传 xhr.withCredentials = true; xhr.upload.onprogress = function (e) { // 进度(e.loaded / e.total * 100) }; xhr.onerror = function () { console.log(xhr.status); return; }; xhr.onload = function () { let json; if (xhr.status < 200 || xhr.status >= 300) { console.log('HTTP 错误: ' + xhr.status); return; } json = JSON.parse(xhr.responseText); console.log(json) //接口返回的文件保存地址 let mediaLocation=json.location; //cb()回调函数,将mediaLocation显示在弹框输入框中 cb(mediaLocation, { title: file.name }); }; formData = new FormData(); //假设接口接收参数为file,值为选中的文件 formData.append('file', file); //正式使用将下面被注释的内容恢复 xhr.send(formData); } //触发点击 input.click(); } } });实现效果
通过 tinymce.activeEditor.getContent()获取编辑区内容,内容为html代码。
form.on('submit(save)', function (data) { var field = data.field; //获取内容核心 field.content = tinymce.activeEditor.getContent() var loadIndex; loadIndex = layer.load(2); $.post("../tmknowledgebase/saveOrUpdate", field, function (data) { if (data.code === 200) { tools.success("保存成功!"); layer.msg("成功!", {time: 1000}, function () { layer.close(loadIndex); //传给上个页面,刷新table用 tools.putTempData('submitOK', true); //关掉对话框 tools.closeThisDialog(); }); } else { layer.close(loadIndex) tools.error(data.msg); } }) })在保存编辑内容后,如果我们想要再次编辑,需要对以保存内容进行回显,之前提到,保存的内容实际是html片段,因此采用html渲染即可。在此项目中采用Freemarker框架,渲染代码如下:
${data.content!""}为后台返回的编辑区内容
<div class="layui-card-body layui-form-item"> <textarea id="content" name="content">${data.content!""}</textarea> </div>实例化区域代码与上文相同
tinymce.init({ selector: '#content', height: 600, ...tinymce默认是英文的,需要引入汉化包zh_CN.js到langs目录下,在language属性下添加zh_CN.
tinymce.init({ selector: '#content', language:'zh_CN',//注意大小写 });首先后台自定义文件上传接口
注意:需要指定具体的下载地址,否则上传后文件无法回显map.put("location", "当前文件实际下载地址");
@PostMapping(value = "/tmmedia/upload") public Object downloadFile(@RequestParam MultipartFile file) { Map<String, String> map = new HashMap<>(); try { String fileName = file.getOriginalFilename(); String extension = StringUtils.getFilenameExtension(fileName); String name = IdUtil.fastUUID() + "." + extension; ftpUtils.upload(dir, name, file); // 文件下载,供前台回显 map.put("location", downloadUrl + dir + "/" + name); } catch (Exception e) { e.printStackTrace(); map.put("location", ""); } return map; }渲染区配置
tinymce.init({ selector: '#content', language:'zh_CN',//注意大小写 plugins: image ', images_upload_url: '../tmmedia/upload',//图片上传地址 images_upload_credentials: true, image_dimensions: false, image_class_list: [ {title: '无', value: ''}, {title: '预览', value: 'preview'}, ], });首先后台自定义文件上传接口
注意:需要指定具体的下载地址,否则上传后文件无法回显map.put("location", "当前文件实际下载地址");
@PostMapping(value = "/tmmedia/upload") public Object downloadFile(@RequestParam MultipartFile file) { Map<String, String> map = new HashMap<>(); try { String fileName = file.getOriginalFilename(); String extension = StringUtils.getFilenameExtension(fileName); String name = IdUtil.fastUUID() + "." + extension; ftpUtils.upload(dir, name, file); // 文件下载,供前台回显 map.put("location", downloadUrl + dir + "/" + name); } catch (Exception e) { e.printStackTrace(); map.put("location", ""); } return map; }渲染区配置
tinymce.init({ selector: '#content', language:'zh_CN',//注意大小写 plugins: media ', file_picker_types: 'media', media_live_embeds: true, //be used to add custom file picker to those dialogs that have it. file_picker_callback: function (cb, value, meta) { if (meta.filetype == 'media') { //创建一个隐藏的type=file的文件选择input let input = document.createElement('input'); input.setAttribute('type', 'file'); input.onchange = function(){ let file = this.files[0];//只选取第一个文件。如果要选取全部,后面注意做修改 let xhr, formData; xhr = new XMLHttpRequest(); xhr.open('POST', '../tmmedia/upload');//自定义文件上传 xhr.withCredentials = true; xhr.upload.onprogress = function (e) { // 进度(e.loaded / e.total * 100) }; xhr.onerror = function () { console.log(xhr.status); return; }; xhr.onload = function () { let json; if (xhr.status < 200 || xhr.status >= 300) { console.log('HTTP 错误: ' + xhr.status); return; } json = JSON.parse(xhr.responseText); console.log(json) //接口返回的文件保存地址 let mediaLocation=json.location; //cb()回调函数,将mediaLocation显示在弹框输入框中 cb(mediaLocation, { title: file.name }); }; formData = new FormData(); //假设接口接收参数为file,值为选中的文件 formData.append('file', file); //正式使用将下面被注释的内容恢复 xhr.send(formData); } //触发点击 input.click(); } } });个人博客 > 欢迎来访