Skip to content

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})`
		)
	)
})

© thebestxt.cc
辽ICP备16009524号-8
本站所有文章版权所有,转载请注明出处