最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue2+Quill富文本編輯器詳解

 更新時(shí)間:2025年08月06日 12:18:55   作者:左邊的天堂  
文章指出Quill 2.0.0-dev.4與2.0.2版本存在兼容性問(wèn)題,原因未知,主要步驟包括引入依賴、創(chuàng)建編輯器組件、使用及效果測(cè)試

本例quill使用的版本是2.0.0-dev.4,2.0.2測(cè)試下來(lái)有很多不兼容的地方,原因未知。

1、先引入依賴

npm install quill@2.0.0-dev.4

2、創(chuàng)建編輯器組件

  • components/Editor.vue
<template>
  <div>
    <div class="editor" ref="editor" :style="styles"></div>
  </div>
</template>

<script>
import Quill from "quill";
import "quill/dist/quill.core.css";
import "quill/dist/quill.snow.css";
import "quill/dist/quill.bubble.css";

export default {
  name: "Editor",
  props: {
    /* 編輯器的內(nèi)容 */
    value: {
      type: String,
      default: "",
    },
    /* 高度 */
    height: {
      type: Number,
      default: 600,
    },
    /* 最小高度 */
    minHeight: {
      type: Number,
      default: 400,
    },
  },
  data() {
    return {
      quill: null,
      currentValue: "",
      options: {
        theme: "snow",
        bounds: document.body,
        debug: "warn",
        modules: {
          table: true,
          // 工具欄配置
          toolbar: {
            container: [
              ["wordBox", "bold", "italic", "underline", "strike"], //加粗,斜體,下劃線,刪除線
              ["blockquote", "code-block"], //引用,代碼塊
              [{header: 1}, {header: 2}], // 標(biāo)題,鍵值對(duì)的形式;1、2表示字體大小
              [{list: "ordered"}, {list: "bullet"}], //列表
              [{script: "sub"}, {script: "super"}], // 上下標(biāo)
              [
                {table: 'TD'},
                {'table-insert-row': 'TIR'},
                {'table-insert-column': 'TIC'},
                {'table-delete-row': 'TDR'},
                {'table-delete-column': 'TDC'}
              ],
              [{indent: "-1"}, {indent: "+1"}], // 縮進(jìn)
              [{direction: "rtl"}], // 文本方向
              [{'size': ['12px', '14px', '16px', '20px', '24px', '32px']}], // 字體大小
              [{header: [1, 2, 3, 4, 5, 6, false]}], //幾級(jí)標(biāo)題
              [{color: []}, {background: []}], // 字體顏色,字體背景顏色
              [{'font': ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial']}], //字體
              [{align: []}], //對(duì)齊方式
              ["clean"], //清除字體樣式
              ["link", "image"], //上傳圖片、上傳視頻
            ],
            handlers: {
              //實(shí)現(xiàn)首行縮進(jìn)的功能
              wordBox: function (val) {
                let range = this.quill.getSelection();
                this.quill.insertText(range.index, '\t', {'style': 'text-indent: 2em;'});
              },
              //增加表格
              table: function (val) {
                this.quill.getModule('table').insertTable(2, 3)
              },
              //插入行
              'table-insert-row': function () {
                this.quill.getModule('table').insertRowBelow()
              },
              //插入列
              'table-insert-column': function () {
                this.quill.getModule('table').insertColumnRight()
              },
              //刪除行
              'table-delete-row': function () {
                this.quill.getModule('table').deleteRow()
              },
              //刪除列
              'table-delete-column': function () {
                this.quill.getModule('table').deleteColumn()
              }
            }
          }
        },
        placeholder: "請(qǐng)輸入內(nèi)容",
      },
      // 圖標(biāo)顯示對(duì)應(yīng)的文字提示
      titleConfig: [
        {Choice: '.ql-wordBox', title: '首行縮進(jìn)'},
        {Choice: '.ql-insertMetric', title: '跳轉(zhuǎn)配置'},
        {Choice: '.ql-bold', title: '加粗'},
        {Choice: '.ql-italic', title: '斜體'},
        {Choice: '.ql-underline', title: '下劃線'},
        {Choice: '.ql-header', title: '段落格式'},
        {Choice: '.ql-strike', title: '刪除線'},
        {Choice: '.ql-blockquote', title: '塊引用'},
        {Choice: '.ql-code', title: '插入代碼'},
        {Choice: '.ql-code-block', title: '插入代碼段'},
        {Choice: '.ql-font', title: '字體'},
        {Choice: '.ql-size', title: '字體大小'},
        {Choice: '.ql-list[value="ordered"]', title: '編號(hào)列表'},
        {Choice: '.ql-list[value="bullet"]', title: '項(xiàng)目列表'},
        {Choice: '.ql-direction', title: '文本方向'},
        {Choice: '.ql-header[value="1"]', title: 'h1'},
        {Choice: '.ql-header[value="2"]', title: 'h2'},
        {Choice: '.ql-align', title: '對(duì)齊方式'},
        {Choice: '.ql-color', title: '字體顏色'},
        {Choice: '.ql-background', title: '背景顏色'},
        {Choice: '.ql-image', title: '圖像'},
        {Choice: '.ql-video', title: '視頻'},
        {Choice: '.ql-link', title: '添加鏈接'},
        {Choice: '.ql-formula', title: '插入公式'},
        {Choice: '.ql-clean', title: '清除字體格式'},
        {Choice: '.ql-script[value="sub"]', title: '下標(biāo)'},
        {Choice: '.ql-script[value="super"]', title: '上標(biāo)'},
        {Choice: '.ql-indent[value="-1"]', title: '向左縮進(jìn)'},
        {Choice: '.ql-indent[value="+1"]', title: '向右縮進(jìn)'},
        {Choice: '.ql-header .ql-picker-label', title: '標(biāo)題大小'},
        {Choice: '.ql-align .ql-picker-item:first-child', title: '居左對(duì)齊'},
        {Choice: '.ql-align .ql-picker-item[data-value="center"]', title: '居中對(duì)齊'},
        {Choice: '.ql-align .ql-picker-item[data-value="right"]', title: '居右對(duì)齊'},
        {Choice: '.ql-align .ql-picker-item[data-value="justify"]', title: '兩端對(duì)齊'},
        {Choice: '.ql-table', title: '添加表格'},
        {Choice: '.ql-table-insert-row', title: '插入行'},
        {Choice: '.ql-table-insert-column', title: '插入列'},
        {Choice: '.ql-table-delete-row', title: '刪除行'},
        {Choice: '.ql-table-delete-column', title: '刪除列'},
      ]
    }
  },
  computed: {
    styles() {
      // 設(shè)置寬高
      let style = {width: '1200px'};
      if (this.minHeight) {
        style.minHeight = `${this.minHeight}px`;
      }
      if (this.height) {
        style.height = `${this.height}px`;
      }
      return style;
    },
  },
  watch: {
    value: {
      handler(val) {
        if (val !== this.currentValue) {
          this.currentValue = (val === null || val === '<p><br></p>') ? "" : val;
          if (this.quill) {
            this.quill.clipboard.dangerouslyPasteHTML(this.currentValue);
          }
        }
      },
      immediate: true,
    },
  },
  mounted() {
    this.init();
  },
  beforeDestroy() {
    this.quill = null;
  },
  methods: {
    init() {
      // 初始化	
      const editor = this.$refs.editor;
      this.quill = new Quill(editor, this.options);
      this.quill.clipboard.dangerouslyPasteHTML(this.currentValue);
      this.quill.on("text-change", (delta, oldDelta, source) => {
        let html = this.$refs.editor.children[0].innerHTML;
        if (html.indexOf('<table>') !== -1) {
        //這里是特殊處理,因?yàn)槭青]件模板,保存的html會(huì)丟失表格樣式,需要在內(nèi)容前面加上
         let _class = "<head>"
          +"<style>"
          +"table {table-layout: fixed; width: 100%; border-collapse: collapse; }"
          +"td, th { padding: 2px 5px; border: 1px solid #000; outline: none; display: table-cell; vertical-align: inherit; unicode-bidi: isolate;}"
          +"img { max-width: 100%; height: auto; }"
          +"</style>"
          +"</head>";
          html = _class + html;
        }
        this.currentValue = html;
        const text = this.quill.getText();
        const quill = this.quill;
        this.$emit("input", html);
        this.$emit("on-change", {html, text, quill});
      });
      this.quill.on("text-change", (delta, oldDelta, source) => {
        this.$emit("on-text-change", delta, oldDelta, source);
      });
      this.quill.on("selection-change", (range, oldRange, source) => {
        this.$emit("on-selection-change", range, oldRange, source);
      });
      this.quill.on("editor-change", (eventName, ...args) => {
        this.$emit("on-editor-change", eventName, ...args);
      });
	  // 首行縮進(jìn)的圖標(biāo)
      document.querySelector('.ql-wordBox').innerHTML = '<i class="el-icon-s-unfold"/>'
      // 鼠標(biāo)懸浮在圖標(biāo)上顯示對(duì)應(yīng)的標(biāo)題
      this.titleConfig.forEach(item => {
        const tip = document.querySelector(item.Choice)
        if (tip) {
          tip.setAttribute('title', item.title)
        }
      });
    },
  },
};
</script>

<style lang="less" scoped>
::v-deep {
  .ql-toolbar {
   /* 要與styles()方法中的width保持一致 */
    width: 1200px; 
  }
  /*設(shè)置字體和字體大小*/
  .ql-picker.ql-font .ql-picker-label[data-value=SimSun]::before, .ql-picker.ql-font .ql-picker-item[data-value=SimSun]::before {
    content: "宋體";
    font-family: "SimSun" !important;
  }

  .ql-picker.ql-font .ql-picker-label[data-value=SimHei]::before, .ql-picker.ql-font .ql-picker-item[data-value=SimHei]::before {
    content: "黑體";
    font-family: "SimHei";
  }

  .ql-picker.ql-font .ql-picker-label[data-value=Microsoft-YaHei]::before, .ql-picker.ql-font .ql-picker-item[data-value=Microsoft-YaHei]::before {
    content: "微軟雅黑";
    font-family: "Microsoft YaHei";
  }

  .ql-picker.ql-font .ql-picker-label[data-value=KaiTi]::before, .ql-picker.ql-font .ql-picker-item[data-value=KaiTi]::before {
    content: "楷體";
    font-family: "KaiTi" !important;
  }

  .ql-picker.ql-font .ql-picker-label[data-value=FangSong]::before, .ql-picker.ql-font .ql-picker-item[data-value=FangSong]::before {
    content: "仿宋";
    font-family: "FangSong";
  }

  .ql-picker.ql-header .ql-picker-label[data-value='1']::before, .ql-picker.ql-header .ql-picker-item[data-value='1']::before {
    content: '一級(jí)標(biāo)題';
  }
  .ql-picker.ql-header .ql-picker-label[data-value='2']::before, .ql-picker.ql-header .ql-picker-item[data-value='2']::before {
    content: '二級(jí)標(biāo)題';
  }
  .ql-picker.ql-header .ql-picker-label[data-value='3']::before, .ql-picker.ql-header .ql-picker-item[data-value='3']::before {
    content: '三級(jí)標(biāo)題';
  }
  .ql-picker.ql-header .ql-picker-label[data-value='4']::before, .ql-picker.ql-header .ql-picker-item[data-value='4']::before {
    content: '四級(jí)標(biāo)題';
  }
  .ql-picker.ql-header .ql-picker-label[data-value='5']::before, .ql-picker.ql-header .ql-picker-item[data-value='5']::before {
    content: '五級(jí)標(biāo)題';
  }
  .ql-picker.ql-header .ql-picker-label[data-value='6']::before, .ql-picker.ql-header .ql-picker-item[data-value='6']::before {
    content: '六級(jí)標(biāo)題';
  }
  .ql-picker.ql-header .ql-picker-label::before, .ql-picker.ql-header .ql-picker-item::before {
    content: '標(biāo)準(zhǔn)';
  }

  .ql-picker.ql-size .ql-picker-label[data-value='12px']::before, .ql-picker.ql-size .ql-picker-item[data-value='12px']::before {
    content: '12px';
  }

  .ql-picker.ql-size .ql-picker-label[data-value='14px']::before, .ql-picker.ql-size .ql-picker-item[data-value='14px']::before {
    content: '14px';
  }

  .ql-picker.ql-size .ql-picker-label[data-value='16px']::before, .ql-picker.ql-size .ql-picker-item[data-value='16px']::before {
    content: '16px';
  }

  .ql-picker.ql-size .ql-picker-label[data-value='20px']::before, .ql-picker.ql-size .ql-picker-item[data-value='20px']::before {
    content: '20px';
  }

  .ql-picker.ql-size .ql-picker-label[data-value='24px']::before, .ql-picker.ql-size .ql-picker-item[data-value='24px']::before {
    content: '24px';
  }

  .ql-picker.ql-size .ql-picker-label[data-value='32px']::before, .ql-picker.ql-size .ql-picker-item[data-value='32px']::before {
    content: '32px';
  }

  .ql-snow .ql-picker.ql-size .ql-picker-label[data-value='32px']::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value='32px']::before {
    content: '32px';
  }

 /* 設(shè)置表格操作的幾個(gè)按鈕圖標(biāo),可以在 www.iconfont.cn 找 */
  .ql-toolbar .ql-table-insert-row {
    background-image: url('../assets/icon/insert_row.svg');
    background-size: 14px 14px;
    background-repeat: no-repeat;
    background-position: center;
  }
  .ql-toolbar .ql-table-insert-column {
    background-image: url('../assets/icon/insert_column.svg');
    background-size: 14px 14px;
    background-repeat: no-repeat;
    background-position: center;
  }
  .ql-toolbar .ql-table-delete-row {
    background-image: url('../assets/icon/delete_row.svg');
    background-size: 14px 14px;
    background-repeat: no-repeat;
    background-position: center;
  }
  .ql-toolbar .ql-table-delete-column {
    background-image: url('../assets/icon/delete_column.svg');
    background-size: 14px 14px;
    background-repeat: no-repeat;
    background-position: center;
  }

}
</style>

3、使用

<template>
  <div class="app-container">
	<div class="drawer-bd">
	   <el-form ref="form" :model="form" :rules="rules" label-position="top">
		<el-form-item label="郵件模板" prop="content">
          <editor ref="editor" :value="form.content" v-model="form.content"/>
        </el-form-item>
      </el-form>
    </div>
    <div class="drawer-ft">
      <el-button @click="reset">清 空</el-button>
      <el-button type="primary" @click="submitForm">保 存</el-button>
    </div>
  </div>
</template>
<script>
import Editor from "@/components/Editor";

export default {
  name: 'Demo',
  components: {Editor},
  data() {
  	return {
      // 表單參數(shù)
      form: {
		content: undefined
	  },
	  rules: {
	    content: [
          {required: true, message: '請(qǐng)輸入郵件模板', trigger: 'blur'},
        ],
      },
    }
  },
  mounted() {
    this.$nextTick(() => {
      // 加載數(shù)據(jù)
    })
  },
  methods: {
  	reset() {
  	  // ... ...
  	},
  	submitForm: function () {
      this.$refs["form"].validate(valid => {
        if (valid) {
          // ... ...
        }
      })
    }
  }
}
</script>

4、實(shí)際效果

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 在Vue中使用TypeScript的幾種方式

    在Vue中使用TypeScript的幾種方式

    本文主要介紹了在Vue中使用TypeScript的幾種方式,包括通過(guò)<script lang="ts">結(jié)合defineComponent,使用Composition API + <script setup lang="ts">和TypeScript定義Props和Emits類型,下面就來(lái)詳細(xì)的介紹一下
    2026-05-05
  • Vue動(dòng)態(tài)數(shù)據(jù)實(shí)現(xiàn)?el-select?多級(jí)聯(lián)動(dòng)、數(shù)據(jù)回顯方式

    Vue動(dòng)態(tài)數(shù)據(jù)實(shí)現(xiàn)?el-select?多級(jí)聯(lián)動(dòng)、數(shù)據(jù)回顯方式

    這篇文章主要介紹了Vue動(dòng)態(tài)數(shù)據(jù)實(shí)現(xiàn)?el-select?多級(jí)聯(lián)動(dòng)、數(shù)據(jù)回顯方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • vscode中vue-cli項(xiàng)目es-lint的配置方法

    vscode中vue-cli項(xiàng)目es-lint的配置方法

    本文主要介紹vscode中 vue項(xiàng)目es-lint的配置方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的的朋友參考下吧
    2018-07-07
  • vue?退出登錄?清除localStorage的問(wèn)題

    vue?退出登錄?清除localStorage的問(wèn)題

    這篇文章主要介紹了vue?退出登錄?清除localStorage的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • vue基于mint-ui的城市選擇3級(jí)聯(lián)動(dòng)的示例

    vue基于mint-ui的城市選擇3級(jí)聯(lián)動(dòng)的示例

    本篇文章主要介紹了vue基于mint-ui的城市選擇3級(jí)聯(lián)動(dòng)的示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • Vue中父子組件通訊之todolist組件功能開發(fā)

    Vue中父子組件通訊之todolist組件功能開發(fā)

    這篇文章主要介紹了Vue中父子組件通訊——todolist組件功能開發(fā)的相關(guān)知識(shí),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-05-05
  • vue使用rules實(shí)現(xiàn)表單字段驗(yàn)證

    vue使用rules實(shí)現(xiàn)表單字段驗(yàn)證

    這篇文章主要為大家詳細(xì)介紹了vue使用rules實(shí)現(xiàn)表單字段驗(yàn)證,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • vue如何實(shí)現(xiàn)動(dòng)態(tài)加載腳本

    vue如何實(shí)現(xiàn)動(dòng)態(tài)加載腳本

    這篇文章主要介紹了vue如何實(shí)現(xiàn)動(dòng)態(tài)加載腳本,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 解決vue3?defineProps?引入定義的接口報(bào)錯(cuò)

    解決vue3?defineProps?引入定義的接口報(bào)錯(cuò)

    這篇文章主要為大家介紹了解決vue3?defineProps?引入定義的接口報(bào)錯(cuò)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Vue.js開發(fā)中常見(jiàn)的錯(cuò)誤分析與解決方案

    Vue.js開發(fā)中常見(jiàn)的錯(cuò)誤分析與解決方案

    在現(xiàn)代前端開發(fā)中,Vue.js作為一款漸進(jìn)式JavaScript框架,以其簡(jiǎn)潔的API和響應(yīng)式數(shù)據(jù)綁定機(jī)制深受開發(fā)者喜愛(ài),本文將以一組典型的Vue錯(cuò)誤信息為切入點(diǎn),深入分析問(wèn)題根源,并提供詳細(xì)的解決方案和最佳實(shí)踐,需要的可以了解下
    2025-08-08

最新評(píng)論

尤溪县| 凌云县| 巨野县| 阿坝| 义马市| 江安县| 广东省| 潮安县| 谷城县| 会昌县| 蒙阴县| 南召县| 静海县| 都安| 双桥区| 色达县| 邹城市| 横峰县| 兰考县| 张掖市| 长顺县| 广宁县| 从江县| 德化县| 石景山区| 聂拉木县| 元谋县| 中江县| 阿尔山市| 白玉县| 彰化县| 镇平县| 白玉县| 达尔| 黎城县| 盱眙县| 广汉市| 伽师县| 基隆市| 岳普湖县| 海淀区|