vue项目wangEditor实现本地视频上传功能
相信大家写过前端的做用过富文本插件,在这里我就是要说的是富文本插件中的WangEditor富文本插件,此插件源码是不支持上传本地视频的,上传的都是一个远程视频链接。
这里就是要实现上传本地视频的功能
友情链接:wangEditor
实现后的效果
实现前:
实现后:
下载wangeditor
我个人比较喜欢使用yarn下载依赖,感觉比npm要快一点(个人爱好)
yarn add wangeditor
下载完成之后编写公共组件以便其他地方去调用
<template lang="html">
<div class="editor">
<div ref="toolbar" class="toolbar">
</div>
<div ref="editor" class="text">
</div>
</div>
</template>
<script>
import E from 'wangeditor'
export default {
name: 'editoritem',
data() {
return {
// uploadPath,
editor: null,
info_: null
}
},
model: {
prop: 'value',
event: 'change'
},
props: {
value: {
type: String,
default: ''
},
isClear: {
type: Boolean,
default: false
}
},
watch: {
isClear(val) {
// 触发清除文本域内容
if (val) {
this.editor.txt.clear()
this.info_ = null
}
},
value: function(value) {
if (value !== this.editor.txt.html()) {
this.editor.txt.html(this.value)
}
}
//value为编辑框输入的内容,这里我监听了一下值,当父组件调用得时候,如果给value赋值了,子组件将会显示父组件赋给的值
},
mounted() {
this.seteditor()
this.editor.txt.html(this.value)
},
methods: {
seteditor() {
// http://192.168.2.125:8080/admin/storage/create
this.editor = new E(this.$refs.toolbar, this.$refs.editor)
this.editor.customConfig.uploadImgShowBase64 = false // base 64 存储图片
this.editor.customConfig.uploadImgServer = ''// 配置服务器端地址
this.editor.customConfig.uploadImgHeaders = { }// 自定义 header
this.editor.customConfig.uploadFileName = 'file' // 后端接受上传文件的参数名
this.editor.customConfig.uploadImgMaxSize = 2 * 1024 * 1024 // 将图片大小限制为 2M
this.editor.customConfig.uploadImgMaxLength = 6 // 限制一次最多上传 3 张图片
this.editor.customConfig.uploadImgTimeout = 3 * 60 * 1000 // 设置超时时间
// 配置菜单
this.editor.customConfig.menus = [
'head', // 标题
'bold', // 粗体
'fontSize', // 字号
'fontName', // 字体
'italic', // 斜体
'underline', // 下划线
'strikeThrough', // 删除线
'foreColor', // 文字颜色
'backColor', // 背景颜色
'link', // 插入链接
'list', // 列表
'justify', // 对齐方式
'quote', // 引用
'emoticon', // 表情
'image', // 插入图片
'table', // 表格
'video', // 插入视频
'code', // 插入代码
'undo', // 撤销
'redo', // 重复
'fullscreen' // 全屏
]
this.editor.customConfig.uploadImgHooks = {
fail: (xhr, editor, result) => {
// 插入图片失败回调
},
success: (xhr, editor, result) => {
// 图片上传成功回调
},
timeout: (xhr, editor) => {
// 网络超时的回调
},
error: (xhr, editor) => {
// 图片上传错误的回调
},
customInsert: (insertImg, result, editor) => {
// 图片上传成功,插入图片的回调
//result为上传图片成功的时候返回的数据,这里我打印了一下发现后台返回的是data:[{url:"路径的形式"},...]
// console.log(result.data[0].url)
//insertImg()为插入图片的函数
//循环插入图片
// for (let i = 0; i < 1; i++) {
// console.log(result)
let url = "http://otp.cdinfotech.top"+result.url
insertImg(url)
// }
}
}
this.editor.customConfig.onchange = (html) => {
this.info_ = html // 绑定当前逐渐地值
this.$emit('change', this.info_) // 将内容同步到父组件中
}
// 创建富文本编辑器
this.editor.create()
}
}
}
</script>
<style lang="css">
.editor {
width: 100%;
margin: 0 auto;
position: relative;
z-index: 0;
}
.toolbar {
border: 1px solid #ccc;
}
.text {
border: 1px solid #ccc;
min-height: 500px;
}
</style>
然后就可以在页面中直接调用
<template>
<div>
<editor-bar v-model="detail" :isClear="isClear" @change="change"></editor-bar>
</div>
</template>
import EditorBar from './editoritem'
components: { EditorBar },
data() {
return {
isClear: false,
detail:""
}
},
methods: {
change(val) {
console.log(val)
},
}
到这里,一个简单的wangeditor的例子就实现了,但是这里是自定义了文件的上传,视频的上传只是一个ifream,然后放进一个远程的视频链接。但是一般的需求都是需要上传本地的视频文件,那么我们就需要去修改源码使其实现我们的功能。
修改源码使其满足上传视频的需求
修改源码wangEditor.js文件
找到对应的上传视频的构造修改如下:
// 构造函数
function Video(editor) {
this.editor = editor;
this.$elem = $('<div class="w-e-menu"><i class="w-e-icon-play"></i></div>');
this.type = 'panel';
// 当前是否 active 状态
this._active = false;
}
// 原型
Video.prototype = {
constructor: Video,onClick: function onClick() {
this._createPanel();
},
_createPanel: function _createPanel() {
var _this = this;
var editor = this.editor;
var uploadImg = editor.uploadImg;
var config = editor.config;// 创建 id
// 上传视频id
var upTriggerVideoId = getRandom('up-trigger-video');
var upFileVideoId = getRandom('up-file-video');
// 插入视频id
var textValId = getRandom('text-val');
var btnId = getRandom('btn');// tabs 的配置
var tabsConfig = [{
title: '上传视频',
tpl: '<div class="w-e-up-img-container"><div id="' + upTriggerVideoId + '" class="w-e-up-btn"><i class="w-e-icon-upload2"></i></div><div style="display:none;"><input id="' + upFileVideoId + '" type="file" multiple="multiple" accept="application/pdf,video/*"/></div></div>',
events: [{
// 触发选择图片selector: '#' + upTriggerVideoId,
type: 'click',
fn: function fn() {
var $file = $('#' + upFileVideoId);
var fileElem = $file[0];
if (fileElem) {
fileElem.click();
} else {
// 返回 true 可关闭 panel
return true;
}
}
}, {// 选择图片完毕
selector: '#' + upFileVideoId,
type: 'change',
fn: function fn() {
var $file = $('#' + upFileVideoId);
var fileElem = $file[0];
if (!fileElem) {
// 返回 true 可关闭 panel
return true;
}// 获取选中的 file 对象列表
var fileList = fileElem.files;
if (fileList.length) {
console.log(fileList);
uploadImg.uploadVideo(fileList);
}
// 返回 true 可关闭 panel
return true;
}
}]
}, // first tab end
{// 标题
title: '网络视频',
// 模板
tpl: '<div><input id="' + textValId + '" type="text" class="block" placeholder="\u683C\u5F0F\u5982\uFF1A<iframe src=... ></iframe>"/><div class="w-e-button-container"><button id="' + btnId + '" class="right">\u63D2\u5165</button></div></div>',
// 事件绑定
events: [{selector: '#' + btnId,
type: 'click',
fn: function fn() {
var $text = $('#' + textValId);
var val = $text.val().trim();
if (val) _this._insert(val); // 插入视频
// 返回 true,表示该事件执行完之后,panel 要关闭。否则 panel 不会关闭
return true;
}
}]} // second tab end
]; // tabs end
// 判断 tabs 的显示
var tabsConfigResult = [];
if (config.uploadVideoServer) {
// 显示“上传视频”
tabsConfigResult.push(tabsConfig[0]);
}if (config.showLinkVideo) {
// 显示“网络视频”
tabsConfigResult.push(tabsConfig[1]);
}
// 创建 panel
var panel = new Panel(this, {
width: 350,
// 一个 panel 多个 tab
tabs: tabsConfigResult // tabs end
}); // panel end// 显示 panel
panel.show();
// 记录属性
this.panel = panel;
},
// 插入视频
_insert: function _insert(val) {
var editor = this.editor;
editor.cmd.do('insertHTML', val + '<p><br></p>');
}
};
在配置中修改上传视频的返回和配置项:
// 根据链接插入视频
insertLinkVideo: function insertLinkVideo(link) {
if (!link) return;
var _this2 = this;
var editor = this.editor;
var config = editor.config;// 校验格式
var linkVideoCheck = config.linkVideoCheck;
var checkResult = void 0;
if (linkVideoCheck && typeof linkVideoCheck === 'function') {
checkResult = linkVideoCheck(link);
if (typeof checkResult === 'string') {
// 校验失败,提示信息
alert(checkResult);
return;
}
} editor.cmd.do('insertHTML', '<iframe src="' + link + '" class="video-iframe" frameborder="0"></iframe>');
},
//上传视频--------------------------------------------------------------------
uploadVideo: function uploadVideo(files) {
var _this3 = this;
if (!files || !files.length) {
return;
}// ------------------------------ 获取配置信息 ------------------------------
var editor = this.editor;
var config = editor.config;
var uploadVideoServer = config.uploadVideoServer;
var uploadToken = config.uploadToken;var maxSize = config.uploadVideoMaxSize;
var maxSizeM = maxSize / 1024 / 1024;
var maxLength = config.uploadVideoMaxLength || 10000;
var uploadFileName = config.uploadFileName || '';
var uploadVideoParams = config.uploadVideoParams || {};var uploadVideoParamsWithUrl = config.uploadVideoParamsWithUrl;
var uploadVideoHeaders = config.uploadVideoHeaders || {};
var hooks = config.uploadVideoHooks || {};
var timeout = config.uploadVideoTimeout || 30 * 60 * 1000; // 30分钟
var withCredentials = config.withCredentials;
if (withCredentials == null) {
withCredentials = false;}
var customUploadVideo = config.customUploadVideo;
if (!customUploadVideo) {
// 没有 customUploadVideo 的情况下,需要如下两个配置才能继续进行图片上传
if (!uploadVideoServer) {
return;
}
}// ------------------------------ 验证文件信息 ------------------------------
var resultFiles = [];
var errInfo = [];
arrForEach(files, function (file) {
var name = file.name;
var size = file.size;
// chrome 低版本 name === undefined
if (!name || !size) {return;
}
if (/\.(pdf|rm|rmvb|3gp|avi|mpeg|mpg|mkv|dat|asf|wmv|flv|mov|mp4|ogg|ogm)$/i.test(name) === false) {
// 后缀名不合法,不是视频
errInfo.push('\u3010' + name + '\u3011\u4E0D\u662F\u56FE\u7247');
return;
}if (maxSize < size) {
// 上传视频过大
errInfo.push('\u3010' + name + '\u3011\u5927\u4E8E ' + maxSizeM + 'M');
return;
}
// 验证通过的加入结果列表
resultFiles.push(file);
});// 抛出验证信息
if (errInfo.length) {
this._alert('视频验证未通过: \n' + errInfo.join('\n'));
return;
}
if (resultFiles.length > maxLength) {
this._alert('一次最多上传' + maxLength + '个视频');
return;
}// ------------------------------ 自定义上传 ------------------------------
if (customUploadVideo && typeof customUploadVideo === 'function') {
customUploadVideo(resultFiles, this.insertLinkVideo.bind(this));
// 阻止以下代码执行
return;
}
然后在公共组件中加入上传视频的配置
//上传视频配置
this.editor.customConfig.uploadVideoHeaders = {token}
this.editor.customConfig.uploadVideoServer = '/api/wx/news/upload'; // 上传接口
this.editor.customConfig.uploadVideoHooks = { // 上传完成处理方法customInsert: function (insertVideo, result) {
if (result.code == 200) {
let url = result.data.fileloadpath+result.data.url
insertVideo(url);
} else {
_this.$message.error(result.msg);
}
}
};
到此为止上传视频的功能就写好了,接下来需要将项目重新启动再去访问就会发现我们的上传视频已经修改成我们需要的样式了
将修改后的源码上传发布到npm中
由于我们是在wangeditor中直接修改的代码,这里的代码都在我们的包mode_modules中,这样的话项目打包发布后就不行了,所以我们需要将我们修改的插件发布到npm中,然后下载到项目中,这样打包就是我们修改后的插件了。
-
在npm中注册账号,千万记住,注册好后需要进行邮箱验证,否则上传时会报错。(我自己遇到的坑)
-
注册完毕后在本地创建一个文件夹然后将我们的之前修改的文件包括css文件,这五个文件放到我们创建的文件夹里面![在这里插入图片描述](https://img-blog.csdnimg.cn/2020122420500873.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hdGFvZVodG1s,size_16,color_FFFFFF,t_70#pic_center
3.然后在命令行中分别执行
npm login
Username:用户名
Password:密码
Email:注册时的邮箱
npm init
初始化包,一次写入对应的包配置
package name: 包名字
version: (1.0.0): 包的版本
description: 描述
entry point: (wangEditor.js)项目入口。这里我们直接到js文件接口
test command:测试命令
git repository: git仓库
keywords:关键字
author:作者
license:令牌 (默认即可)
然后回车即可
npm publish
最后一步 发布 发布成功后会在你的npm主页看到自己上传的,如果有报错,请注意:(1)是否进行了邮箱验证(2)包名可能会冲突
在npm中下载修改后的代码到项目中使用
直接在vue项目中下载刚刚我们上传的依赖包,yarn add …
然后就可以直接使用了!真棒。。。
我的npm链接
我自己封装的依赖包makereditor或者zhangeditor(别人的)
直接下载即可使用:
yarn add makereditor
yarn add zhangeditor 亲测都可使用