天天看點

VUE內建富文本編輯器vue-quill-editor

官方文檔:https://www.kancloud.cn/liuwave/quill/1434140

一、內建方法:

1、先安裝依賴 :進入到項目目錄下,執行   npm install vue-quill-editor --save  或者cnpm安裝。

2、main.js引入:

import VueQuillEditor from 'vue-quill-editor';
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
Vue.use(VueQuillEditor);
           

3、頁面使用:

<template>
  <div class="edit_container">
    <quill-editor v-model="content"></quill-editor>
  </div>
</template>

<script>
import { quillEditor } from "vue-quill-editor"; //調用編輯器
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
export default {
  name: "fuwenben",
  components: {
    quillEditor
  },
  data() {
    return {
      content: `<p></p><p><br></p><ol><li><strong><em>Or drag/paste an image here.</em></strong></li><li><strong><em>rerew</em></strong></li><li><strong><em>rtrete</em></strong></li><li><strong><em>tytrytr</em></strong></li><li><strong><em>uytu</em></strong></li></ol>`
    };
  }
};
</script>


   
           

二、回顯:原樣回顯使用v-html,隻展示文字可以比對下去除不需要的标簽樣式之類的。

1、如我資料庫建立一張表,

CREATE TABLE `t_user_content` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `account` varchar(255) DEFAULT NULL,
  `content` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
           

2、後端:使用者可以在頁面輸入簡介,資料庫存在則更新,否則插入:

@RequestMapping("/getContext")
    public ResponseMessage getContext(){
        JWTUserDTO jwtUser = (JWTUserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UserContext userContext = userService.getContext(jwtUser.getUserName());
        return ResponseMessage.success(userContext);
    }

    @RequestMapping("/addContext")
    public ResponseMessage addContext(@RequestBody UserContext userContext){
        JWTUserDTO jwtUser = (JWTUserDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        userContext.setUserAccount(jwtUser.getUserName());
        userService.addContext(userContext);
        return ResponseMessage.success();
    }
           
@Override
    public void addContext(UserContext userContext) {
        String userAccount = userContext.getUserAccount();
        int count = userDao.getContextByUserAccount(userAccount);
        if(count >0){
            //更新
            userDao.updateContext(userContext);
        }else{
            userDao.insertContext(userContext);
        }
    }

    @Override
    public UserContext getContext(String userName) {
        return userDao.getContext(userName);
    }
           
<select id="getContextByUserAccount" resultType="int">
        select count(1) from t_user_content where account = #{userAccount}
    </select>

    <update id="updateContext">
        update t_user_content set content = #{userContext.content}
        where account =#{userContext.userAccount}
    </update>

    <insert id="insertContext">
        insert into t_user_content(account,content)
        values (#{userContext.userAccount},#{userContext.content})
    </insert>

    <select id="getContext" resultType="com.demo.dto.UserContext">
        select  account userAccount,content
        from t_user_content where  account =#{userName} limit 1
    </select>
           

3、前端:

<template>
  <div class="edit_container">
   
    簡介
    <quill-editor
      v-model="content"
      ref="myQuillEditor"
      :options="editorOption"
      @blur="onEditorBlur($event)"
      @focus="onEditorFocus($event)"
      @change="onEditorChange($event)"
    ></quill-editor>
    <!-- 從資料庫讀取展示 -->
    <p>
      <button @click="submit()">送出</button>
    </p>
  </div>
</template>

<script>
import axios from "axios";
import { quillEditor } from "vue-quill-editor"; //調用編輯器
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";
import { getContext, addContext } from "@/api/user";
export default {
  name: "fuwenben",
  components: {
    quillEditor
  },
  data() {
    return {
      content: `<p></p><p><br></p><ol><li><strong><em>Or drag/paste an image here.</em></strong></li><li><strong><em>rerew</em></strong></li><li><strong><em>rtrete</em></strong></li><li><strong><em>tytrytr</em></strong></li><li><strong><em>uytu</em></strong></li></ol>`,
      editorOption: {}
    };
  },
  methods: {
    onEditorReady(editor) {
      // 準備編輯器
    },
    onEditorBlur() {}, // 失去焦點事件
    onEditorFocus() {}, // 獲得焦點事件
    onEditorChange() {}, // 内容改變事件

    init() {
      getContext().then(res => {
        this.content = res.data.content;
      });
    },

    submit() {
      addContext({ content: this.content }).then(res => {});
    }
  },
  computed: {
    editor() {
      return this.$refs.myQuillEditor.quill;
    }
  },
  created() {
    this.init();
  }
};
</script>


   
           

頁面效果:

VUE內建富文本編輯器vue-quill-editor

如我編輯以上内容,點選儲存,資料庫存儲如下:可以看到圖檔被轉碼成base64了

VUE內建富文本編輯器vue-quill-editor

 重新整理頁面,擷取的編輯框格式正确。

4、說明:回顯問題,可以原樣回顯(在富文本框或者其他地方),也可以隻提取純文字回顯。

<div>
<!--回顯文本-->
<span class="first-marquee">
              {{ contentText }}
            </span>
  <!--原樣回顯-->
  <div class="title-popover" v-html="content" v-show="titleShow"></div>
</div>


 getContent() {
      this.$api[...]({  }).then(data => {
        if (data) {
          this.content= data.content;
          let reg = /<[^>]+>/gi;
          this.contentText = this.content.replace(reg, '');
          this.contentText = this.contentText.replace(/&nbsp;/g, '');
        }
      });
    },
           

三、長度限制:可以使用quill自帶的方法。其中,圖檔會被當成一個字元,換行也會被當成一個字元,當長度超過最大長度時,輸入不了了,光标不可以再往後移動;複制進去的文本,長度超出的會自動删除

<el-form-item label="内容:" prop="messageContent" :required="true">
          <quill-editor
            class="ql-editor-class"
            v-model="formValidate.messageContent"
            :options="editorOption"
            @change="onEditorChange($event)"
          ></quill-editor>
          <span class="wordNumber">{{ TiLength }}/{{ maxLength }}</span>
        </el-form-item>


data(){
  return{
    TiLength: 0,
     maxLength: 100,  
  }
}

 //富文本框内容長度限制
    onEditorChange(e) {
      e.quill.deleteText(this.maxLength, 4);
      if (this.formValidate.content == '') {
        this.TiLength = 0;
      } else {
        this.TiLength = e.quill.getLength() - 1;
      }
    },
           

效果:

VUE內建富文本編輯器vue-quill-editor

四、工具欄自定義:quill支援自定義工具欄,可以删除一些不需要的配置,也可以修改某些配置。

<quill-editor
            class="ql-editor-class"
            v-model="formValidate.messageContent"
            :options="editorOption"
          ></quill-editor>
           

之後按照規則覆寫editorOption即可。

editorOption: {//配置工具欄
        modules: {
          toolbar:  [
            ['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': ['45px','60px','90px'] }],  // 字型大小
            [{ 'header': [1, 2, 3, 4, 5, 6, false] }],// 标題
            [{ 'color': [] }, { 'background': [] }],          // 顔色選擇
            [{ 'font': ['SimSun', 'SimHei','Microsoft-YaHei','KaiTi','FangSong','Arial'] }],// 字型
            [{ 'align': [] }], // 居中
            ['clean']                                         // 清除樣式
          ]
        }
        // 背景顔色 - background
        // 加粗- bold
        // 顔色 - color
        // 字型 - font
        // 内聯代碼 - code
        // 斜體 - italic
        // 連結 - link
        // 大小 - size
        // 删除線 - strike
        // 上标/下标 - script
        // 下劃線 - underline
        // 引用- blockquote
        // 标題 - header
        // 縮進 - indent
        // 清單 - list
        // 文本對齊 - align
        // 文本方向 - direction
        // 代碼塊 - code-block
        // 公式 - formula
        // 圖檔 - image
        // 視訊 - video
        // 清除字型樣式- clean
      }
    }
           

如我去掉了視訊、清楚樣式等幾個工具,且把原來的字型

VUE內建富文本編輯器vue-quill-editor

拓展了一下:

VUE內建富文本編輯器vue-quill-editor

 代碼如下:

<!-- @format -->

<template>
  <div>
    <div class="container">
      <el-form ref="formValidate" :model="formValidate" :rules="ruleValidate" label-position="left" label-width="100px">
        <el-form-item label="内容:" prop="messageContent" :required="true">
          <quill-editor
            class="ql-editor-class"
            v-model="formValidate.messageContent"
            :options="editorOption"
          ></quill-editor>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import { quillEditor, Quill } from 'vue-quill-editor';
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
//設定字型大小
let fontSizeStyle = Quill.import('attributors/style/size'); //引入這個後會把樣式寫在style上
fontSizeStyle.whitelist = ['12px', '14px', '16px'];
Quill.register(fontSizeStyle, true);

//設定字型樣式
let Font = Quill.import('attributors/style/font'); //引入這個後會把樣式寫在style上
let fonts = [false, 'SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial'];
Font.whitelist = fonts; //将字型加入到白名單
Quill.register(Font, true);

export default {
  data() {
    return {
      // 表單資料
      formValidate: {
        messageContent: '',
      },
      // 表單驗證
      ruleValidate: {
        messageContent: [{ required: true, message: '消息内容不能為空!' }]
      },
      //富文本框自定義工具欄
      editorOption: {
        modules: {
          toolbar: [
            ['bold', 'italic', 'underline'], // 加粗,斜體,下劃線
            [{ header: 1 }, { header: 2 }], // 幾級标題
            [{ list: 'ordered' }, { list: 'bullet' }], // 有序清單,無序清單
            [{ script: 'sub' }, { script: 'super' }],
            [{ indent: '-1' }, { indent: '+1' }], // 縮進
            [{ direction: 'rtl' }], // 文字輸入方向
            [{ color: [] }, { background: [] }], // 顔色選擇
            [{ size: ['12px', '14px', '16px']}], // 字型大小
            [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标題
            [{ font: ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial'] }], // 字型
            [{ align: [] }], // 對齊方式
            ['image', 'link'] //圖檔,連結
          ]
        }
      },
    };
  },
 }
  


<!--富文本框-->
<style scoped>
.quill-editor >>> .ql-container {
  min-height: 300px;
}
/** 縮小工具欄下拉框的間距*/
.quill-editor >>> .ql-snow .ql-picker-options .ql-picker-item {
  cursor: pointer;
  display: block;
  padding-bottom: 0px;
  padding-top: 0px;
  line-height: 30px;
}
/*
這裡一定要寫上,是用來把相關改變的配置在工具欄正常顯示
如果不寫,字型樣式的下拉會重複顯示Sans Serif,字型大小的下拉會重複顯示Normal
*/
.quill-editor >>> .ql-picker.ql-font .ql-picker-label[data-value='SimSun']::before,
.quill-editor >>> .ql-picker.ql-font .ql-picker-item[data-value='SimSun']::before {
  content: '宋體';
  font-family: 'SimSun' !important;
}
.quill-editor >>> .ql-picker.ql-font .ql-picker-label[data-value='SimHei']::before,
.quill-editor >>> .ql-picker.ql-font .ql-picker-item[data-value='SimHei']::before {
  content: '黑體';
  font-family: 'SimHei';
}
.quill-editor >>> .ql-picker.ql-font .ql-picker-label[data-value='Microsoft-YaHei']::before,
.quill-editor >>> .ql-picker.ql-font .ql-picker-item[data-value='Microsoft-YaHei']::before {
  content: '微軟雅黑';
  font-family: 'Microsoft YaHei';
}
.quill-editor >>> .ql-picker.ql-font .ql-picker-label[data-value='KaiTi']::before,
.quill-editor >>> .ql-picker.ql-font .ql-picker-item[data-value='KaiTi']::before {
  content: '楷體';
  font-family: 'KaiTi' !important;
}
.quill-editor >>> .ql-picker.ql-font .ql-picker-label[data-value='FangSong']::before,
.quill-editor >>> .ql-picker.ql-font .ql-picker-item[data-value='FangSong']::before {
  content: '仿宋';
  font-family: 'FangSong';
}
.quill-editor >>> .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='12px']::before,
.quill-editor >>> .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='12px']::before {
  content: '12px';
}
.quill-editor >>> .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='14px']::before,
.quill-editor >>> .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='14px']::before {
  content: '14px';
}
.quill-editor >>> .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='16px']::before,
.quill-editor >>> .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='16px']::before {
  content: '16px';
}
</style>
           

五、自定義圖檔上傳:quill自己的圖檔上傳,會被轉成base64,當圖檔過大的時候會導緻字段過長、渲染過慢。方法是禁止quill的圖檔上傳功能,點選圖檔工具時觸發自定義圖檔上傳元件點選事件,然後調用自定義的接口上傳并擷取url,将url寫入到富文本框中即可。隻要圖檔位址正确,在富文本框中會顯示圖檔,而内容實際為url,長度也隻占一個字元。

<div style="display:none" ref="articalImg" class="articalImg">
            <span>
              <label class="button text-overflow" for="messageFile">
                <span>上傳圖檔<i class="el-icon-plus"></i></span>
              </label>
              <form id="messageFileForm" class="upload-form">
                <input
                  ref="messageFile"
                  @change="uploadFile($event)"
                  type="file"
                  id="messageFile"
                  style="position:absolute;clip:rect(0 0 0 0);"
                  accept="image/png"
                  class="upload-label"
                />
              </form>
            </span>
          </div>
          <quill-editor
            class="ql-editor-class"
            ref="myQuillEditor"
            v-model="formValidate.messageContent"
            :options="editorOption"
            @change="onEditorChange($event)"
          ></quill-editor>
          <span class="word-number">{{ TiLength }}/{{ contentMaxLength }}</span>



<script>
import { quillEditor, Quill } from 'vue-quill-editor';
import 'quill/dist/quill.core.css';
import 'quill/dist/quill.snow.css';
import 'quill/dist/quill.bubble.css';
//設定字型大小
let fontSizeStyle = Quill.import('attributors/style/size'); //引入這個後會把樣式寫在style上
fontSizeStyle.whitelist = [
  '14px',
  '16px',
  '18px',
  '20px',
  '28px',
  '36px',
  '42px'
];
Quill.register(fontSizeStyle, true);
//設定字型樣式
let Font = Quill.import('attributors/style/font'); //引入這個後會把樣式寫在style上
let fonts = [false, 'SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial'];
Font.whitelist = fonts; //将字型加入到白名單
Quill.register(Font, true);
//工具欄自定義
const toolbarOptions = [
  ['bold', 'italic', 'underline'], // 加粗,斜體,下劃線
  [{ header: 1 }, { header: 2 }], // 幾級标題
  [{ list: 'ordered' }, { list: 'bullet' }], // 有序清單,無序清單
  [{ indent: '-1' }, { indent: '+1' }], // 縮進
  [{ direction: 'rtl' }], // 文字輸入方向
  [{ color: [] }, { background: [] }], // 顔色選擇
  [
    {
      size: ['14px', '16px', '18px', '20px', '28px', '36px', '42px']
    }
  ], // 字型大小
  [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标題
  [{ font: ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial'] }], // 字型
  [{ align: [] }], // 對齊方式
  ['image', 'link'] //圖檔,連結
];
export default {
  name: 'sendMessage',
  mixins: [BreadCrumb],
  data() {
    return {
      // 表單資料
      formValidate: {
        //内容
        messageContent: ''
      },
      //富文本框自定義工具欄
      editorOption: {
        modules: {
          toolbar: {
            container: toolbarOptions, // 工具欄
            handlers: {
              image: function(value) {
                if (value) {
                  // this.$refs.articalImg.click()
                  document.querySelector('.articalImg .upload-label').click();
                } else {
                  this.quill.format('image', false);
                }
              }
            }
          }
        }
      },
      TiLength: 0,
      contentMaxLength: 1000
    };
  },
  methods: {
    //富文本框内容長度限制
    onEditorChange(e) {
      e.quill.deleteText(this.contentMaxLength, 4);
      if (this.formValidate.content == '') {
        this.TiLength = 0;
      } else {
        this.TiLength = e.quill.getLength() - 1;
      }
    },
    uploadFile(ev) {
      var fileList = ev.target.files;
      let file = fileList[0];
      let formData = new FormData();
      formData.append('file', file);
      //清空本次選擇的檔案
      this.$refs.messageFile.value = '';
      this.$api['file/upload'](formData, {
        headers: {
          'Content-Type': 'multipart/form-data'
        },
        timeout: 300000
      }).then(data => {
        if (data) {
          //插入到富文本框中
          let quill = this.$refs.myQuillEditor.quill;
          console.info(quill);
          // 擷取光标所在位置
          let length = quill.getSelection().index;
          // 插入圖檔,res為伺服器傳回的圖檔連結位址
          quill.insertEmbed(
            length,
            'image',
            data.url
          );
          // 調整光标到最後
          quill.setSelection(length + 1);
        }
      });
    }
  }
};
</script>
           

如圖:

VUE內建富文本編輯器vue-quill-editor

繼續閱讀