一、實現效果
實現效果
原本效果
二、源碼
下面是wangEditor實現插入視頻的代碼
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;
// 創建 id
var textValId = getRandom('text-val');
var btnId = getRandom('btn');
// 創建 panel
var panel = new Panel(this, {
width: 350,
// 一個 panel 多個 tab
tabs: [{
// 標題
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;
}
}]
}] // 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>');
}
};
復制代碼
三、實現
看完源碼之后發現挺簡單, 在創建panel的時候添加一個插入視頻的panel,完事再實現一個視頻上傳、插入編輯器就完事了,參考一下文件上傳代碼。
1. 添加插入視頻panel
修改Video.prototype._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: '上傳視頻或pdf',
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;
}
復制代碼
2. 實現文件上傳
圖片上傳在UploadImg中uploadImg方法中實現,參考一下,在UploadImg中添加一個uploadVideo方法。
// 上傳視頻
UploadImg.prototype.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 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;
}
// 添加圖片數據
var formdata = new FormData();
arrForEach(resultFiles, function (file) {
var name = uploadFileName || file.name;
formdata.append(name, file);
});
// ------------------------------ 上傳圖片 ------------------------------
if (uploadVideoServer && typeof uploadVideoServer === 'string') {
// 添加參數
var uploadVideoServerArr = uploadVideoServer.split('#');
uploadVideoServer = uploadVideoServerArr[0];
var uploadVideoServerHash = uploadVideoServerArr[1] || '';
objForEach(uploadVideoParams, function (key, val) {
// 因使用者反應,自定義參數不能默認 encode ,由 v3.1.1 版本開始注釋掉
// val = encodeURIComponent(val)
// 第一,將參數拼接到 url 中
if (uploadVideoParamsWithUrl) {
if (uploadVideoServer.indexOf('?') > 0) {
uploadVideoServer += '&';
} else {
uploadVideoServer += '?';
}
uploadVideoServer = uploadVideoServer + key + '=' + val;
}
// 第二,將參數添加到 formdata 中
formdata.append(key, val);
});
if (uploadVideoServerHash) {
uploadVideoServer += '#' + uploadVideoServerHash;
}
// 定義 xhr
var xhr = new XMLHttpRequest();
xhr.open('POST', uploadVideoServer);
// 設置超時
xhr.timeout = timeout;
xhr.ontimeout = function () {
// hook - timeout
if (hooks.timeout && typeof hooks.timeout === 'function') {
hooks.timeout(xhr, editor);
}
_this3._alert('上傳視頻超時');
};
// 監控 progress
if (xhr.upload) {
xhr.upload.onprogress = function (e) {
var percent = void 0;
// 進度條
var progressBar = new Progress(editor);
if (e.lengthComputable) {
percent = e.loaded / e.total;
progressBar.show(percent);
}
};
}
// 返回數據
xhr.onreadystatechange = function () {
var result = void 0;
if (xhr.readyState === 4) {
if (xhr.status < 200 || xhr.status >= 300) {
// hook - error
if (hooks.error && typeof hooks.error === 'function') {
hooks.error(xhr, editor);
}
// xhr 返回狀態錯誤
_this3._alert('上傳視頻發生錯誤', '\u4E0A\u4F20\u56FE\u7247\u53D1\u751F\u9519\u8BEF\uFF0C\u670D\u52A1\u5668\u8FD4\u56DE\u72B6\u6001\u662F ' + xhr.status);
return;
}
result = xhr.responseText;
if ((typeof result === 'undefined' ? 'undefined' : _typeof(result)) !== 'object') {
try {
result = JSON.parse(result);
} catch (ex) {
// hook - fail
if (hooks.fail && typeof hooks.fail === 'function') {
hooks.fail(xhr, editor, result);
}
_this3._alert('上傳視頻失敗', '上傳視頻返回結果錯誤,返回結果是: ' + result);
return;
}
}
if (!hooks.customInsert && result.errno != '0') {
// hook - fail
if (hooks.fail && typeof hooks.fail === 'function') {
hooks.fail(xhr, editor, result);
}
// 數據錯誤
_this3._alert('上傳視頻失敗', '上傳視頻返回結果錯誤,返回結果 errno=' + result.errno);
} else {
if (hooks.customInsert && typeof hooks.customInsert === 'function') {
// 使用者自定義插入方法
hooks.customInsert(_this3.insertLinkVideo.bind(_this3), result, editor);
} else {
// 將圖片插入編輯器
var data = result.data || [];
data.forEach(function (link) {
_this3.insertLinkVideo(link);
});
}
// hook - success
if (hooks.success && typeof hooks.success === 'function') {
hooks.success(xhr, editor, result);
}
}
}
};
// hook - before
if (hooks.before && typeof hooks.before === 'function') {
var beforeResult = hooks.before(xhr, editor, resultFiles);
if (beforeResult && (typeof beforeResult === 'undefined' ? 'undefined' : _typeof(beforeResult)) === 'object') {
if (beforeResult.prevent) {
// 如果返回的結果是 {prevent: true, msg: 'xxxx'} 則表示用戶放棄上傳
this._alert(beforeResult.msg);
return;
}
}
}
// 自定義 headers
objForEach(uploadVideoHeaders, function (key, val) {
xhr.setRequestHeader(key, val);
});
// 跨域傳 cookie
xhr.withCredentials = withCredentials;
// 發送請求
xhr.send(formdata);
}
}
復制代碼
3. 插入編輯器
插入視頻也寫在UploadImg.prototype中
// 根據鏈接插入視頻
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 + '" style="width:650px;height: 366px" frameborder="0"></iframe>');
}
4. 添加視頻上傳的默認參數
在config中添加一些上傳視頻默認參數, 加不加無所謂
// 是否顯示添加網絡視頻的 tab
showLinkVideo: true,
// 插入網絡視頻的回調
linkVideoCallback: function linkVideoCallback(url) {
// console.log(url) // url 即插入視頻的地址
},
// 默認上傳視頻 max size: 512M
uploadVideoMaxSize: 512 * 1024 * 1024,
// 配置一次最多上傳幾個視頻
uploadVideoMaxLength: 5,
// 上傳視頻的自定義參數
uploadVideoParams: {
// token: 'abcdef12345'
},
// 上傳視頻的自定義header
uploadVideoHeaders: {
// 'Accept': 'text/x-json'
},
// 自定義上傳視頻超時時間 30分鍾
uploadVideoTimeout: 30 * 60 * 1000,
// 上傳視頻 hook
uploadVideoHooks: {
// customInsert: function (insertLinkVideo, result, editor) {
// console.log('customInsert')
// // 視頻上傳並返回結果,自定義插入視頻的事件,而不是編輯器自動插入視頻
// const data = result.data1 || []
// data.forEach(link => {
// insertLinkVideo(link)
// })
// },
before: function before(xhr, editor, files) {
// 視頻上傳之前觸發
// 如果返回的結果是 {prevent: true, msg: 'xxxx'} 則表示用戶放棄上傳
// return {
// prevent: true,
// msg: '放棄上傳'
// }
},
success: function success(xhr, editor, result) {
// 視頻上傳並返回結果,視頻插入成功之后觸發
},
fail: function fail(xhr, editor, result) {
// 視頻上傳並返回結果,但視頻插入錯誤時觸發
},
error: function error(xhr, editor) {
// 視頻上傳出錯時觸發
},
timeout: function timeout(xhr, editor) {
// 視頻上傳超時時觸發
}
}
四、使用
初始化編輯器,配置上傳視頻參數
var editor = new window.wangEditor('#text-editor');
// 圖片上傳
editor.customConfig.uploadImgServer = 'upload/editUpload'; // 上傳接口
editor.customConfig.uploadFileName = 'files'; // 上傳文件參數名
editor.customConfig.uploadImgHooks = { // 上傳完成處理方法
customInsert: function (insertImg, result) {
if (result.ret === 200) {
(result.data || '').split(',').forEach(function (link) {
link && insertImg(link);
});
} else {
flavrShowByTime('上傳失敗', null, 'danger');
}
}
};
// 視頻上傳
editor.customConfig.uploadVideoServer = 'editUpload'; // 上傳接口
editor.customConfig.uploadVideoHooks = { // 上傳完成處理方法
customInsert: function (insertVideo, result) {
if (result.ret === 200) {
(result.data || '').split(',').forEach(function (link) {
link && insertVideo(link);
});
} else {
flavrShowByTime('上傳失敗', null, 'danger');
}
}
};
editor.create();
五、寫在最后
暫時想不到可以不修改源碼就實現視頻上傳的辦法