富文本编辑vue-quill-editor自定义图片、文件上传

需求一 图片上传

就是要一个富文本编辑器,然后有图片上传功能,因为vue-quill-editor是将图片转为base64编码,所以当图片比较大时,提交后台时参数过长,导致提交失败。

解决思路

将图片先上传至服务器,再将图片链接插入到富文本中
图片上传的话可以使用element或者iview,这里我以iview举例
图片上传区域要隐藏,自定义vue-quill-editor的图片上传,点击图片上传时调用iview或者element的图片上传,上传成功后在富文本编辑器中显示图片

步骤

零、安装使用
npm install vue-quill-editor --save

main.js

import VueQuillEditor from 'vue-quill-editor'
Vue.use(VueQuillEditor);
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
一、自定义vue-quill-editor图片上传

html:

<quill-editor
    v-model="content"
    :options="editorOption"
    ref="QuillEditor">
</quill-editor>

js:

<script>
    // 工具栏配置
    const toolbarOptions = [
      ['bold', 'italic', 'underline', 'strike'],        // toggled buttons
      ['blockquote', 'code-block'],
    
      [{'header': 1}, {'header': 2}],               // custom button values
      [{'list': 'ordered'}, {'list': 'bullet'}],
      [{'script': 'sub'}, {'script': 'super'}],      // superscript/subscript
      [{'indent': '-1'}, {'indent': '+1'}],          // outdent/indent
      [{'direction': 'rtl'}],                         // text direction
    
      [{'size': ['small', false, 'large', 'huge']}],  // custom dropdown
      [{'header': [1, 2, 3, 4, 5, 6, false]}],
    
      [{'color': []}, {'background': []}],          // dropdown with defaults from theme
      [{'font': []}],
      [{'align': []}],
      ['link', 'image', 'video'],
      ['clean']                                         // remove formatting button
    ]
    
    export default {
        data () {
            return {
                content: '',
                editorOption: {                
                    modules: {
                        toolbar: {
                            container: toolbarOptions,  // 工具栏
                            handlers: {
                                'image': function (value) {
                                    if (value) {
                                        alert('自定义图片')
                                    } else {
                                        this.quill.format('image', false);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }    
</script>
二、调用element或iview图片上传组件

html:

<Upload
    :show-upload-list="false"
    :on-success="handleSuccess"
    :format="['jpg','jpeg','png','gif']"
    :max-size="2048"
    multiple
    action="/file/upload"
    >
    <Button icon="ios-cloud-upload-outline" ></Button>
</Upload>
<quill-editor
    v-model="content"
    :options="editorOption"
    ref="QuillEditor">
</quill-editor>

css:

.ivu-upload {
    display: none;
}

js:

data () {
    return {
        content: '',
        editorOption: {                
            modules: {
                toolbar: {
                    container: toolbarOptions,  // 工具栏
                    handlers: {
                        'image': function (value) {
                            if (value) {
                                // 调用iview图片上传
                                document.querySelector('.ivu-upload .ivu-btn').click()
                            } else {
                                this.quill.format('image', false);
                            }
                        }
                    }
                }
            }
        }
    }
},
methods: {
    handleSuccess (res) {
        // 获取富文本组件实例
        let quill = this.$refs.QuillEditor.quill
        // 如果上传成功
        if (res) {
            // 获取光标所在位置
            let length = quill.getSelection().index;
            // 插入图片,res为服务器返回的图片链接地址
            quill.insertEmbed(length, 'image', res)
            // 调整光标到最后
            quill.setSelection(length + 1)
        } else {
            // 提示信息,需引入Message
            Message.error('图片插入失败')
        }
    },
} 
三、假如需要多个富文本编辑器

可能不止一处地方用到,比如添加完成后还有编辑功能,那就复制一份文件上传和富文本编辑:两个富文本用不同的ref标记,在各自配置中调用各自的文件上传;文件上传成功也使用不同的方法名称,里面调用各自的富文本编辑器。

重点:富文本和文件上传不管使用类名还是什么方式区分的,这两处地方都要和之前区分开。

需求二 文件上传

和图片上传相同,不同的是上传文件。解决的思路也相同:在vue-quill-editor中自定义按钮,点击使用iView的文件上传,然后将地址赋值给a标签的href属性,插入到富文本光标处。

步骤

一、自定义编辑器附件上传

我想通过download属性自定义文件下载名称,但是两种方式都失败了,可以忽略相关代码。以下是为富文本自定义插入a链接

 import { Quill } from 'vue-quill-editor';
  // 自定义插入a链接
  var Link = Quill.import('formats/link');
  class FileBlot extends Link {  // 继承Link Blot
    static create(value) {
      let node = undefined
      if (value&&!value.href){  // 适应原本的Link Blot
        node = super.create(value);
      }
      else{  // 自定义Link Blot
        node = super.create(value.href);
        // node.setAttribute('download', value.innerText);  // 左键点击即下载
        node.innerText = value.innerText;
        node.download = value.innerText;
      }
      return node;
    }
  }
  FileBlot.blotName = 'link';
  FileBlot.tagName = 'A';
  Quill.register(FileBlot);

配置工具栏,添加了一个upload,其余不需要的都可以去掉

<script>
    // 自定义插入a链接
    // ...
    // 工具栏配置
    const toolbarOptions = [
      ['bold', 'italic', 'underline', 'strike'],        // toggled buttons
      ['blockquote', 'code-block'],
    
      [{'header': 1}, {'header': 2}],               // custom button values
      [{'list': 'ordered'}, {'list': 'bullet'}],
      [{'script': 'sub'}, {'script': 'super'}],      // superscript/subscript
      [{'indent': '-1'}, {'indent': '+1'}],          // outdent/indent
      [{'direction': 'rtl'}],                         // text direction
    
      [{'size': ['small', false, 'large', 'huge']}],  // custom dropdown
      [{'header': [1, 2, 3, 4, 5, 6, false]}],
    
      [{'color': []}, {'background': []}],          // dropdown with defaults from theme
      [{'font': []}],
      [{'align': []}],
      ['link', 'image', 'upload'],
      ['clean']                                         // remove formatting button
    ]
    
    export default {
        data () {
            return {
                content: '',
                editorOption: {                
                    modules: {
                        toolbar: {
                            container: toolbarOptions,  // 工具栏
                            handlers: {
                                'image': ((value) => {
                                    if (value) {
                                        alert('自定义图片')
                                    } else {
                                        this.quill.format('image', false);
                                    }
                                }),
                                'upload': ((value) => {
                                    if (value) {
                                        alert('自定义文件上传')
                                    }
                                })
                            }
                        }
                    }
                }
            }
        }
    }    
</script>

自定义文件上传的图标样式

.ql-snow.ql-toolbar .ql-upload{
      background: url("../assets/images/icon-upload.svg");
      background-size: 16px 16px;
      background-position: center center;
      background-repeat:no-repeat;
      /*background: red;*/
}
二、调用element或iview上传组件

为两个图片上传分别定义了类名,以做调用时的区分。

    <!-- 上传图片 -->
    <Upload
      :show-upload-list="false"
      :on-success="handleSuccess"
      :format="messageAllData.imgFileType"
      :before-upload="handleBeforeUpload"
      type="drag"
      :action="api.imgManage"
      class="uploadImage">
    </Upload>
    <!-- 上传文件 -->
    <Upload :show-upload-list="false"
            :on-success="handleFileSuccess"
            :before-upload="handleFileBeforeUpload"
            type="drag"
            :action="api.imgManage"
            class="uploadFile">
    </Upload>

修改工具栏配置,当点击富文本时,调用相应的上传组件

handlers: {
  'image': (value => {
    if (value) {
      document.querySelector('.uploadImage input').click()
    }else {
      this.quill.format('image', false);
    }
  }),
  'upload': (value => {
    if (value) {
      document.querySelector('.uploadFile input').click()
    }
  })
}

这两个文件上传都要隐藏

.uploadImage,
.uploadFile{
    width: 0;
    height: 0;
    display: none;
}

下面是插入图片和文件的方法

<quill-editor
    v-model="content"
    :options="editorOption"
    ref="QuillEditor">
</quill-editor>
methods: {
   // 图片
   handleSuccess (res, file) {
        let quill = this.$refs.QuillEditor.quill
        let length = quill.getSelection().index;
        quill.insertEmbed(length, 'image', res)
        quill.setSelection(length + 1)
   },
   // 文件
   handleFileSuccess (res, file) {       
        let fileNameLength = file.name.length
        // 插入链接
        let quill = this.$refs.QuillEditor.quill
        let length = quill.getSelection().index;
        quill.insertEmbed(length, 'link', {href:res, innerText:file.name}, "api")
        quill.setSelection(length + fileNameLength)
   },
} 

bug及优化

一、回车光标不显示

不知道为什么,百度都搜不到,好像只有我出现了这个问题,最后通过监听回车,手动换行并在换行后加了一个空格,因为没有内容的时候光标不显示,然后把光标向前调一个位置,移到空格前面。

const bindings = {
    custom: {
      key: 13,
      handler: function(range, context) {
        this.quill.insertText(range.index, '\n ');
        setTimeout(() => {
          let nowRange = this.quill.getSelection().index - 1
          this.quill.setSelection(nowRange)
        }, 0)
      }
    },
}
    export default {
        data () {
            return {
                content: '',
                editorOption: {                
                    modules: {
                        keyboard: {
                            bindings: bindings
                        },
                        toolbar: {
                            // ...
                        }
                    }
                }
            }
        }
    }    

二、给菜单栏添加中文标题title

// 标题
const titleConfig = {
    'ql-bold':'加粗',
    'ql-color':'颜色',
    'ql-font':'字体',
    'ql-code':'插入代码',
    'ql-italic':'斜体',
    'ql-link':'添加链接',
    'ql-background':'背景颜色',
    'ql-size':'字体大小',
    'ql-strike':'删除线',
    'ql-script':'上标/下标',
    'ql-underline':'下划线',
    'ql-blockquote':'引用',
    'ql-header':'标题',
    'ql-indent':'缩进',
    'ql-list':'列表',
    'ql-align':'文本对齐',
    'ql-direction':'文本方向',
    'ql-code-block':'代码块',
    'ql-formula':'公式',
    'ql-image':'图片',
    'ql-video':'视频',
    'ql-clean':'清除字体样式',
    'ql-upload':'文件'
};

methods: {
    addQuillTitle () {
        const oToolBar = document.querySelector('.ql-toolbar'),
        aButton = oToolBar.querySelectorAll('button'),
        aSelect =  oToolBar.querySelectorAll('select');
        aButton.forEach(function(item){
          if(item.className === 'ql-script'){
              item.value === 'sub' ? item.title = '下标': item.title = '上标';
          }else if(item.className === 'ql-indent'){
              item.value === '+1' ? item.title ='向右缩进': item.title ='向左缩进';
          }else{
              item.title = titleConfig[item.classList[0]];
          }
        });
        aSelect.forEach(function(item){
            item.parentNode.title = titleConfig[item.classList[0]];
        });
    },
},
mounted () {
      this.addQuillTitle()
},

有个需要注意的地方,按上面的方法使用后,确实有效,但是字体颜色和背景颜色的提示都变成了背景颜色,然后修改了标题栏的配置,提示才彼此对应。

const toolbarOptions = [     
      [{'color': []}, {'background': []}],
]

修改为

const toolbarOptions = [     
      [{'color': []}],
      [{'background': []}],
]

文档及其他参考

官方文档参考vue-quill-editor
图片及文件的验证参考

页面展示

图片样式限制宽高和边距就可以了,在富文本编辑器里面可以回车换行;
方式一:
可以另写一个style标签里面写上样式,也可以在原有的样式中通过深度选择器来写样式

<div v-html="editorContent" class="richTextStyle"></div>
<style>
  /*富文本图片样式 */
  .richTextStyle img {
    max-width: 720px;
    margin:10px;
  }
  /*富文本文字溢出不换行样式 */
  .richTextStyle p, .richTextStyle sup, .richTextStyle strong,
  .richTextStyle em, .richTextStyle u,
  .richTextStyle s, .richTextStyle blockquote, 
  .richTextStyle h1, .richTextStyle h2, .richTextStyle h3,
  .richTextStyle h4, .richTextStyle h5, .richTextStyle h6, 
  .richTextStyle li, .richTextStyle sub, .richTextStyle a {
    word-break: break-all;
  }
</style>

方式二:
完全以原来的样式显示富文本

<div v-html="editorContent" class="ql-editor"></div>

网站导航

网站导航

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容