klqa开发实践(一):说说富文本编辑器、文件上传那些事

11月的某一天,某某组需要klqa支持开发一个A流程,需要支持图片上传、富文本编辑,嗯,作为组内最可爱最会卖萌的人(哈哈,被别人看到了会打我的!)该任务就落在我身上啦...本以为一切都很顺利,一天就能搞定,毕竟考拉的程序猿哥哥们一个个都很厉害,代码不会写,可以直接找他们就好了嘛(sorry,这是我自己臆想的....)

在进入整体之前,先说说为啥会出现即将介绍的问题,由于历史原因,klqa平台搭建的时候,没有使用比较主流的vue、react等框架,so....目前一些开源的组件库无法使用(泪奔T_T...我们现在正在努力优化...现在的开发任务 已经在使用vue前端框架啦)  作为历史遗留问题,该用的暂时还不能全部大改,总归需要时间的嘛
一、关于富文本编辑器
这次我们也尝试了很多编辑器,百度的ueeditor、layui组件库自带的编辑器等等,但是适配的时候发现很多暂时无法解决的问题,so...不能不舍弃啊,最终我们还是选择比较轻量级的wangEditor嵌入到我们的模块中,并尽量保持格式上一致,视觉上美观...
  1. js引入(Base2中已经引用,这个针对单独新开的html)
    <link href="{{ url_for('static', filename='css/platform/editor/wangEditor.css') }}" rel="stylesheet">
    <script src="{{ url_for('static',filename='js/platform/wangEditor.js') }}"></script>
  2. 前提条件:html中预先定义个文本框 便于后续富文本编辑器渲染
    <textarea id="db_change_content" type="text" name="db_change_content"  ></textarea>
    height: 150px   这个是你页面显示富文本框 编辑区的高度 按照自己的需求设置
  3. JS中设置:渲染编辑器
    var eDbEditor = new wangEditor(document.getElementById('db_change_content'));
    eDbEditor.config.menus = dSelfMenus;
    eDbEditor.create();

解释:

第一行是用来将 textarea 渲染成为一个编辑器;

第二行自定也编辑器菜单(就是编辑器上支持哪些功能), 使用编辑器默认值的话  第二行去掉就可以 , 当然全局的默认值 也可以全局指定,具体配置在 wangEditor.js 中, 比如:

var dSelfMenus = [
'bold', 'underline', 'italic', 'strikethrough', 'forecolor', 'bgcolor', '|',
 'quote', 'fontfamily', 'fontsize', 'head', 'unorderlist', 'orderlist', 'alignleft', 'aligncenter', 'alignright',
 '|', 'link', 'unlink', 'table', 'img', '|', 'undo', 'redo'];

第三行创建一个编辑器;

Attention: 对一个 id 一次加载js中只能出现 一次 create() 操作, 否则如果多次create()操作会出现 菜单栏重复增加现象  严重影响用户体验

初始化编辑器:

var textarea = document.getElementById('wang_edit');
var editor = new wangEditor(textarea);
.....
if(editor_count ==0){
  editor.create();
}

在页面上多次点击编辑之后的按钮渲染:

// 非首次点击编辑按钮
if(editor_count !=0 ){
  editor.destroy();
}


// 首次点击编辑按钮
if(editor_count ==0 ){
 editor.create();
}
else{
  editor.undestroy(); // 因为前面多次点击时候 destroy 了 这个地方需要复原
}
editor.$txt.html(content); // 将内容渲染到编辑器里面去

其他Tips:

1、富文本编辑器在 日常压测流程 开发过程中,第一版demo会出现抖屏问题 严重影响用户体验

解决方法:  修改wangEditor源码  设置min-Height  菜单吸顶设置为false

二、关于图片上传

富文本编辑框中粘贴图片上传前端设置:
// 上传图片(举例)
editor.config.uploadImgUrl = '/后端接口名;
editor.config.uploadImgFileName = 'myFileName';
粘贴渲染:document.getElementById('wang_edit').addEventListener('paste',function(e){
        if ( !(e.clipboardData && e.clipboardData.items) ) {
            return;
        }
        for (var i = 0, len = e.clipboardData.items.length; i < len; i++) {
            var item = e.clipboardData.items[i];

            if (item.kind === "file" && item.type == "image/png") {
                var data = new FormData();
                data.append('upload_file'+i, item.getAsFile());
                jQuery.ajax({
                    url:'/performance_upload',
                    type:'Post',
                    data: data
                });
            }
        }
    });

后端代码 主要是为了生成上传后返回的私有 url:

@pw.route('/upload,methods=['POST'])
def performance_upload():
    file = request.files['myFileName']
    file_binary = file.read()
    filename = file.filename
    postfix = filename.split('.')[-1]

    # 时间戳
    file_time_name = str(int(round(time.time()*1000)))
    now_time = str((int(round(time.time()*1000)) + 94608000000)/1000)
    object_name = file_time_name + 'klqafile' + str(random.randint(1, 9999))+ '.' + postfix

    access_key = '******'
    secret_key = '******'
    bucket = '*****'
    end_point = "*****"

    client = nos.Client(access_key_id=access_key,
                        access_key_secret=secret_key,
                        end_point=end_point)

    client.put_object(bucket, object_name, file_binary)

    message = 'GET\n\n\n' + now_time + '\n/bucket名称/' + object_name
    signature = base64.b64encode(hmac.new(secret_key, message, digestmod=hashlib.sha256).digest())
    signature_str = urllib.quote(signature.encode('utf-8', 'replace'))
    if '\+' in signature_str:
        signature_str = signature_str.replace('\+', '%20').replace('\+', '%20')
    if '/' in signature_str:
        signature_str = signature_str.replace('/', '%2F').replace('/', '%2F').replace('/', '%2F')

    url =  'http://nos.netease.com/bucket名称/' + \
          str(object_name) + \
          '?' \
          'Signature=' \
          + signature_str + \
          '&Expires=' + now_time + \
          '&NOSAccessKeyId=******'

    res = Response(url)
    res.headers["ContentType"] = "text/html"
    res.headers["Charset"] = "utf-8"
    return res

代码解释:

now_time 设置私有url的过期时间
object_name 你上传的图片或者文件独一无二的名称
access_key、 secret_key  密钥
bucket 私有桶名称

// 下面两行是nos python上传接口   其它语言的上传接口类似  大同小异  

client = nos.Client(access_key_id=access_key,access_key_secret=secret_key,end_point=end_point)
client.put_object(bucket, object_name, file_binary)

// 生成私有链接 签名信息 通过 sha256算法生成

signature = base64.b64encode(hmac.new(secret_key, message, digestmod=hashlib.sha256).digest())
signature_str = urllib.quote(signature.encode('utf-8', 'replace'))

// 特殊字符编码

signature_str = urllib.quote(signature.encode('utf-8', 'replace')) if '\+' in signature_str: signature_str = signature_str.replace('\+', '%20').replace('\+', '%20') if '/' in signature_str: signature_str = signature_str.replace('/', '%2F').replace('/', '%2F').replace('/', '%2F')

// 私有url 拼接格式

url = 'http://nos.netease.com/私有桶bucket 名称/' + \ str(object_name) + '?Signature=' + signature_str + '&Expires=' + now_time + \ '&NOSAccessKeyId=***********************'

// 编辑器自动渲染图片需要的返回值(这里默认是 wangEditor  其它格式 这边可能不太一样)

res = Response(url) res.headers["ContentType"] = "text/html" res.headers["Charset"] = "utf-8"考拉质量平台更多功能,等你体验哦,点我直达>> 平台也正在不断更新优化中,大家一起学习吧!!!

相关阅读:klqa开发实践(二):使用flask+vue+iview搭建项目管理系统

本文来自网易实践者社区,经作者朱珊珊授权发布