背景
MdEditor是一款非常棒的編輯器辨萍,但是在上傳圖片方面有點(diǎn)美中不足铁瞒,缺少了本地上傳圖片到云服務(wù)器的功能,如果要日常使用的話還是需要二次開發(fā)的耳奕,經(jīng)過一番魔改后可以支持本地圖片上傳了衅斩,本來打算直接引入到項(xiàng)目中的盆顾,考慮到編輯器實(shí)在太大了,所以就使用了iframe的方式引入畏梆,不多BB直接上圖您宪。
1.jpg
2.jpg
3.jpg
4.jpg
基于Markdown修改傳送門:http://www.mdeditor.com/
拓展后項(xiàng)目源碼傳送門:https://github.com/LiveJie/simple-markdown
正常使用的話還是需要在editor項(xiàng)目中的html修改一些配置
$(function() {
window.editor = editormd("min-editor", {
width : "100%",
height : "600px",
emoji: true,
updateBefore: updateBefore, //拓展上傳文件方法
theme : (localStorage.theme) ? localStorage.theme : "dark",
previewTheme : (localStorage.previewTheme) ? localStorage.previewTheme : "default",
editorTheme : (localStorage.editorTheme) ? localStorage.editorTheme : "pastel-on-dark",
path : "./lib/"
});
// 圖片上傳方法
function updateBefore(file, callBack) {
const formData = new FormData()
formData.append('file', file)
formData.append('fileName', file.name)
ajax('post', location.origin+'/api/updateImg', formData, callBack)
}
// 簡(jiǎn)單ajax封裝
function ajax(type, url, data, callBack) {
var xhr = null;
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
xhr.open(type, url, true);
xhr.setRequestHeader('token', window._blog_token);
data && (xhr.send(data));
// xhr.responseType = "blob";
xhr.onload = function (e) {
if (this.status == 200) {
let res = JSON.parse(xhr.response)
let params = {
url: res.data,
alt: data.get("fileName"),
link: res.data
}
callBack && callBack(params)
}
}
}
// 添加監(jiān)聽回應(yīng)事件
window.addEventListener('message', function (e) {
let data = e.data
//完成事件后響應(yīng)
let str = "window_" + data.type
if(typeof data === 'object') {
switch(data.type) {
case "setToken":
window._blog_token = data.blog_token
window.parent.postMessage(str,"*");
break;
case "setValue":
window.editor.setValue(data.value)
window.parent.postMessage(str,"*");
break;
}
}else {
let params = {}
switch(data) {
case "getHTML":
params = {
type: 'setHtml',
data: window.editor.getHTML()
}
window.parent.postMessage(params,"*");
break;
case "getValue":
params = {
type: 'setValue',
data: window.editor.getValue()
}
window.parent.postMessage(params,"*");
break;
}
}
});
});
上面是本人自己用到的圖片上傳方法使用的時(shí)候需要相應(yīng)的修改,然后需要注意的是callBack方法三個(gè)參數(shù)需要存在不然可能會(huì)報(bào)錯(cuò)奠涌,也可以再次魔改源碼宪巨,
下面說下編輯器內(nèi)嵌的相應(yīng)事件內(nèi)嵌的父項(xiàng)目的首頁(yè)index.html
// 設(shè)置iframe需要的token 個(gè)人七牛云需要 不需要的不用傳
window._setIframeMessage = function(json) {
window["_"+json.type] = false
document.getElementsByTagName('iframe')[0].contentWindow.postMessage(json,"*");
}
// 獲取編輯器HTML
window._getEditorHTML = function() {
document.getElementsByTagName('iframe')[0].contentWindow.postMessage("getHTML","*");
}
// 獲取編輯器VALUE
window._getEditorValue = function() {
document.getElementsByTagName('iframe')[0].contentWindow.postMessage("getValue","*");
}
// 捕獲反向傳播事件
window.addEventListener('message', function (e) {
let data = e.data
if(typeof data === 'object') {
switch(data.type) {
case "setHtml":
window._editorHtml = data.data
break;
case "setValue":
window._editorValue = data.data
break;
}
}else {
switch(data) {
case "window_setValue":
window._setValue = true
break;
case "window_setToken":
window._setToken = true
break;
}
}
})
接著是父項(xiàng)目的具體內(nèi)嵌頁(yè)面, 要根據(jù)具體情況來調(diào)用方法
mounted () {
setTimeout(() => {
let json = {
type: "setToken",
blog_token: localStorage.blog_token
}
this.getEditorData(json)
}, 3000)
},
methods: {
// 獲取獲取通訊數(shù)據(jù)
getEditorData(json) {
if (window["_" + json.type]) {
return
}
window._setIframeMessage(json)
setTimeout(() => {
this.getEditorData(json)
}, 100)
},
}
魔改編輯器的核心拓展文件update-img.js
/**
* @description editor圖片拓展上傳插件
* @author jie
* @export
* @param {*}
* @returns
*/
;
(function () {
var factory = function () {
let _this = this
this.Message = null;
this.fileList = [];
let imgWrapperDom = document.getElementById("extend-img-dialog-wrapper")
// 插件初始化
this.init = function () {
this.Message = new Message()
let updateDom = document.createElement("div")
updateDom.setAttribute("id", "update-wrapper")
updateDom.className = "update-wrapper"
updateDom.innerHTML = `
<div class="input-box-wrapper">
<div class="input-box" onclick="selectFile()">
<div class="svg-box">
<svg viewBox="0 0 1024 1024" focusable="false" class="" data-icon="inbox" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M885.2 446.3l-.2-.8-112.2-285.1c-5-16.1-19.9-27.2-36.8-27.2H281.2c-17 0-32.1 11.3-36.9 27.6L139.4 443l-.3.7-.2.8c-1.3 4.9-1.7 9.9-1 14.8-.1 1.6-.2 3.2-.2 4.8V830a60.9 60.9 0 0060.8 60.8h627.2c33.5 0 60.8-27.3 60.9-60.8V464.1c0-1.3 0-2.6-.1-3.7.4-4.9 0-9.6-1.3-14.1zm-295.8-43l-.3 15.7c-.8 44.9-31.8 75.1-77.1 75.1-22.1 0-41.1-7.1-54.8-20.6S436 441.2 435.6 419l-.3-15.7H229.5L309 210h399.2l81.7 193.3H589.4zm-375 76.8h157.3c24.3 57.1 76 90.8 140.4 90.8 33.7 0 65-9.4 90.3-27.2 22.2-15.6 39.5-37.4 50.7-63.6h156.5V814H214.4V480.1z"></path></svg>
</div>
<div class="title">Click or drag file to this area to upload</div>
<div class="desc">Support for a single or bulk upload. Strictly prohibit from uploading company data or other band files</div>
</div>
<div class="file-list-wrapper">
</div>
<input id="input-file" type="file" style="display: none;" accept="image/*" multiple></input>
<div class="button-wrapper">
<div class="ensure btn" onclick="confirm()">確認(rèn)</div>
<div class="cencel btn" onclick="hide()">取消</div>
</div>
</div>
`;
imgWrapperDom.appendChild(updateDom);
//監(jiān)聽input上傳圖片
let fileDom = document.getElementById('input-file');
fileDom.onchange = function(e) {
e.preventDefault();
let fileList = e.target.files
if(fileList.length > 5) {
_this.Message.error("圖片最多只能選擇5張!")
}else {
for(let item of fileList) {
if(!item.type.match("image")) {
_this.Message.error("請(qǐng)上傳正確格式的圖片!")
return false
}
let sign = new Date().getTime()
item.sign = sign
_this.fileList.push(item)
var read = new FileReader();
read.readAsDataURL(item);
read.onload = function (e) {
addFileList(this.result, item.name, sign)
}
}
}
}
//圖片拖拽上傳
let box = document.getElementById('update-wrapper');
box.ondragover = function (e){
e.preventDefault();
}
// 拖拽圖片
box.ondrop = function (e){
e.preventDefault();
var files = e.dataTransfer.files;//獲取到第一個(gè)上傳的文件對(duì)象
for(let file of files) {
if(!file.type.match("image")) {
_this.Message.error("請(qǐng)上傳正確格式的圖片溜畅!")
return false
}
_this.fileList.push(file)
var fr=new FileReader();//實(shí)例FileReader對(duì)象
fr.readAsDataURL(file);//把上傳的文件對(duì)象轉(zhuǎn)換成url
fr.onload=function (e){
addFileList(this.result, file.name)
}
}
}
}()
function Message() {
this.success = function(msg = "", duration = 3) {
let className = "message active success"
this.showThis(msg, duration, className)
}
this.wraning = function(msg = "", duration = 3) {
let className = "message active wraning"
this.showThis(msg, duration, className)
}
this.error = function(msg = "", duration = 3) {
let className = "message active error"
this.showThis(msg, duration, className)
}
this.showThis = function(msg, duration, className) {
if(!msg) {
return Error("msg is null")
}
let divDom = document.createElement("div")
divDom.innerText = msg
divDom.className = "message";
imgWrapperDom.appendChild(divDom)
setTimeout(function(){
divDom.className = className || "message"
},50)
setTimeout(function(){
imgWrapperDom.removeChild(divDom)
}, duration * 1000)
}
}
this.getFileList = function () {
return this.fileList
}
this.hide = function () {
this.reset();
imgWrapperDom.style.display = 'none';
}
this.confirm = function () {
if(!window._updateBefore) {
_this.Message.error("updateBefore function is not setting!")
return
}
if(!this.fileList.length) {
_this.Message.error("上傳圖片不能為空!")
}
for(let item of this.fileList) {
window._updateBefore(item, function(params) {
dialog.setFileUrl(params)
})
}
this.reset()
imgWrapperDom.style.display = 'none';
}
this.reset = function() {
this.fileList = [];
let fileListDom = document.getElementsByClassName("file-list-wrapper")[0]
fileListDom.innerHTML = '';
}
this.show = function () {
this.fileList = [];
imgWrapperDom.style.display = 'block';
}
//加載進(jìn)度條
this.speedProgress = function (e) {
const lastLinearDom = e.children[e.children.length - 1]
let w = ~~lastLinearDom.style.width.replace("%", "")
if(w >= 100) {
lastLinearDom.style.width = '';
}else {
let randomNum = Math.floor(Math.random()*10)
if((w + randomNum) >= 100) {
lastLinearDom.style.width = '';
}else {
lastLinearDom.style.width = w + randomNum + '%';
setTimeout(function(){
speedProgress(e)
},100)
}
}
}
//添加圖片文件
this.addFileList = function(url, name, sign) {
let fileListDom = document.getElementsByClassName("file-list-wrapper")[0]
if(fileListDom.children.length >= 5) {
this.Message.error("圖片最多只能選擇5張!")
return
}
let html = `
<div class="left">
<img src="${url}" alt="">
<div class="name">${name}</div>
</div>
<div class="right" data-sign="${sign}" onclick="deleteDom(this)">
<svg viewBox="64 64 896 896" focusable="false" class="" data-icon="delete" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M360 184h-8c4.4 0 8-3.6 8-8v8h304v-8c0 4.4 3.6 8 8 8h-8v72h72v-80c0-35.3-28.7-64-64-64H352c-35.3 0-64 28.7-64 64v80h72v-72zm504 72H160c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h60.4l24.7 523c1.6 34.1 29.8 61 63.9 61h454c34.2 0 62.3-26.8 63.9-61l24.7-523H888c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM731.3 840H292.7l-24.2-512h487l-24.2 512z"></path></svg>
</div>
<div class="file-list-linear"></div>
`
let divDom = document.createElement("div")
divDom.className = "list"
divDom.innerHTML = html;
fileListDom.appendChild(divDom)
}
//點(diǎn)擊刪除元素
this.deleteDom = function(e) {
e.parentNode.remove(e)
_this.fileList.forEach(function(item, index) {
if(item.sign == e.attributes[1].value) {
_this.fileList.splice(index)
return;
}
})
console.log(_this.fileList)
}
// 模擬點(diǎn)擊上上傳圖片
this.selectFile = function() {
var fileDom = document.getElementById('input-file');
fileDom.click()
}
};
if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
module.exports = factory;
} else if ((typeof define === "function")) {
if(define.amd) {
define(null, function() {
factory()
});
}else {
define(function() {
factory();
});
}
} else {
factory();
}
})();
到這里就介紹的差不多了捏卓,希望可以幫助到有需要的人