1 动机
尽管tinymce已经有link插件,但是不能完全满足客户的需求,因此采取自行编写插件的方式来设计。 首先,明确自己的需求。
- 实现图片、视频、文件的上传,上传至七牛云
- 有预览区,对于视频、图片可以设置宽高
- 根据返回URL,以及不同的文件类型,以HTML的形式插入到editor
- 对于大文件、视频,实现分片上传,支持断点续传
本文主要是剩下部分
2 文件上传七牛云
网上很多资料都是需要后端配合的,本文提供一个前端实现的方法。需要用到 qiniu-js以及crypto-js。 qiniu-js提供了很多上传方法并且支持大文件分片上传,这里主要使用qiniu.upload方法来实现文件的上传。
2.1 准备工作
- 在七牛云注册账号,创建一个自己的存储空间。
- 绑定自己的域名(七牛云提供的临时域名有效期只有30天)
3. 复制自己的access_key, secret_key, bucketname
图中分别是access_key, secret_key
图中框出的区域为bucketname
2.2 获取token
需要用到crypto-js,根据自己的access_key, secret_key, bucketname来生成token
import CryptoJS from 'crypto-js';
// 获取token
function getToken(access_key, secret_key, bucketname) {
// 构造策略
var putPolicy = {
"scope": bucketname,
"deadline": 3600 + Math.floor(Date.now() / 1000)
}
var encoded = base64Encode(utf16to8(JSON.stringify(putPolicy)));
var hash = CryptoJS.HmacSHA1(encoded, secret_key);
// 构造凭证
var encodedSign = hash.toString(CryptoJS.enc.Base64).replace(/\//g, '_').replace(/\+/g, '-');
var uploadToken = access_key + ':' + encodedSign + ':' + encoded;
return uploadToken;
}
// 编码函数
function base64Encode(str) {
var out, i, len;
var c1, c2, c3;
len = str.length;
i = 0;
out = "";
var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
while (i < len) {
c1 = str.charCodeAt(i++) & 0xff;
if (i == len) {
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt((c1 & 0x3) << 4);
out += "==";
break;
}
c2 = str.charCodeAt(i++);
if (i == len) {
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt((c2 & 0xF) << 2);
out += "=";
break;
}
c3 = str.charCodeAt(i++);
out += base64EncodeChars.charAt(c1 >> 2);
out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
out += base64EncodeChars.charAt(c3 & 0x3F);
}
return out;
}
// 加密函数
function utf16to8(str) {
var out, i, len, c;
out = "";
len = str.length;
for (i = 0; i < len; i++) {
c = str.charCodeAt(i);
if ((c >= 0x0001) && (c <= 0x007F)) {
out += str.charAt(i);
} else if (c > 0x07FF) {
out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
} else {
out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
}
}
return out;
}
2.3 文件上传
暴露出一个uploadFile函数,传入两个参数,一个是file(File类型),一个是要存储的文件夹的位置
import * as qiniu from 'qiniu-js';
export function uploadFile(file,directory="file/") {
// 对应上一节的token获取
const uptoken = getToken("xx", "aa", "bb");
const key = file.name;
const config = {
useCdnDomain: true,
forceDirect: true // 是否上传全部采用直传方式
};
const putExtra = {
fname: file.name, //文件原文件名
};
// 返回一个 observable 对象
return qiniu.upload(file, directory+key, uptoken, putExtra, config);
}
2.4 tinymce的行为
将uploadFile函数引入到编辑器的组件,设置tinymce的file_picker_callback属性为fileUpload函数。
import { uploadFile } from "./upload";
const fileUpload = (cb)=>{
// 必须定义input,并且点击才会弹出文件上传的框
const input = document.createElement('input');
input.setAttribute('type', 'file');
input.onchange = function () {
let file = this.files[0];
let reader = new FileReader();
reader.onload = function () {
uploadFile(file,'file/').subscribe({
// 接收上传进度信息的回调函数
next: (result) => {
console.log(result,"result")
},
// 出现错误
error: (err) => {
console.log(err,"err")
},
// 全部完成
complete: (e) => {
//回调函数,传给urlinput
cb('http://cdn1.bdbdbdsbd.asia/'+e.key, { title: file.name });
},
});
};
reader.readAsDataURL(file);
};
input.click();
}
3 总结
本文编写了一个组件用于文件上传,实现了文件上传到七牛云并插入HTML元素到富文本编辑器中。
待提高:
- 图片视频的压缩
- 进度条的实现