vue+element-ui使用 tinymce富文本编辑器步骤(上传图片+上传本地视频)以及遇到的一些bug
vue+element-ui使用 tinymce富文本编辑器步骤以及遇到的一些bug前言最近接触前端,发现富文本使用频率比较高,在网上找了很多种方法也看了很多资料,现在来总结最近新使用的富文本编辑器tinymce(tinymce的介绍大家可以百度哈~)tinymce的中文官网:tinymce的中文官网前端项目都基于vue来开发的(本人是前端新手,如有不对地方,还请各位大佬指点)以前用的都是vue-
vue+element-ui使用 tinymce富文本编辑器步骤(上传图片+上传本地视频)以及遇到的一些bug
前言
最近接触前端,发现富文本使用频率比较高,在网上找了很多种方法也看了很多资料,现在来总结最近新使用的富文本编辑器tinymce(tinymce的介绍大家可以百度哈~)
tinymce的中文官网:tinymce的中文官网
前端项目都基于vue来开发的(本人是前端新手,如有不对地方,还请各位大佬指点)
以前用的都是vue-quill-editor富文本插件, 这个插件还不错,是vue自带的,比较轻巧,适用于功能不是很大,简单的富文本编辑器,等有时间再写一篇vue-quill-editor的使用心得,啰嗦这么久,进入正题啦~~(这是一篇很详细的教程,一步一步来一点都不难)
使用方法:
- 下载插件:
npm install tinymce -S
- 安装之后,在 node_modules 中找到 tinymce/skins 目录,然后将 skins 目录拷贝到 static 目录下
但是我是使用 vue-cli 3.x 构建的 typescript 项目,所以就放到 public 目录下
- 新建一个根目录tinymce,因为tinymce 默认是英文界面,所以还需要下载一个中文语言包 也放到tinymce目录下
图片展示:
- 初始化数据
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'
上传图片+本地视频的是
tinymce-vue 是一个组件,需要在 components 中注册,然后直接使用
注册组件:
<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
更多推荐
所有评论(0)