0%
Editor.md + 七牛云 实现在文本框粘贴图片上传到七牛云,并实时更新上传进度到文本框
2023-10-24
先准备一个 div 给 Editor.md 渲染用:
html
<div id="editormd-container"></div>
渲染逻辑
javascript
this.Editor = editormd("editormd-container", {
width: "100%",
height: 640,
syncScrolling: "single",
path: "/public/js/editor-md-lib/",
});
由于七牛云部分是使用了客户端上传,参考了官方的js sdk 文档。所以需要提前用后端把七牛云的上传 token 准备好。这里就默认我已经将 token 放到this.qiniuToken
中了。
在编辑器加载完毕后,绑定粘贴事件。
javascript
this.Editor = editormd("editormd-container", {
width: "100%",
height: 640,
syncScrolling: "single",
path: "/public/js/editor-md-lib/",
onload: function() {
document.addEventListener("paste", function (e) {
var items = (e.clipboardData || e.originalEvent.clipboardData).items
for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1){
var blob = items[i].getAsFile();
var reader = new FileReader();
reader.onload = function (event) {
const imageData = event.target.result
// imageData 就是图片的 base64数据
};
reader.readAsDataURL(blob);
}
}
});
}
});
接下来需要准备两个工具函数
javascript
// base64 转 Blob
function base64ToBlob(base64, type) {
const binaryString = atob(base64);
const length = binaryString.length;
const bytes = new Uint8Array(length);
for (let i = 0; i < length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return new Blob([bytes], { type: type });
}
// Blob 转 File 对象
function blobToFile(blob, fileName) {
return new File([blob], fileName, { type: blob.type });
}
在获取到图片的 base64 数据后,将其转换为 File 对象,就可以直接调用七牛云的 sdk 进行上传了。
我们先将 base64 转为 File 对象:
javascript
const blob = base64ToBlob(imageData.replaceAll('data:image/png;base64,', ''), "image/png")
// rand 是个生成随机数的函数,随便一搜就能搜到
const fileName = `${md5(`${Date.parse(new Date())}`)}${rand(100000, 999999)}`
const file = blobToFile(blob, fileName)
紧接着,我们向文本框中粘贴的位置插入一个占位字符串,用来更新图片上传进度和上传完成后直接显示图片。
javascript
// 编辑器实例存放在 _this.Editor 中
// 由于是在 onload 事件中,而 onload 事件是用 function 的形式写的
// 所以需要在 onload 外面提前用 `const _this = this` 把当前 Vue 实例存起来
// fileName 是上面一段代码中生成的随机文件名
_this.Editor.insertValue(`![图片上传中 0%](${fileName})`)
后面要实现的逻辑是,当图片上传进度变化时,我们要将进度更新到这个占位串中;当图片上传完毕,我们要将图片的服务器地址更新到这个占位串上。
javascript
// 开启一个七牛云的上传任务
const observable = qiniu.upload(file, `childPath/${fileName}`, _this.qiniuToken)
// 订阅七牛云的上传事件
const subscription = observable.subscribe((e) => {
// 上传中途,更新图片的上传进度
_this.Editor.setMarkdown(
addVm.$refs.md.Editor.getMarkdown().replace(
new RegExp(`\\!\\[图片上传中 (\\d+(\\.\\d+)?%)\\]\\(${fileName}\\)`, 'g'),
`![图片上传中 ${e.total.percent.toFixed(2)}%](${fileName})`
)
)
}, (e) => {
// 上传失败,删除编辑框里的图片
_this.Editor.setMarkdown(
addVm.$refs.md.Editor.getMarkdown().replace(new RegExp(`\\!\\[图片上传中 \\d+%\\]\\(${fileName}\\)`, 'g'), ``))
}, (e) => {
// 上传完毕,更新图片显示
_this.Editor.setMarkdown(
_this.$refs.md.Editor.getMarkdown().replace(
new RegExp(`\\!\\[图片上传中 (\\d+(\\.\\d+)?%)\\]\\(${fileName}\\)`, 'g'),
`![${fileName}](http://host.com/${e.key})`
)
)
})