quill富文本编辑器自定义字体、文字大小(编辑器内含element上传组件)


如下是我们需要得到的文字大小和字体的效果:

自定义字体、文字大小JS部分:

//引入Qill插件
import Quill from "quill";

// 自定义字体
let fontFamily = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'pingfang'];
Quill.imports['formats/font'].whitelist = fontFamily;
Quill.register(Quill.imports['formats/font'])

// 自定义文字大小
let fontSize = ['10px', '12px', '14px', '16px', '20px', '24px', '36px']
Quill.imports['attributors/style/size'].whitelist = fontSize;
Quill.register(Quill.imports['attributors/style/size']);

const toolbarOptions = [
  [
    "bold",
    "italic",
    "underline",
    "strike",
    "blockquote",
    "code-block",
    { header: 1 },
    { header: 2 },
    { list: "ordered" },
    { list: "bullet" },
    { indent: "-1" },
    { indent: "+1" },
    { script: "sub" }, // 下标
    { script: "super" }, // 上标
    { align: [] },
    { color: [] },
    { background: [] },
    "link",
    "image",
  ],
  [{ size: fontSize }], // 文字大小
  [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
  [{ font: fontFamily }], // 字体
];

自定义字体、文字大小css部分:

::v-deep{
  /*
    文字大小
  */
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='10px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='10px']::before {
    content: '10px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='12px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='12px']::before {
    content: '12px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='14px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='14px']::before {
    content: '14px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='16px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='16px']::before {
    content: '16px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='20px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='20px']::before {
    content: '20px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='24px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='24px']::before {
    content: '24px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='36px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='36px']::before {
    content: '36px';
  }


  /*
    字体
  */
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='SimSun']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='SimSun']::before {
    content: '宋体';
    font-family: 'SimSun' !important;
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='SimHei']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='SimHei']::before {
    content: '黑体';
    font-family: 'SimHei';
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='Microsoft-YaHei']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='Microsoft-YaHei']::before {
    content: '微软雅黑';
    font-family: '微软雅黑';
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='KaiTi']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='KaiTi']::before {
    content: '楷体';
    font-family: 'KaiTi' !important;
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='FangSong']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='FangSong']::before {
    content: '仿宋';
    font-family: 'FangSong';
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='Arial']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='Arial']::before {
    content: 'Arial';
    font-family: 'Arial';
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='pingfang']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='pingfang']::before {
    content: '苹方';
    font-family: '苹方';
  }
  // 设置每个字体的css字体样式
  .ql-font-SimSun {
    font-family: 'SimSun';
  }
  .ql-font-SimHei {
    font-family: 'SimHei';
  }
  .ql-font-Microsoft-YaHei {
    font-family: '微软雅黑';
  }
  .ql-font-KaiTi {
    font-family: 'KaiTi';
  }
  .ql-font-FangSong {
    font-family: 'FangSong';
  }
  .ql-font-Arial {
    font-family: 'Arial';
  }
  .ql-font-pingfang {
    font-family: '苹方';
  }

  /*
    标题  
  */
  .ql-snow .ql-picker.ql-header .ql-picker-label::before,
  .ql-snow .ql-picker.ql-header .ql-picker-item::before {
    content: "文本" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
}

组件完整代码(含element上传组件功能):

<template>
  <div>
    
    <el-upload
      id="upload"
      class="editor-upload"
      :action="uploadUrl"
      :data="uploadData"
      name="file"
      :headers="headers"
      :show-file-list="false"
      :on-success="uploadSuccess"
      :on-error="uploadError"
      :before-upload="beforeUpload"
    >
    el-upload>

    
    <quill-editor
      class="editor"
      v-model="content"
      ref="myQuillEditor"
      :options="editorOption"
      @blur="onEditorBlur($event)"
      @focus="onEditorFocus($event)"
      @change="onEditorChange($event)"
    >
    quill-editor>
  div>
template>

<script>
import { mapGetters } from "vuex";
//引入Qill插件
import Quill from "quill";

// 自定义字体
let fontFamily = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'pingfang'];
Quill.imports['formats/font'].whitelist = fontFamily;
Quill.register(Quill.imports['formats/font'])

// 自定义文字大小
let fontSize = ['10px', '12px', '14px', '16px', '20px', '24px', '36px']
Quill.imports['attributors/style/size'].whitelist = fontSize;
Quill.register(Quill.imports['attributors/style/size']);

const toolbarOptions = [
  [
    "bold",
    "italic",
    "underline",
    "strike",
    "blockquote",
    "code-block",
    { header: 1 },
    { header: 2 },
    { list: "ordered" },
    { list: "bullet" },
    { indent: "-1" },
    { indent: "+1" },
    { script: "sub" }, // 下标
    { script: "super" }, // 上标
    { align: [] },
    { color: [] },
    { background: [] },
    "link",
    "image",
  ],
  [{ size: fontSize }], // 文字大小
  [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
  [{ font: fontFamily }], // 字体
];
export default {
  name: "Editor",
  data() {
    return {
      content: null,
      uploadUrl: process.env.VUE_APP_BASE_URL + "/pa/material/upload",
      headers: { Authorization: "Bearer " + this.$cookieGet("TOKEN") },
      editorOption: {
        modules: {
          toolbar: {
            container: toolbarOptions,
            handlers: {
              // 编辑器菜单点击图片上传事件
              image: function (value) {
                if (value) {
                  // 调用element上传组件
                  document.querySelector("#upload input").click();
                }
              },
            },
          },
        },
      },
    };
  },
  computed: {
    ...mapGetters(["officialInfo"]),
    // 图片上传的参数
    uploadData() {
      return { type: 1, id: this.officialInfo.id };
    },
  },
  methods: {
    onEditorBlur() {
      this.$emit("on-blur", this.content);
    },
    onEditorFocus() {
      //获得焦点事件
    },
    onEditorChange() {
      //内容改变事件
    },
    // 上传图片前
    beforeUpload(file) {
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isLt2M) {
        this.$message.error("上传图片不能大于 2M");
      }
    },
    // 上传图片成功
    uploadSuccess(res, file) {
      if (res.code == 200) {
        let img = `<img src="https:${res.data.url}" />`;
        this.content = (this.content || "") + img;
      }
    },
    // 上传图片失败
    uploadError(res, file) {
      console.log(res);
    },
    // 更新文本编辑器内容
    upDateContent(v) {
      this.content = v;
    },
  },
};
script>

<style lang="scss" scoped>
::v-deep {
  .ql-container {
    height: 300px;
  }
  .editor-upload {
    display: none;
  }
  /*
    文字大小
  */
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='10px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='10px']::before {
    content: '10px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='12px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='12px']::before {
    content: '12px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='14px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='14px']::before {
    content: '14px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='16px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='16px']::before {
    content: '16px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='20px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='20px']::before {
    content: '20px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='24px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='24px']::before {
    content: '24px';
  }
  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='36px']::before,
  .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='36px']::before {
    content: '36px';
  }

  /*
    字体
  */
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='SimSun']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='SimSun']::before {
    content: '宋体';
    font-family: 'SimSun' !important;
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='SimHei']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='SimHei']::before {
    content: '黑体';
    font-family: 'SimHei';
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='Microsoft-YaHei']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='Microsoft-YaHei']::before {
    content: '微软雅黑';
    font-family: '微软雅黑';
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='KaiTi']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='KaiTi']::before {
    content: '楷体';
    font-family: 'KaiTi' !important;
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='FangSong']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='FangSong']::before {
    content: '仿宋';
    font-family: 'FangSong';
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='Arial']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='Arial']::before {
    content: 'Arial';
    font-family: 'Arial';
  }
  .ql-snow .ql-picker.ql-font .ql-picker-label[data-value='pingfang']::before,
  .ql-snow .ql-picker.ql-font .ql-picker-item[data-value='pingfang']::before {
    content: '苹方';
    font-family: '苹方';
  }
  // 设置每个字体的css字体样式
  .ql-font-SimSun {
    font-family: 'SimSun';
  }
  .ql-font-SimHei {
    font-family: 'SimHei';
  }
  .ql-font-Microsoft-YaHei {
    font-family: '微软雅黑';
  }
  .ql-font-KaiTi {
    font-family: 'KaiTi';
  }
  .ql-font-FangSong {
    font-family: 'FangSong';
  }
  .ql-font-Arial {
    font-family: 'Arial';
  }
  .ql-font-pingfang {
    font-family: '苹方';
  }

  /*
    标题  
  */
  .ql-snow .ql-picker.ql-header .ql-picker-label::before,
  .ql-snow .ql-picker.ql-header .ql-picker-item::before {
    content: "文本" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
  .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" !important;
  }
}
style>
vue