quillEditor富文本编辑器的封装使用

整理笔记时发现的之前做项目用到的富文本编辑器quillEditor

  • 效果

在这里插入图片描述

  • Index.vue
<template>
	<r-t-editor
	  full-button
	  :disabled="false"
	  :show-content="content"
	  @change="getContent"
	></r-t-editor>
</template>
<script>
  data() {
    return {
      content: '回显数据',
    }
  },
  methods: {
    getContent({ html, text }) {
      console.log(html, text)
    }
  }
</script>
  • RTEditor.vue
<!--
 富文本编辑器组件
 @author: zhangxt
 @date: 2021/07/23
 @description: 基于quillEditor封装的富文本编辑器
               官方文档:https://www.kancloud.cn/liuwave/quill/1409423
               参考:https://blog.csdn.net/liuqiao0327/article/details/107126784/
               全屏:https://www.cnblogs.com/huihuihero/p/14084621.html
-->
<template>
  <div class="r-t-editor" id="RTEditor">
    <div class="full-screen" v-show="fullButton">
      <span :title="isFullscreen ? '退出全屏' : '全屏'" @click="toggleFull()">
        <svg-icon :icon-class="isFullscreen ? 'exit-fullscreen' : 'fullscreen'" />
      </span>
    </div>
    <!--手动控制数据同步-->
    <quill-editor
      ref="quillEditor"
      class="editor"
      :content="content"
      :options="option"
      @change="onEditorChange($event)"
    />
    <!--双向数据绑定-->
    <!--    <quill-editor-->
    <!--      ref="quillEditor"-->
    <!--      class="editor"-->
    <!--      v-model="content"-->
    <!--      :options="option"-->
    <!--      @ready="onEditorReady($event)"-->
    <!--      @focus="onEditorFocus($event)"-->
    <!--      @blur="onEditorBlur($event)"-->
    <!--    />-->
    <form action method="post" enctype="multipart/form-data" id="uploadFormMulti">
      <input
        style="display: none"
        :id="uniqueId"
        type="file"
        name="file"
        multiple
        accept="image/jpg, image/jpeg, image/png, image/gif"
        @change="uploadImg('uploadFormMulti')"
      />
    </form>
  </div>
</template>

<script>
import { quillEditor } from 'vue-quill-editor'
import screenfull from 'screenfull'
import { uploadAttach } from '@/api/file'
// 工具栏配置
const toolbarOptions = [
  ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线 -----['bold', 'italic', 'underline', 'strike']
  ['blockquote', 'code-block'], // 引用  代码块-----['blockquote', 'code-block']
  [{ header: 1 }, { header: 2 }], // 1、2 级标题-----[{ header: 1 }, { header: 2 }]
  [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表-----[{ list: 'ordered' }, { list: 'bullet' }]
  [{ script: 'sub' }, { script: 'super' }], // 上标/下标-----[{ script: 'sub' }, { script: 'super' }]
  [{ indent: '-1' }, { indent: '+1' }], // 缩进-----[{ indent: '-1' }, { indent: '+1' }]
  [{ direction: 'rtl' }], // 文本方向-----[{'direction': 'rtl'}]
  [{ size: ['small', false, 'large', 'huge'] }], // 字体大小-----[{ size: ['small', false, 'large', 'huge'] }]
  [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题-----[{ header: [1, 2, 3, 4, 5, 6, false] }]
  [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色-----[{ color: [] }, { background: [] }]
  [{ font: [] }], // 字体种类-----[{ font: [] }]
  [{ align: [] }], // 对齐方式-----[{ align: [] }]
  ['clean'], // 清除文本格式-----['clean']
  ['link', 'image'] // 链接、图片、视频-----['link', 'image', 'video']
]
export default {
  name: 'RTEditor',
  components: { quillEditor },
  props: {
    // 回显内容
    showContent: {
      type: String,
      default: ''
    },
    // 是否禁用
    disabled: {
      type: Boolean,
      default: false
    },
    // 是否显示全屏按钮
    fullButton: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      isFullscreen: false, //是否全屏显示
      content: '',
      uniqueId: 'uniqueId', //上传图片节点Id
      //富文本编辑器配置,详见: https://www.kancloud.cn/liuwave/quill/1409366#bounds_52
      option: {
        bounds: 'document.body', //可以设置为DOM元素或代表DOM元素的CSS选择器,用来包含编辑器的UI元素(比如tooltips等等),当前只考虑左右边界。
        debug: 'warn', //debug的快捷方式。注意,debug是一个静态方法并且可能影响当前页面内Quill编辑器实例。默认只显示警告和错误信息。
        formats: '', //编辑器允许的格式列表白名单。完整的列表,请见Formats。
        //需要引入模块的集合及它们各自的选项。详情见See Modules。
        modules: {
          toolbar: toolbarOptions
        },
        placeholder: '请输入正文', //当编辑器为空时显示的占位符文字。
        readOnly: true, // 是否将编辑器实例设置为只读模式,
        // 当默认的'ql-editor'元素已经被自定义CSS改变,可以设置为DOM元素或代表DOM元素的CSS选择器,指定有滚动条(overflow-y: auto)的容器。
        // 当Quill被设置成自适应高度,需要修复这个滚动时跳动的bug,从而让另一个祖先容器负责滚动。
        scrollingContainer: null,
        strict: true, //在semver的严格解释下,一些改进或修改被要求一个大版本的bump。它们通过strict严格标志来防止对Quill版本号进行小的更改。可以在
        theme: 'snow' //使用主题的名称。这个内置的选项是"bubble"或"snow"。一个无效或错误的值将加载默认的最小化主题。注意,主题的样式表任需要手动包含。详情,请见主题
      }
    }
  },
  computed: {
    //当前富文本实例
    editor() {
      return this.$refs.quillEditor.quill
    }
  },
  mounted() {
    this.init()
    this.initFull()
  },
  beforeDestroy() {
    this.destroyFull()
  },
  methods: {
    init() {
      this.content = this.showContent
      if (this.disabled) {
        this.editor.enable(false)
      }
      let _this = this
      let imgHandler = async function(image) {
        if (image) {
          let fileInput = document.getElementById(_this.uniqueId) //隐藏的file文本ID
          fileInput.click() //加一个触发事件
        }
      }
      _this.editor.getModule('toolbar').addHandler('image', imgHandler)
    },
    //失去焦点事件
    // onEditorBlur(quill) {
    //   console.log('editor blur!', quill)
    // },
    // // 准备富文本编辑器
    // onEditorReady(quill) {
    //   console.log('editor ready!', quill)
    // },
    // //获得焦点事件
    // onEditorFocus(quill) {
    //   console.log('editor focus!', quill)
    // },
    //内容改变事件
    onEditorChange({ quill, html, text }) {
      console.log('editor change!', quill, html, text)
      this.content = html
      this.$emit('change', { html, text })
    },
    toggleFull() {
      if (!screenfull.enabled) {
        this.$message({
          message: '你的浏览器不支持该功能!',
          type: 'warning'
        })
        return false
      }
      const $id = document.getElementById('RTEditor')
      screenfull.toggle($id)
    },
    changeFull() {
      this.isFullscreen = screenfull.isFullscreen
    },
    initFull() {
      if (screenfull.enabled) {
        screenfull.on('change', this.changeFull)
      }
    },
    destroyFull() {
      if (screenfull.enabled) {
        screenfull.off('change', this.changeFull)
      }
    },
    async uploadImg() {
      let _this = this
      // 构造formData对象
      let formData = new FormData()
      formData.append('file', document.getElementById(_this.uniqueId).files[0])
      try {
        //调用上传文件接口
        let queryParam = {
          module: 'editor',
          publicRead: true,
          type: 1 // 1---图片 、 2---附件
        }
        uploadAttach(formData, queryParam).then(res => {
          //返回上传文件的地址
          let url = res.data.url
          if (url != null && url.length > 0) {
            let range = _this.editor.getSelection()
            url = url.indexOf('http') !== -1 ? url : 'http:' + url
            //上传文件成功之后在富文本中回显(显示)
            _this.editor.insertEmbed(range != null ? range.index : 0, 'image', url)
          } else {
            _this.$message.warning('图片上传失败')
          }
          //成功之后,将文件的文本框的value置空
          document.getElementById(_this.uniqueId).value = ''
        })
      } catch ({ message: msg }) {
        document.getElementById(_this.uniqueId).value = ''
        _this.$message.warning(msg)
      }
    }
  }
}
</script>

<style lang="scss">
.r-t-editor {
  width: 100%;
  padding: 20px;
  &:fullscreen {
    background: #ffffff;
    overflow: auto;
    padding: 0;
    .ql-editor {
      height: calc(100vh - 80px);
    }
  }
  .full-screen {
    width: 100%;
    text-align: right;
    border: 1px solid #ccc;
    border-bottom: 0;
    padding: 5px 10px;
    color: #444;
  }
  .editor {
    line-height: normal !important;
  }
}
.ql-snow .ql-editor {
  min-height: 200px;
}
.ql-snow .ql-tooltip {
  position: static;
}
.ql-snow .ql-tooltip[data-mode='link']::before {
  content: '请输入链接地址:';
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  border-right: 0;
  content: '保存';
  padding-right: 0;
}

.ql-snow .ql-tooltip[data-mode='video']::before {
  content: '请输入视频地址:';
}

.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
  content: '14px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='small']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='small']::before {
  content: '10px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='large']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='large']::before {
  content: '18px';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value='huge']::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value='huge']::before {
  content: '32px';
}

.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
  content: '文本';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='1']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
  content: '标题1';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='2']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
  content: '标题2';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='3']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
  content: '标题3';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='4']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
  content: '标题4';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='5']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
  content: '标题5';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value='6']::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
  content: '标题6';
}

.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
  content: '标准字体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='serif']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='serif']::before {
  content: '衬线字体';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value='monospace']::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value='monospace']::before {
  content: '等宽字体';
}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值