vue2 集成quill-editor,自定义插件开发_vue2.0中quill如何添加自定义组件-程序员宅基地

技术标签: vue  前端  vue.js  javascript  

需求介绍

vue2集成富文本编辑器,并开发一个选人插件,选中后加到编辑区域内。

效果展示

安装Vue-Quill-Editor

npm install vue-quill-editor --save

项目中引入

// 导入插件,引用样式
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';

// Vue-Quill-Editor放到组件中
components: {
    quillEditor
},

页面代码

<template>
  <div class="app-quill-editor"> 
      <!--   编辑器   -->
      <quill-editor ref="editorComp" v-model="content" class="quilleditor" :options="editorOption"> </quill-editor>
      <!--   选人列表   -->
      <div id="myPanel" v-if="showMetric" style="position:absolute; top: 80px; left: 10px;background-color: #FFFFFF">
        <el-card class="box-card" style="height: 150px; overflow-y: auto; overflow-x: hidden">
          <div v-for="item in userList" class="box-div" style="width: 210px; height: 30px; background-color: #FFFFFF">
            <el-button type="text" @click="handleClick(item)">
              <span style="float: left; width: 50px;">{
   { item.name }}</span>
              <span style="float: right; color: #8492a6; font-size: 13px; width: 150px; text-align: right">{
   { item.mobile }}</span>
            </el-button>
          </div>
        </el-card>
      </div>
  </div>
</template>

定义变量

insertMetric 声明选人插件

在handlers中控制插件

insertMetric: function () {
  let self = this.handlers.that;
  self.showMetric = !self.showMetric;
  self.quill_this = this;
}
  data() {
    return {
      user: '',
      //父组件传过来
      userList: [],
      // 工具按钮
      editorOption: {
        modules: {
          toolbar: {
            container: [
              ['insertMetric'], //新添加的工具
              ['bold', 'italic', 'underline'],
              [
                {
                  size: ['small', false, 'large', 'huge']
                }
              ],
              [
                {
                  list: 'ordered'
                },
                {
                  list: 'bullet'
                }
              ],
              [
                {
                  color: []
                },
                {
                  background: []
                }
              ],

            ],
            handlers: {
              shadeBox: null,
              that: this,
              insertMetric: function () {
                let self = this.handlers.that;
                self.showMetric = !self.showMetric;
                self.quill_this = this;
              }
            }
          }
        }
      },
      // 提醒
      toolbarTips: [
        {
          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-size',
          title: '字体大小'
        },
        {
          Choice: '.ql-list[value="ordered"]',
          title: '编号列表'
        },
        {
          Choice: '.ql-list[value="bullet"]',
          title: '项目列表'
        },
        {
          Choice: '.ql-align',
          title: '对齐方式'
        },
        {
          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-indent[value="-1"]',
          title: '向左缩进'
        },
        {
          Choice: '.ql-indent[value="+1"]',
          title: '向右缩进'
        },
        {
          Choice: '.ql-header .ql-picker-label',
          title: '标题大小'
        },
        {
          Choice: '.ql-header .ql-picker-item[data-value="1"]',
          title: '标题一'
        },
        {
          Choice: '.ql-header .ql-picker-item[data-value="2"]',
          title: '标题二'
        },
        {
          Choice: '.ql-header .ql-picker-item[data-value="3"]',
          title: '标题三'
        },
        {
          Choice: '.ql-header .ql-picker-item[data-value="4"]',
          title: '标题四'
        },
        {
          Choice: '.ql-header .ql-picker-item[data-value="5"]',
          title: '标题五'
        },
        {
          Choice: '.ql-header .ql-picker-item[data-value="6"]',
          title: '标题六'
        },
        {
          Choice: '.ql-header .ql-picker-item:last-child',
          title: '标准'
        },
        {
          Choice: '.ql-size .ql-picker-item[data-value="small"]',
          title: '小号'
        },
        {
          Choice: '.ql-size .ql-picker-item[data-value="large"]',
          title: '大号'
        },
        {
          Choice: '.ql-size .ql-picker-item[data-value="huge"]',
          title: '超大号'
        },
        {
          Choice: '.ql-size .ql-picker-item:nth-child(2)',
          title: '标准'
        },
        {
          Choice: '.ql-align .ql-picker-item:first-child',
          title: '居左对齐'
        },
        {
          Choice: '.ql-align .ql-picker-item[data-value="center"]',
          title: '居中对齐'
        },
        {
          Choice: '.ql-align .ql-picker-item[data-value="right"]',
          title: '居右对齐'
        },
        {
          Choice: '.ql-align .ql-picker-item[data-value="justify"]',
          title: '两端对齐'
        },
        {
          Choice: '.ql-insertMetric',
          title: '插入用户'
        }
      ],
      // 编辑器内容
      content: '',
      // 是否显示选人插件
      showMetric: false,
      quill_this: this,
    };
  },

逻辑代码

mounted() {
    this.initButton();
},
methods: {
    initButton() {
      document.getElementsByClassName('ql-editor')[0].dataset.placeholder = '';
      for (let item of this.toolbarTips) {
        let tip = document.querySelector('.quill-editor ' + item.Choice);
        if (!tip) continue;
        tip.setAttribute('title', item.title);
      }
      const sourceEditorButton = document.querySelector('.ql-insertMetric');

      sourceEditorButton.innerHTML = '<i class="el-icon-user-solid" style="font-size: 18px; color: black"></i>';
    },
    handleClick(row) {
      this.insert(row);
      this.showMetric = false;
      this.user = ''
    },
    insert(user) {
      const name = user.name;
      let quill_this = this.quill_this;
      let range = quill_this.quill.getSelection(true);

      quill_this.quill.insertEmbed(range.index, 'atusertag', {text:`@${name} `,id: user.id}, Quill.sources.USER);
      quill_this.quill.insertText(range.index + 1, ' ');

      quill_this.quill.setSelection(range.index + 2);
      quill_this.quill.focus()
      quill_this.quill.update()

    },
}

用户组件

此时@用户需要作为一个整体组件,方便删除。新建一个js文件,LinkUserBlot.js

// 引入组件js,并注册
import LinkUserBlot from './LinkUserBlot.js'
Quill.register(LinkUserBlot, true)
import {
    Quill
} from 'vue-quill-editor'

const Embed = Quill.import("blots/embed");
class LinkUserBlot extends Embed {
  static create(value) {
    // console.log('value', value)
    let node = super.create();
    node.innerHTML = value.text
    node.setAttribute('id', value.id);
    node.setAttribute('contenteditable', false);
    node.setAttribute('class', 'at-some-one');
    // @人样式不受影响
    node.setAttribute('style', 'color:#4498F0;text-decoration: none;display: inline-block;font-style: normal;background-color: #fff;margin: 0 2px;');
    return node;
  }
  static value(node) {
    return {
      id: node.getAttribute('id'),
      text: node.innerHTML.trim()
    };
  }
}
LinkUserBlot.blotName = 'atusertag';
LinkUserBlot.tagName = 'span';
LinkUserBlot.className = 'user-at-span';


export default LinkUserBlot

 这两处通过 atusertag 关联

quill_this.quill.insertEmbed(range.index, 'atusertag', {text:`@${name} `,id: user.id}, Quill.sources.USER);
LinkUserBlot.blotName = 'atusertag';

样式

<style lang="scss">
.app-quill-editor {
  position: relative;

  .ql-container {
    height: 200px;
  }
  .el-card__body {
    padding: 10px;
  }
  .box-card {

  }
}
::v-deep {
  @media only screen and (max-width: 1280px) {
    .quilleditor {
      height: 240px !important;
    }
  }
  @media only screen and (max-width: 900px) {
    .quilleditor {
      height: 240px !important;
    }
    .ql-container {
      height: 85%;
    }
  }
}

</style>
<style>
.editor, .ql-toolbar {
  white-space: pre-wrap !important;
  line-height: normal !important;
}
.quill-img {
  display: none;
}
.ql-snow .ql-tooltip[data-mode="link"]::before {
  content: "请输入链接地址:";
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
  border-right: 0px;
  content: "保存";
  padding-right: 0px;
}

.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: "等宽字体";
}
.footer {
  float: right;
  padding: 10px;
}
</style>

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Oct_Somnus/article/details/134240811

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法