基于MdEditor魔改的markdown编辑器,拓展了图片上传
2020-08-25 本文已影响0人
夜雨渐停丶我独行
背景
MdEditor是一款非常棒的编辑器,但是在上传图片方面有点美中不足,缺少了本地上传图片到云服务器的功能,如果要日常使用的话还是需要二次开发的,经过一番魔改后可以支持本地图片上传了,本来打算直接引入到项目中的,考虑到编辑器实在太大了,所以就使用了iframe的方式引入,不多BB直接上图。
1.jpg 2.jpg 3.jpg 4.jpg
基于Markdown修改传送门:http://www.mdeditor.com/
拓展后项目源码传送门:https://github.com/LiveJie/simple-markdown
正常使用的话还是需要在editor项目中的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)
}
// 简单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)
}
}
}
// 添加监听回应事件
window.addEventListener('message', function (e) {
let data = e.data
//完成事件后响应
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;
}
}
});
});
上面是本人自己用到的图片上传方法使用的时候需要相应的修改,然后需要注意的是callBack方法三个参数需要存在不然可能会报错,也可以再次魔改源码,
下面说下编辑器内嵌的相应事件内嵌的父项目的首页index.html
// 设置iframe需要的token 个人七牛云需要 不需要的不用传
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;
}
}
})
接着是父项目的具体内嵌页面, 要根据具体情况来调用方法
mounted () {
setTimeout(() => {
let json = {
type: "setToken",
blog_token: localStorage.blog_token
}
this.getEditorData(json)
}, 3000)
},
methods: {
// 获取获取通讯数据
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()">确认</div>
<div class="cencel btn" onclick="hide()">取消</div>
</div>
</div>
`;
imgWrapperDom.appendChild(updateDom);
//监听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("请上传正确格式的图片!")
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;//获取到第一个上传的文件对象
for(let file of files) {
if(!file.type.match("image")) {
_this.Message.error("请上传正确格式的图片!")
return false
}
_this.fileList.push(file)
var fr=new FileReader();//实例FileReader对象
fr.readAsDataURL(file);//把上传的文件对象转换成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';
}
//加载进度条
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)
}
//点击删除元素
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)
}
// 模拟点击上上传图片
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();
}
})();
到这里就介绍的差不多了,希望可以帮助到有需要的人