vue-quill-editor 富文本框编辑器

基于quilljs实现的支持vue的富文本框编辑器

官网

  1. vue-quill-editor
  2. Toolbar Module - Quill
  3. vue-quill-image-upload

图片支持上传服务器并调整大小

  1. package.json 中加入 "quill-image-extend-module": "^1.1.2" 依赖
  2. 在编辑器组件中引入以下代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<template>
  <div class="in-editor-panel">
    <quill-editor ref="quillEditor" v-model="content" :options="editorOption" @change="onChange">
    </quill-editor>
  </div>
</template>

<script type="text/ecmascript-6">
  import 'quill/dist/quill.core.css'
  import 'quill/dist/quill.snow.css'
  import { quillEditor, Quill } from 'vue-quill-editor'
  import { ImageExtend, QuillWatch } from 'quill-image-extend-module'
  import { hasClass } from 'assets/scripts/dom/dom'

  Quill.register('modules/ImageExtend', ImageExtend)

  export default {
    props: {
      value: {
        type: String,
        default: ''
      },
      toolbarMode: {
        type: Number,
        default: 0
      },
      placeholder: {
        type: String,
        default: '请输入内容'
      },
      height: {
        type: Number,
        default: 170
      },
      imagePath: {
        type: String,
        default: ''
      }
    },
    data () {
      return {
        content: '',
        toolbars: [
          [
            ['bold', 'italic', 'underline', 'strike'],
            ['blockquote', 'code-block'],
            [{'header': 1}, {'header': 2}],
            [{'list': 'ordered'}, {'list': 'bullet'}],
            [{'script': 'sub'}, {'script': 'super'}],
            [{'indent': '-1'}, {'indent': '+1'}],
            [{'direction': 'rtl'}],
            [{'size': ['small', false, 'large', 'huge']}],
            [{'header': [1, 2, 3, 4, 5, 6, false]}],
            [{'font': []}],
            [{'color': []}, {'background': []}],
            [{'align': []}],
            ['clean'],
            ['link', 'image', 'video']
          ],
          [
            ['bold', 'italic', 'underline'],
            ['blockquote', 'code-block'],
            [{'list': 'ordered'}, {'list': 'bullet'}],
            [{'header': [1, 2, 3, 4, 5, 6, false]}],
            [{'color': []}, {'background': []}],
            [{'align': []}],
            ['link', 'image', 'video']
          ],
          [
            ['bold', 'italic', 'underline'],
            ['blockquote', 'code-block'],
            [{'list': 'ordered'}, {'list': 'bullet'}],
            [{'color': []}, {'background': []}],
            ['insert']
          ]
        ],
        editorOption: {
          modules: {
            ImageExtend: {
              loading: true,
              name: 'image',
              size: 2,
              action: `/api/file/upload/image?filePath=${JSON.stringify(this.imagePath)}`,
              response: (res) => {
                return res.data
              }
            },
            toolbar: {
              container: [],
              handlers: {
                'image': function () {
                  QuillWatch.emit(this.quill.id)
                }
              }
            }
          },
          placeholder: this.placeholder
        }
      }
    },
    computed: {
      editor () {
        return this.$refs.quillEditor.quill
      }
    },
    watch: {
      // 监听父组件传入的内容
      value (newVal) {
        this.$nextTick(() => {
          this._listenerImage()
        })

        if (newVal === this.content) {
          return false
        }

        // 传入的内容不等于编辑器自身内容,则更新
        this.content = newVal
      },
      'content' () {
        this._listenerImage()
      }
    },
    created () {
      // 指定工具栏
      this.editorOption.modules.toolbar.container = this.toolbars[this.toolbarMode]
    },
    mounted () {
      // 设置编辑器高度
      this.editor.container.style.height = `${this.height}px`
    },
    methods: {
      // 显示宽度修改框
      _showWidthBox (event) {
        // 获取当前图片对象
        let currentImg = event.target

        // 弹出宽度输入框
        this.$prompt('请输入宽度', '提示', {
          inputValue: currentImg.width,
          confirmButtonText: '确定',
          cancelButtonText: '取消'
        }).then(({value}) => {
          // 赋值新宽度
          currentImg.width = value
        }).catch(() => {})
      },
      // 监听图片点击
      _listenerImage () {
        // 获取DOM对象
        let editor = document.getElementsByClassName('ql-editor')[0]
        let img = editor.getElementsByTagName('img')

        // 非空验证
        if (img.length === 0) {
          return
        }

        for (let i = 0; i < img.length; i++) {
          let currentImg = img[i]

          // 绑定且防止重复绑定
          currentImg.removeEventListener('dblclick', this._showWidthBox, false)
          currentImg.addEventListener('dblclick', this._showWidthBox, false)
        }
      },
      onChange () {
        // 告知父组件内容发生变化
        this.$emit('input', this.content)
      }
    },
    components: {
      quillEditor
    }
  }
</script>