vue后台管理系统项目-vue-quill-editor实现富文本编辑器功能

news2024/11/16 23:59:57

富文本编辑器功能实现详细过程

目录

富文本编辑器功能实现详细过程

1.安装富文本插件

2.实现效果

3.实现详细过程 可直接使用

全局引入 

局部引入

配置option

扩展需求 自定义配置文字大小


1.安装富文本插件

npm install vue-quill-editor --save
//或者
yarn add vue-quill-editor

2.实现效果

3.实现详细过程 可直接使用

全局引入 

main.js注册

import quillEditor 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)

局部引入

vue页面中引用

 import {
    quillEditor
  } from "vue-quill-editor";
  import "quill/dist/quill.core.css";
  import "quill/dist/quill.snow.css";
  import "quill/dist/quill.bubble.css";
components: {
      quillEditor
},

重要代码

这里上传图片功能使用了vant-ui框架上传代码,因为项目有特殊要求,也可以使用默认富文本自带的功能,这里也可使用自定义上传图片功能,都会一一介绍使用,记得自定义的图片上传功能图标覆盖默认编辑的图标,根据项目需求自行选择使用

<el-col :span="24">
                <el-form-item style="height:600px;">
                  <quill-editor v-model="createModelForm.content" ref="myQuillEditor" style="height: 500px;"
                    :options="contentOption">
                  </quill-editor>
                  <!-- 自定义上传图片弹窗 -->
                  <!-- <el-upload
                      ref="ztphotoUrl"
                      class="upload-demo ivu-upload"
                      :action="baseUrl + '/file/upload'"
                      :headers="{ Authorization: token }"
                      :on-success="handleZtSuccess"
                      accept="image/jpeg,image/png,image/jpg"
                      list-type="picture">
                      <el-button v-throttle size="small" type="primary" class="ivu-btn">点击上传</el-button>
                    </el-upload> -->
                  <van-uploader :after-read="afterCard" :before-read="beforeRead" accept="image/*" class="uploadfile"
                    :max-size="10240 * 1024" @oversize="onOversize">
                    <img src="../../assets/upload.png">
                  </van-uploader>
                </el-form-item>
              </el-col>

配置option

  • 富文本全部功能配置

效果

// 富文本编辑器配置
      contentOption: {
        modules: {
          toolbar: [
            ['bold', 'italic', 'underline', 'strike'], // 加粗 斜体 下划线 删除线
            ['blockquote', 'code-block'], // 引用  代码块
            [{ header: 1 }, { header: 2 }], // 1、2 级标题
            [{ list: 'ordered' }, { list: 'bullet' }], // 有序、无序列表
            [{ script: 'sub' }, { script: 'super' }], // 上标/下标
            [{ indent: '-1' }, { indent: '+1' }], // 缩进
            [{ direction: 'rtl' }], // 文本方向
            [{ size: ['12', '14', '16', '18', '20', '22', '24', '28', '32', '36'] }], // 字体大小
            [{ header: [1, 2, 3, 4, 5, 6] }], // 标题
            [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
            // [{ font: ['songti'] }], // 字体种类
            [{ align: [] }], // 对齐方式
            ['clean'], // 清除文本格式
            ['image', 'video'] // 链接、图片、视频
          ]
        },
        placeholder: '请输入正文'
      },
  • 自定义配置使用

效果

本项目选择自定义配置

const toolbarOptions = [
    ['image'], //上传图片、上传视频
    ['bold', 'strike', 'underline'],
    [{
      'color': []
    }], // 字体颜色
    [{
      'align': []
    }], //对齐方式
    [{
      'size': [false, '16px', '18px', '20px']
    }], //字体大小
    ['clean'], //清除字体样式


  ];
contentOption: {
          placeholder: "请输入图文详情",
          // // 编辑器的配置
          // theme: "bubble"
          modules: {
            clipboard: {
              // 粘贴版,处理粘贴时候的自带样式
              matchers: [
                [Node.ELEMENT_NODE, this.handleCustomMatcher]
              ],
            },
            toolbar: {
              container: toolbarOptions, // 工具栏
              handlers: {
                'image': (value) => {
                  if (value) {
                    // 调用自定义上传图片
                    // document.querySelector('.ivu-btn').click();
                    this.afterCard();
                  } else {
                    this.quill.format('image', false);
                  }
                }
              }
            }
          }
        },
  • 自定义使用vant-ui图片上传功能实现过程

这里有使用图片压缩上传功能,图片压缩封装功能可查看vue实现文件上传压缩优化处理文章使用

// 文件压缩实现
      afterCard(file) {
        console.log(file, "1223213")
        this.$imgUpload.imgZip(file).then(resData => {
          const formData = new FormData();
          formData.append("file", resData);
          // 请求接口上传图片到服务器
          upload(formData).then(res => {
            console.log(res.data, "图片上传");
            showLoading();
            if (res.code == 200) {
              let quill = this.$refs.myQuillEditor.quill;
              // 设置焦点
              quill.focus();
              // 获取光标所在位置
              let length = quill.getSelection().index;
              // 插入图片,res为服务器返回的图片链接地址
              quill.insertEmbed(length, 'image', this.$baseImgUrl + res.data);
              // 调整光标到最后
              quill.setSelection(length + 1);
              hideLoading();
              let toastTimer = setTimeout(() => {
                this.$message.success('上传成功');
                clearTimeout(toastTimer);
              }, 0)
            } else {
              this.$message.warning('上传失败,请重新上传');
              hideLoading();
            }
          })
        });
      },
      
    // 限制上传大小图片
      onOversize(file) {
        console.log(file, "file");
        this.$message.warning("文件大小不能超过 10M");
      },

      // 上传之前的图片验证
      beforeRead(file) {
        console.log(file, "file,123");
        if (this.$utils.isImage(file.name)) {
          return true;
        } else {
          this.$message.warning("图片格式不正确");
        }
      },
  • 自定义使用element上传功能
// 自定义上传图片
      handleZtSuccess(res) {
        console.log(res);
        const imgType = res.data.split(".")[1];
        console.log(imgType, "图片格式");
        if (imgType == "jpeg" || imgType == "png" || imgType == "jpg") {
          showLoading();
          let quill = this.$refs.myQuillEditor.quill;
          // 如果上传成功
          if (res.data) {
            // 获取光标所在位置
            let length = quill.getSelection().index;
            // 插入图片,res为服务器返回的图片链接地址
            quill.insertEmbed(length, 'image', this.$baseImgUrl + res.data);
            // 调整光标到最后
            quill.setSelection(length + 1);
            hideLoading();
          } else {
            hideLoading();
            this.$message.error('图片插入失败');
            return;
          }
        } else {
          this.$message.warning("图片格式不正确")
          return;
        }

      },
  • 粘贴版,处理粘贴时候的自带样式

粘贴文字样式(包括背景色和文字颜色等)处理方式

粘贴图片时候不能直接复制本地图片,如果复制本地图片,编辑器识别不了,可以选择上传或者复制网络图片

// 粘贴版,处理粘贴时候的自带样式
matchers: [
  [Node.ELEMENT_NODE, this.handleCustomMatcher]
],
handleCustomMatcher(node, Delta) {
        let ops = []
        Delta.ops.forEach(op => {
          if (op.insert && typeof op.insert === 'string') { // 如果粘贴了图片,这里会是一个对象,所以可以这样处理
            ops.push({
              insert: op.insert,
              attributes: op.attributes //文字样式(包括背景色和文字颜色等)
            })
          } else {
            if (op.insert.image.includes('data:image/png;')) { //本地图片会使文件file开头
              this.$message.warning('不允许粘贴本地图片,请手动上传或者复制网络图片')
            } else {
              ops.push({
                insert: op.insert,
              })
            }
          }
        })
        Delta.ops = ops
        return Delta
      },

扩展需求 自定义配置文字大小

默认编辑器字体只有几种大小可以选择,满足不了产品的需求,主要是需要更改配置文件,以及对应的CSS和js文件。

改变 toolbarOptions的配置项

const toolbarOptions = [
//  原本是 'small',fasle,'large','huge',改成自己想要设置的大小,这会改变页面下拉框的个数以及每个选项的data-value值,插件的js会根据data-value的值去增加对应的class类名。 
[{'size': ['10px', '12px', '14px', '16px' ,'18px', '20px', '22px', '24px', '26px', '32px', '48px']}], 
]

再到node_modules下面找到 quill, 对目录dist 下面的 css文件和 js文件进行修改。

修改quill.core.js

// small,large,huge 这三个是默认的,可以删可以留。后面必须增加和editor配置项一样。
whitelist: ['small', 'large', 'huge','8px','10px','12px','14px','16px','18px','20px','22px','24px','26px','32px','48px']

修改quill.js

// 跟quill.core.js 同理,修改下面两项,huge及之前都是默认的
whitelist: ['small', 'large', 'huge','8px','10px','12px','14px','16px','18px','20px','22px','24px','26px','32px','48px']
var SIZES = ['small', false, 'large', 'huge','8px','10px','12px','14px','16px','18px','20px','22px','24px','26px','32px','48px'];

修改quill.bubble.css

// 需要全部增加一下css选项,需要注意的是data-value=如果是接数字要有引号,字符串可以不带引号
//10px,12px等等新设置的大小都要设置相应的类名字体大小
.ql-editor .ql-size-8px {
    font-size: 8px;
}
// select选择的字体大小
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value="8px"]::before {
    font-size: 8px;
}
.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value="8px"]::before,
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value="8px"]::before {
    content: '8px';    
}

修改quill.core.css 

// 需要全部增加一下css选项
.ql-editor .ql-size-10px {
    font-size: 10px;
}

修改quill.snow.css 

// 需要全部增加一下css选项
.ql-editor .ql-size-8px {
    font-size: 8px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="8px"]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="8px"]::before {
    content: '8px';
}
// select选择的字体大小
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="8px"]::before {
    font-size: 8px;
}

如有疑问,可在文章下留言评论,看到后会及时 回复。

⭐️⭐️⭐️  作者:船长在船上
🚩🚩🚩  主页:来访地址船长在船上的博客
🔨🔨🔨  简介:CSDN前端领域博客专家,CSDN前端领域优质创作者,资深前端开发工程师,专注web前端领域开发,在CSDN分享工作中遇到的问题以及问题解决方法和对项目开发的实际案例总结以及新技术的认识。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/113675.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI城管自动识别摊贩占道经营出店经营行为

AI城管自动识别摊贩占道经营出店经营行为通过pythonyolov7对现场画面自动AI实时监测&#xff0c;当监测到流动商贩占道经营违规摆摊出店经营时时&#xff0c;立即告警。Python是一种由Guido van Rossum开发的通用编程语言&#xff0c;它很快就变得非常流行&#xff0c;主要是因…

论多窗口相互关联下window.open打开已在的窗口时只激活不刷新的实现方案

前端博主&#xff0c;热衷各种前端向的骚操作&#xff0c;经常想到哪就写到哪&#xff0c;如果有感兴趣的技术和前端效果可以留言&#xff5e;博主看到后会去代替大家踩坑的&#xff5e; 主页: oliver尹的主页 格言: 跌倒了爬起来就好&#xff5e; 来个关注吧&#xff0c;点个赞…

Springboot+Netty实现基于天翼物联网平台CTWing(AIOT)终端TCP协议(透传模式)-设备终端(南向设备)

电信的天翼物联网平台CTWing(AIOT)原先是我们俗称的aep&#xff0c;主要用于接入nb-iot设备&#xff0c;当然也可以接入其他的设备&#xff0c;在熟悉AIOT平台后&#xff0c;做后端的我有时候急需终端样品(智能门禁&#xff0c;支付识别终端&#xff0c;CPE终端&#xff0c;考勤…

使用 Swift/SwiftUI 的音频可视化

IOS 应用程序中的音频可视化是一项流行的功能,在实现聊天功能时可能需要它。将它添加到我最近的项目之一时,我个人遇到了一些问题。 你们中的一些人可能在开发包含聊天功能的应用程序时遇到过问题,其中某些消息可能包含音频。这些消息需要在应用程序内进行适当的音频可视化,…

【算法题解】3. 颠倒二进制位

文章目录题目解法一解题思路代码实现复杂度分析解法二解题思路代码实现复杂度分析解法三解题思路代码实现复杂度分析题目 颠倒给定的 32 位无符号整数的二进制位。来自&#xff1a;leetcode 解法一 解题思路 取 n 的最低位&#xff0c;赋值给 ans 的最低位&#xff08;ans 初…

mybatis 多对一查询的处理方式,1.按照查询嵌套处理(子查询),2、按照结果嵌套处理(连表查询)

多对一查询 1、实体类 Student实体类&#xff1a; public class Student { private int id; private String name; private Teacher teacher;//对象属性}Teacheer 实体类&#xff1a; public class Teacher { private int id; private String name;2、Mybatis配置文件mybatis…

FastDDS(4)安装步骤

eProsima Fast DDS for Linux的最新二进制安装版本可在eProssma网站找到。 eProsima Fast DDSSpecialized on high performance middleware. Check out our comparatives such as Apache Thrift vs Protocol Buffers vs Fast Buffers or ZMQ vs Fast RTPS.https://www.eprosim…

从一道经典题来弄懂Eventloop(搞不懂算我输)

前言 时间不知不觉来到了11月底&#xff0c;马上也要准备一下寒假的实习了。 最近打算把面试中的一些拦路虎给解决掉&#xff01;&#xff01; 先拿臭名昭著的Eventloop开刀~ 经典题 async function foo() {console.log(foo) } async function bar() {console.log(bar start…

RabbitMQ:基本消息模型

单生产单消费模型&#xff0c;即基本消息模型或简单消费模型&#xff0c;即完成基本的一对一消息转发。 RabbitMQ 单生产单消费模型主要有以下三个角色构成&#xff1a; 生产者&#xff08;producer/ publisher&#xff09;&#xff1a;一个发送消息的用户应用程序。消费者&…

JS面试题--JavaScript数据类型

数据类型 1.JavaScript有哪些数据类型&#xff0c;它们的区别&#xff1f; JavaScript共有八种数据类型&#xff0c;分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。 其中 Symbol 和 BigInt 是ES6 中新增的数据类型&#xff1a; ● Symbol 代表…

Linux系统基础——程序和进程

代码&#xff0c;程序&#xff0c;进程 特此说明: 刘超的趣谈linux操作系统是比较重要的参考资料&#xff0c;本文大部分内容和图片来源于这个专栏。 1 实验环境 运行一个demo&#xff0c;主要功能是主进程通过系统调用fork一个新的进程&#xff0c;子进程功能是加载二进制文件…

背包模型~

背包模型 概述 ​ 最长上升子序列&#xff1a;序列DP&#xff08;相邻两个被选择的有关系&#xff09; 背包问题&#xff1a;组合DP&#xff0c;在全局的考虑之下最小 f[i][j]&#xff1a;i 表示搞了多少&#xff0c;j 表示限制 集合&#xff1a;所有仅仅从前 i 个物品当…

论文推荐:CCNet用于语义分割的交叉注意力

CCNet&#xff0c; Transformer递归交叉自注意力&#xff0c;比非局部神经网络更有效。华中科技大学、地平线、ReLER 和伊利诺伊大学香槟分校联合研发 论文提出了交叉网络 (CCNet)&#xff0c;对于每个像素&#xff0c;CCNet 中的一个新的交叉注意力模块收集其交叉路径上所有像…

智慧路口:未来都市的智能节点

摘要交通路口是部署未来智慧城市的计算、通信和情报服务的最合适地点。需要收集和处理的大量数据&#xff0c;再加上隐私和安全问题&#xff0c;促使边缘计算范式的使用&#xff0c;这种范式与大都市的物理交叉路口很好地吻合。本文主要针对高带宽、低时延的应用&#xff0c;在…

2007-2022年消费者信心、满意度、预期指数月度数据(CCI、CEI、CSI、CGPI)

根据企业商品价格指数与消费者信心指数、消费者满意指数、消费者预期指数的月度数据&#xff0c;可以探究商品价格对消费者信心的影响作用和作用机制。 商品价格与消费者信心的三类细分指数均具有滞后二阶关联&#xff0c;其中&#xff0c;商品价格对对消费者预期指数的影响作…

IndexedDB的包装器JsStore - 实现登录功能及事务处理

JsStore是IndexedDB的包装器。它提供了简单的SQL像api&#xff0c;这是容易学习和使用。 IndexedDb查询可以在web worker内部执行&#xff0c;JsStore通过提供一个单独的worker文件来保持这种功能。 最近有位叫Pioneer网友一直在问我关于事务的实现方式&#xff0c;关于…

谷粒学院——Day13【微信扫描登录】

OAuth2 OAuth2的使用场景 一、OAuth2解决什么问题 1. OAuth2提出的背景 照片拥有者想要在云冲印服务上打印照片&#xff0c;云冲印服务需要访问云存储服务上的资源。 2. 图例 资源拥有者&#xff1a;照片拥有者。 客户应用&#xff1a;云冲印。 受保护的资源&#xff…

Python pandas库|任凭弱水三千,我只取一瓢饮(2)

上一篇链接&#xff1a; Python pandas库&#xff5c;任凭弱水三千&#xff0c;我只取一瓢饮&#xff08;2&#xff09;_Hann Yang的博客-CSDN博客 I~Q&#xff1a; Function10~25 Types[Function][9:25] [infer_freq, interval_range, isna, isnull, json_normalize, lres…

④【Maven】Maven的构建命令

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Maven的构建命令一、注意二、&#x1f680;清理…

指针与数组的联系与区别【一万六千字超详解】

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;《初识C语言》 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录前言数组的性质1.1 数组的内存布局1…