最近接触前端,发现富文本使用频率比较高,在网上找了很多种方法也看了很多资料,现在来总结最近新使用的富文本编辑器tinymce(tinymce的介绍大家可以百度哈~) tinymce的中文官网:tinymce的中文官网
前端项目都基于vue来开发的(本人是前端新手,如有不对地方,还请各位大佬指点)
图片展示:
初始化数据 import tinymce from 'tinymce/tinymce' import 'tinymce/themes/modern/theme' import Editor from '@tinymce/tinymce-vue'如果找不到 import 'tinymce/themes/modern/theme' 可以替换成 import 'tinymce/themes/silver/theme'
注册组件:
<template> <div class="myEditor"> <div class="tinymce-editor-wrapper"> <editor v-model="content" :disabled="disabled" :init="options" initial-value="请输入内容..." /> </div> </div> </template> <script> import tinymce from 'tinymce/tinymce' import Editor from '@tinymce/tinymce-vue' import 'tinymce/themes/silver' //引入图片上传服务器的接口 import { uploadOss } from "@/api/system/oss"; // 引入编辑器插件plugins import 'tinymce/plugins/advlist' import 'tinymce/plugins/autolink' import 'tinymce/plugins/lists' import 'tinymce/plugins/link' import 'tinymce/plugins/image' import 'tinymce/plugins/charmap' import 'tinymce/plugins/print' import 'tinymce/plugins/preview' import 'tinymce/plugins/anchor' import 'tinymce/plugins/searchreplace' import 'tinymce/plugins/visualblocks' import 'tinymce/plugins/fullscreen' import 'tinymce/plugins/insertdatetime' import 'tinymce/plugins/media' import 'tinymce/plugins/table' //引入工具栏图标 import 'tinymce/icons/default' // 自定义工具栏 const toolbar = 'undo redo | insert | styleselect | fontselect bold italic forecolor backcolor | alignleft aligncenter alignright | outdent indent | link image media | fullscreen' // 引入插件 const plugins = [ 'advlist autolink lists link image charmap print preview anchor', 'searchreplace visualblocks fullscreen', 'insertdatetime media table' ] // 字体 const fonts = 'Andale Mono=andale mono,times; Arial=arial,helvetica,sans-serif; 黑体=arial black,avant garde; Book Antiqua=book antiqua,palatino; Comic Sans MS=comic sans ms,sans-serif; Courier New=courier new,courier; Georgia=georgia,palatino; Helvetica=helvetica; Impact=impact,chicago; Symbol=symbol; 宋体=tahoma,arial,helvetica,sans-serif; Terminal=terminal,monaco; Times New Roman=times new roman,times; Trebuchet MS=trebuchet ms,geneva; Verdana=verdana,geneva; Webdings=webdings; Wingdings=wingdings,zapf dingbats' export default { components: { Editor }, props: { value: { type: String, default: '' }, disabled: { type: Boolean, default: false } }, data() { return { content: this.value, options: { language_url: '/tinymce/zh_CN.js', // 语言包的路径 language: 'zh_CN', // 语言 skin_url: '/tinymce/skins/ui/oxide', // 浅色 plugins: plugins, // 插件 toolbar: toolbar, // 工具栏 font_formats: fonts, // 字体 height: 900, // 编辑器高度 branding: false, // 是否禁用“Powered by TinyMCE” menubar: true, // 顶部菜单栏显示 resVideo:'', //上传视频的url uploaded:false,//有没有上传完成 file_picker_types: 'media', images_upload_handler: (blobInfo, success, failure) => { this.handleImageAdded(blobInfo, success, failure) }, //be used to add custom file picker to those dialogs that have it. file_picker_callback: (callback, value, meta) => { this.open(callback, value, meta) } } } }, watch: { value(val) { //父子组建双向绑定 this.content = val }, content(val) { this.$emit('input', val) } }, mounted() { tinymce.init({}) }, created() { }, methods: { open(callback, value, meta){ if (meta.filetype == 'media') { let input = document.createElement('input');//创建一个隐藏的input input.setAttribute('type', 'file'); let that = this; input.onchange = function(){ let file = this.files[0];//选取第一个文件 that.uploadVideo(file,'media'); // 上传视频拿到url console.log('dongbug',that.options.uploaded) setTimeout(()=>{ if(that.options.uploaded){ console.log(that.resVideo,'true') callback(that.resVideo) //将url显示在弹框输入框中 }else{ setTimeout(()=>{ //设置几秒后再去取数据 console.log(that.resVideo,'false') callback(this.resVideo) },5000) } },5000) } //触发点击 input.click(); } }, // 插入视频的方法 uploadVideo(file,type){ const formdate = new FormData() formdate.set('file',file) console.log(formdate) uploadOss(formdate).then(response =>{ if (response.code == 200) { if(type == 'media') { this.resVideo = response.url this.options.uploaded = true } console.log('dsdsdoooooooo', this.options.uploaded) } }) }, // 插入图片的方法 handleImageAdded(blobInfo, success, failure) { console.log('图片',blobInfo.blob()) let file = blobInfo.blob() const isLt8M = file.size / 1024 / 1024 < 20 if (!isLt8M) { this.$message.error('图片大小不能超过 20MB!') return } const formdate = new FormData() formdate.set('file',blobInfo.blob()) console.log('图片',formdate) uploadOss(formdate).then(response =>{ if (response.code == 200) { let url = response.url success(url) } else { failure(response.message) this.$message.error(response.message) } }) }, async info() { //回显内容 console.log(this.mubanId) let { data } = await getDetail({ templateId: this.mubanId }) this.content = data } } } </script> <style lang="scss" scoped></style> <style> .tox-silver-sink { z-index: 13000 !important; } </style>引入组件:(根据自己存放组件的路径来哦)
import TinymceEditor from '@/components/Tinymce/index'注册组件:
components: {TinymceEditor },使用组件:
<tinymce-editor v-model="form.tables" v-if="open" />说一下v-if=“open ”这块 因为我的富文本使用在弹出框,每次一点击修改就会显示和上传一样的内容,而且不可以修改 原因是因为弹窗是父组件,富文本是子组件,弹窗关闭的时候子组件没有触发销毁钩子函数,既然没有销毁,那么第二次打开弹窗的时候也就不会再次初始化,所以父组件的弹窗每次打开关闭、打开关闭,显示都是第一次的富文本内容。 解决方法: 所以要在使用富文本组件上加上v-if,使子组件随弹窗关闭进行销毁,随弹窗的打开,进行初始化
代码如下:
<el-dialog :title="title" :visible.sync="open" width="1000px" append-to-body> <el-form ref="form" :model="form" :rules="rules" label-width="80px"> <el-form-item label="内容" prop="tables"> <tinymce-editor v-model="form.tables" v-if="open" /> </el-form-item> </el-form> </el-dialog >还有遇到一种情况,富文本会出现这种情况: 工具栏的icon都显示not found 解决方法: 在tinymce组件中引入这段代码:import 'tinymce/icons/default' 就可以啦~
还有个问题是图片的上传:(图片上传的方法) inymce 提供了 images_upload_url等 api 让用户配置上传图片的相关参数 images_upload_handler 自定义一个上传方法
这个方法会提供三个参数:blobInfo, success, failure 其中 blobinfo 是一个对象,包含上传文件的信息: success和failure 是函数,上传成功的时候向 success 传入一个图片地址,失败的时候向 failure 传入报错信息
有了图片上传就少不了视频上传(编辑器一开始是没有本地视频上传的按钮,只有填写视频url) 需要引入对应的插件media
import 'tinymce/plugins/media' const toolbar = 'undo redo | insert | styleselect | fontselect bold italic forecolor backcolor | alignleft aligncenter alignright | outdent indent | link image media | fullscreen' // 引入插件 const plugins = [ 'advlist autolink lists link image charmap print preview anchor', 'searchreplace visualblocks fullscreen', 'insertdatetime media table' ]在data加上这四行
resVideo:'', //上传视频的url uploaded:false,//有没有上传完成 file_picker_types: 'media', file_picker_callback: (callback, value, meta) => { this.open(callback, value, meta) }this.open是上传视频的方法(返回三个参数) 注意这一块 如果不加定时器,上传视频返回的uploaded会延迟,所以就会进入判断的else方法,url就不会显示到input框中
这些都设置完成后就会出现一个可以的上传本地文件的图标(同理也可以上传图片和文件) 但是预览效果为图片,不能预览
找到tinymce的原文件下的media>plugin.js文件 找到下面源码、注释掉
第二步:创建一个全局变量来存video的src
第三步:判断video标签 获取src值赋值给videoSource(写在注释的那一段代码那里):
if(node.name === 'video' && hasLiveEmbeds(editor) && global$8.ceFalse){ console.log('videoSource===', videoSource) videoSource = '' if(node.attributes['map'] && node.attributes['map'].src){ videoSource = node.attributes['map'].src }else{ for(var ii=0;ii<node.attributes.length;ii++){ if(node.attributes[ii].name == "src"){ videoSource = node.map.node.attributes[ii].value } } } if(node.firstChild && node.firstChild.value){ var elel=node.firstChild && node.firstChild.value var objE = document.createElement("div"); objE.innerHTML = elel; var dom = objE.getElementsByTagName('source')[0] videoSource = dom.getAttribute('src') } node.replace(createPreviewIframeNode(editor, node)); }第四步:在createPreviewIframeNode 方法中有两处修改:修改previewNode.attr中src:videoSource || node.attr(‘src’), 增加播放属性controls: ‘controls’。
var createPreviewIframeNode = function (editor, node) { var previewWrapper; var previewNode; var shimNode; var name = node.name; previewWrapper = new global$7('span', 1); previewWrapper.attr({ 'contentEditable': 'false', 'style': node.attr('style'), 'data-mce-object': name, 'class': 'mce-preview-object mce-object-' + name }); retainAttributesAndInnerHtml(editor, node, previewWrapper); previewNode = new global$7(name, 1); previewNode.attr({ src: videoSource || node.attr('src'), // 修改 controls: 'controls', // 新增 allowfullscreen: node.attr('allowfullscreen'), style: node.attr('style'), class: node.attr('class'), width: node.attr('width'), height: node.attr('height'), frameborder: '0' }); shimNode = new global$7('span', 1); shimNode.attr('class', 'mce-shim'); previewWrapper.append(previewNode); previewWrapper.append(shimNode); return previewWrapper; };这样就可以正常显示了:
好了tinymce富文本的使用就写到这,如有不足,欢迎补充~~~
思路来源:参考链接,https://www.cnblogs.com/wisewrong/p/8985471.html 视频上传思路来源:https://blog.csdn.net/web_527965583_ld/article/details/107299416