Tinymce插件设计——文件上传插件(2)

168 阅读3分钟

1 动机

尽管tinymce已经有link插件,但是不能完全满足客户的需求,因此采取自行编写插件的方式来设计。 首先,明确自己的需求。

  1. 实现图片、视频、文件的上传,上传至七牛云
  2. 有预览区,对于视频、图片可以设置宽高
  3. 根据返回URL,以及不同的文件类型,以HTML的形式插入到editor
  4. 对于大文件、视频,实现分片上传,支持断点续传

本文主要是剩下部分

2 文件上传七牛云

网上很多资料都是需要后端配合的,本文提供一个前端实现的方法。需要用到 qiniu-js以及crypto-jsqiniu-js提供了很多上传方法并且支持大文件分片上传,这里主要使用qiniu.upload方法来实现文件的上传。

2.1 准备工作

  1. 在七牛云注册账号,创建一个自己的存储空间。
  2. 绑定自己的域名(七牛云提供的临时域名有效期只有30天)

image.png 3. 复制自己的access_key, secret_key, bucketname

图中分别是access_key, secret_key image.png 图中框出的区域为bucketname image.png

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元素到富文本编辑器中。

待提高:

  1. 图片视频的压缩
  2. 进度条的实现