Vue3富文本编辑器组件开发

479 阅读2分钟

背景需求

vite构建的vue3项目, 需要开发一个富文本组件满足条件如下:

VueQuill富文本编辑器

这个是今天的主角,项目中使用的是基于quill的富文本插件VueQuill

基本使用

  1. 要使用VueQuill组件,需要先将其安装到您的Vue项目中。您可以使用npm安装:
npm install @vueup/vue-quill@latest --save
  1. 安装完成后,将组件导入到您的Vue组件中:
import { ref, toRaw, reactive } from 'vue'
import { QuillEditor, Quill } from '@vueup/vue-quill'
import '@vueup/vue-quill/dist/vue-quill.snow.css'

defineOptions({
  name: 'QEditor',
})

const props = defineProps({
  content: {
    type: String,
    default: '',
  },
  // 工具栏配置
  toolbarOptions: {
    type: Array,
    default: () => [
      ['bold', 'italic', 'underline', 'strike'], // 粗体、斜体、下划线、删除线
      [{ header: 1 }, { header: 2 }], // 标题1和标题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] }], // 标题等级
      [{ color: [] }, { background: [] }], // 字体颜色和背景色
      [{ font: [] }], // 字体
      [{ align: [] }], // 对齐方式
      ['clean'], // 清除格式
      ['image'], //上传图片
      // ["image","video"], //上传图片、上传视频
    ],
  },
  placeholder: {
    type: String,
    default: '请输入',
  },

  // 是否只读
  readOnly: {
    type: Boolean,
    default: false,
  },

  // 限制字数
  maxLength: {
    type: Number,
    default: 1000,
  },
})

const emit = defineEmits(['changeContent'])

// 富文本内容
const content = ref(props.content)

// 富文本组件DOM元素
const myQuillEditor = ref(null)

// 富文本配置项
const editorOptions = reactive({
  theme: 'snow',
  modules: {
    toolbar: props.toolbarOptions,
  },
  placeholder: props.placeholder,
  readOnly: props.readOnly,
})

// 内容更新事件
const changeContent = () => {
  const text = toRaw(myQuillEditor.value).getHTML()

  // 限制输入字数
  const TiLength = myQuillEditor.value.getText().length - 1
  if (
    TiLength > props.maxLength &&
    myQuillEditor.value &&
    myQuillEditor.value.getQuill()
  ) {
    myQuillEditor.value.getQuill().deleteText(props.maxLength, TiLength + 1)
    return
  }

  emit('changeContent', text)
}
  1. Vue组件中使用VueQuill组件
<template>
  <div class="q-editor">
    <QuillEditor
      ref="myQuillEditor"
      theme="snow"
      v-model:content="content"
      :options="editorOptions"
      contentType="html"
      @update:content="changeContent()"
    />
  </div>
</template>

这里的v-model:content绑定了Vue组件的ref属性content,以便在编辑器中输入的内容能够被保存到Vue组件中。

如何设置富文本自定义图片上传?

  1. 富文本注册图片上传插件
import { QuillEditor, Quill } from '@vueup/vue-quill'
import ImageUploader from 'quill-image-uploader'
import 'quill-image-uploader/dist/quill.imageUploader.min.css'

Quill.register('modules/imageUploader', ImageUploader)
  1. 富文本配置项配置图片上传事件
// 富文本配置项
const editorOptions = reactive({
  theme: 'snow',
  modules: {
    ...
    // 上传图片
    imageUploader: {
      upload: async (file) => {
        try {
          return new Promise((resolve, reject) => {
            const formData = new FormData()
            formData.append('file', file)

            uploadFile(formData)
              .then((res) => {
                resolve(res.data.url)
              })
              .catch((err) => {
                reject('Upload failed')
                console.error('Error:', err)
              })
          })
        } catch (error) {
          console.error('压缩和上传图像时出错:', error)
        }
      },
    },
  },
  ...
})
  1. 富文本图片上传处理
// 上传图片
const uploadFile = (formData) => {
  // 此处为模拟接口请求
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('formData', formData)
      resolve({
        data: {
          url: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/JavaScript-logo.png/480px-JavaScript-logo.png',
        },
      })
    }, 3500)
  })
}

富文本组件外部调用

<script>
  // 富文本编辑器
  const editorValue = ref('富文本编辑器')
  const editorChange = (html) => {
    console.log('富文本内容', html)
  }
</script>

<template>
  <div>
      <QuillEditor
        :content="editorValue"
        placeholder="请输入内容"
        @changeContent="editorChange"
      />
  </div>
</template>