Jeecg富文本编辑器上传视频无法预览解决
jeecg使用的富文本编辑器是:tinyMCE富文本编辑器
tinyMCE中文文档:http://tinymce.ax-z.cn/
参考:
https://blog.csdn.net/QQ_Empire/article/details/107846057
https://blog.csdn.net/Sarahhoney12_/article/details/85629014
问题: 视频上传成功后,无法预览,通过查看标签元素发现video标签设置错误,内容为:
%0A%3Csource%20src%3D%22http%3A//192.168.1.107%3A8008/alliaceUniversity/sys/common/static/6-v_1634784386454.mp4%22%20type%3D%22video/mp4%22%20/%3E
可以播放的正确标签为:
<video width="100%" height="auto" src="http://192.168.1.107:8008/alliaceUniversity/sys/common/static/6-WhatIfIWanttoMoveFaster_1634720194226.mp4" controls="controls"></video>
解决前
解决后可以正常播放
解决思路:在视频上传成功后需要回显到富文本编辑器时,手动修改视频的标签然后回显到富文本编辑器。
media_url_resolver: function (data, resolve) {
console.log('media_url_resolver', data)
try {
let videoUri = encodeURI(data.url);
let embedHtml = `<p>
<span
class="mce-object mce-object-video"
data-mce-selected="1"
data-mce-object="video"
data-mce-p-width="100%"
data-mce-p-height="auto"
data-mce-p-controls="controls"
data-mce-p-controlslist="nodownload"
data-mce-p-allowfullscreen="true"
data-mce-p-src=${videoUri} >
<video src=${data.url} width="100%" height="auto" controls="controls" controlslist="nodownload">
</video>
</span>
</p>
<p style="text-align: left;"></p>`;
resolve({ html: embedHtml });
} catch (e) {
resolve({ html: "" });
}
},
完整代码
Jeditor.vue
<template>
<div class="tinymce-editor">
<editor
v-if="!reloading"
v-model="myValue"
:init="init"
:disabled="disabled"
@onClick="onClick">
</editor>
</div>
</template>
<script>
import Vue from 'vue'
import { ACCESS_TOKEN } from "@/store/mutation-types"
import tinymce from 'tinymce/tinymce'
import Editor from '@tinymce/tinymce-vue'
import 'tinymce/themes/silver/theme'
import 'tinymce/plugins/image'
import 'tinymce/plugins/link'
import 'tinymce/plugins/media'
import 'tinymce/plugins/table'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/contextmenu'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/colorpicker'
import 'tinymce/plugins/textcolor'
import 'tinymce/plugins/fullscreen'
import 'tinymce/icons/default'
import {uploadAction, getFileAccessHttpUrl} from '@/api/manage'
import {getVmParentByName} from '@/utils/util'
export default {
components: {
Editor
},
props: {
value: {
type: String,
required: false
},
triggerChange: {
type: Boolean,
default: false,
required: false
},
disabled: {
type: Boolean,
default: false
},
plugins: {
type: [String, Array],
default: 'lists image link media table textcolor wordcount contextmenu fullscreen'
},
toolbar: {
type: [String, Array],
default: 'undo redo | formatselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | lists link unlink image media table | removeformat | fullscreen',
branding: false
}
},
data() {
return {
//初始化配置
init: {
language_url: '/tinymce/langs/zh_CN.js',
language: 'zh_CN',
skin_url: '/tinymce/skins/lightgray',
height: 300,
plugins: this.plugins,
toolbar: this.toolbar,
branding: false,
menubar: false,
toolbar_drawer: false,
file_picker_types: 'media',
//视频上传
file_picker_callback: function (cb, value, meta) {
//当点击meidia图标上传时,判断meta.filetype == 'media'有必要,因为file_picker_callback是media(媒体)、image(图片)、file(文件)的共同入口
if (meta.filetype == 'media') {
//创建一个隐藏的type=file的文件选择input
let input = document.createElement('input');
const token = Vue.ls.get(ACCESS_TOKEN)
input.setAttribute('type', 'file');
input.onchange = function () {
let file = this.files[0];//只选取第一个文件。如果要选取全部,后面注意做修改
let xhr, formData;
xhr = new XMLHttpRequest();
xhr.open('POST', window._CONFIG['domianURL'] + "/sys/common/upload");
if(token) {
xhr.setRequestHeader("X-Access-Token", token)
}
xhr.withCredentials = self.credentials;
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);
//假设接口返回JSON数据为{status: 0, msg: "上传成功", data: {location: "/localImgs/1546434503854.mp4"}}
console.log("***********")
console.log(json)
console.log("***********")
if (json.code == 0) {
//接口返回的文件保存地址
console.log("*******************")
let mediaLocation = getFileAccessHttpUrl(json.message);
console.log(getFileAccessHttpUrl(json.message));
console.log("*******************")
//cb()回调函数,将mediaLocation显示在弹框输入框中
cb(mediaLocation, {title: file.name});
} else {
console.log(json.msg);
return;
}
};
formData = new FormData();
//假设接口接收参数为file,值为选中的文件
formData.append('file', file);
//正式使用将下面被注释的内容恢复
xhr.send(formData);
}
//触发点击
input.click();
}
},
media_url_resolver: function (data, resolve) {
console.log('media_url_resolver', data)
try {
let videoUri = encodeURI(data.url);
let embedHtml = `<p>
<span
class="mce-object mce-object-video"
data-mce-selected="1"
data-mce-object="video"
data-mce-p-width="100%"
data-mce-p-height="auto"
data-mce-p-controls="controls"
data-mce-p-controlslist="nodownload"
data-mce-p-allowfullscreen="true"
data-mce-p-src=${videoUri} >
<video src=${data.url} width="100%" height="auto" controls="controls" controlslist="nodownload">
</video>
</span>
</p>
<p style="text-align: left;"></p>`;
resolve({ html: embedHtml });
} catch (e) {
resolve({ html: "" });
}
},
images_upload_handler: (blobInfo, success) => {
let formData = new FormData()
formData.append('file', blobInfo.blob(), blobInfo.filename());
formData.append('biz', "jeditor");
formData.append("jeditor", "1");
uploadAction(window._CONFIG['domianURL'] + "/sys/common/upload", formData).then((res) => {
if (res.success) {
if (res.message == 'local') {
const img = 'data:image/jpeg;base64,' + blobInfo.base64()
success(img)
} else {
let img = getFileAccessHttpUrl(res.message)
success(img)
}
}
})
}
},
myValue: this.value,
reloading: false,
}
},
mounted() {
this.initATabsChangeAutoReload()
},
methods: {
reload() {
this.reloading = true
this.$nextTick(() => this.reloading = false)
},
onClick(e) {
this.$emit('onClick', e, tinymce)
},
//可以添加一些自己的自定义事件,如清空内容
clear() {
this.myValue = ''
},
/**
* 自动判断父级是否是 <a-tabs/> 组件,然后添加事件监听,自动触发reload()
*
* 由于 tabs 组件切换会导致 tinymce 无法输入,
* 只有重新加载才能使用(无论是vue版的还是jQuery版tinymce都有这个通病)
*/
initATabsChangeAutoReload() {
// 获取父级
let tabs = getVmParentByName(this, 'ATabs')
let tabPane = getVmParentByName(this, 'ATabPane')
if (tabs && tabPane) {
// 用户自定义的 key
let currentKey = tabPane.$vnode.key
// 添加事件监听
tabs.$on('change', (key) => {
// 切换到自己时执行reload
if (currentKey === key) {
this.reload()
}
})
//update--begin--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------
this.reload()
//update--end--autor:liusq-----date:20210316------for:富文本编辑器tab父组件可能导致的赋值问题------
} else {
//update--begin--autor:wangshuai-----date:20200724------for:富文本编辑器切换tab无法修改------
let tabLayout = getVmParentByName(this, 'TabLayout')
tabLayout.excuteCallback(() => {
this.reload()
})
//update--begin--autor:wangshuai-----date:20200724------for:文本编辑器切换tab无法修改------
}
},
},
watch: {
value(newValue) {
this.myValue = (newValue == null ? '' : newValue)
},
myValue(newValue) {
if (this.triggerChange) {
this.$emit('change', newValue)
} else {
this.$emit('input', newValue)
}
}
}
}
</script>
<style scoped>
</style>