Vue3使用vue-quill富文本编辑器

news2024/9/28 7:39:07

安装依赖

npm install @vueup/vue-quill quill quill-image-uploader

自定义字体

把自定义字体样式放入font.css中在main.js中导入

.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";
}
.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: "Microsoft YaHei";
}
.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";
}
.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=Times-New-Roman]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=Times-New-Roman]::before {
	content: "Times New Roman";
	font-family: "Times New Roman";
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=sans-serif]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=sans-serif]::before {
	content: "sans-serif";
	font-family: "sans-serif";
}
 
.ql-font-SimSun {
  	font-family: "SimSun";
}
.ql-font-SimHei {
  	font-family: "SimHei";
}
.ql-font-Microsoft-YaHei {
  	font-family: "Microsoft YaHei";
}
.ql-font-KaiTi {
  	font-family: "KaiTi";
}
.ql-font-FangSong {
  	font-family: "FangSong";
}
.ql-font-Arial {
  	font-family: "Arial";
}
.ql-font-Times-New-Roman {
  	font-family: "Times New Roman";
}
.ql-font-sans-serif {
  	font-family: "sans-serif";
}

注册自定义字体到quill

案例

<template>
  <div class="publish-form-container">
    <div class="publish-form">
      <form @submit.prevent="submitForm">
        <div class="form-group">
          <label for="content">内容</label>
          <QuillEditor v-model="content" :options="editorOption" class="quill-editor" />
        </div>
        <button type="submit" class="submit-btn">提交</button>
      </form>
    </div>
  </div>
</template>

<script>
import { QuillEditor, Quill } from '@vueup/vue-quill';
import ImageUploader from 'quill-image-uploader';
import '@vueup/vue-quill/dist/vue-quill.snow.css';

// 注册自定义字体到 Quill
const Font = Quill.import('formats/font');
Font.whitelist = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'Times-New-Roman', 'sans-serif'];
Quill.register(Font, true);

// 注册图片上传模块
Quill.register("modules/imageUploader", ImageUploader);

// 模拟上传API
const uploadFileAPI = async (fileData) => {
  // 模拟上传返回URL
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ data: { filePath: 'https://lalallalal.com/' + fileData.file.name } });
    }, 1000);
  });
};

// 将本地文件转换为URL
const getLocalImageURL = (file) => {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      resolve(e.target.result);
    };
    reader.readAsDataURL(file);
  });
};

export default {
  components: {
    QuillEditor,
  },
  data() {
    return {
      title: '',
      type: '',
      content: '',
      editorOption: {
        modules: {
          imageUploader: {
            upload: async (file) => {
              const localUrl = await getLocalImageURL(file);
              return localUrl; // 返回本地图片的 URL 进行预览
            },
          },
          toolbar: [
            [{ font: Font.whitelist }], // 字体
            ['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: ['small', false, 'large', 'huge'] }], // 文字大小
            [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题大小
            [{ color: [] }, { background: [] }], // 字体颜色,背景颜色
            [{ align: [] }], // 对齐
            ['clean'], // 清除格式
            ['link', 'image', 'video'], // 链接,图片,视频
          ],
        },
      },
    };
  },
  methods: {
    // 提交表单方法
    async submitForm() {
      // 创建虚拟 DOM 来解析内容
      const parser = new DOMParser();
      const doc = parser.parseFromString(this.content, 'text/html');

      // 查找所有的本地图片
      const images = doc.querySelectorAll('img');
      const imageUploadPromises = [];

      images.forEach((img) => {
        const localSrc = img.getAttribute('src');
        
        // 如果是本地图片,上传图片并替换URL
        if (localSrc.startsWith('data:')) {
          const uploadPromise = uploadFileAPI({ file: this.dataURLtoFile(localSrc, 'image.png') }).then((res) => {
            img.setAttribute('src', res.data.filePath); // 替换成服务器上的图片URL
          });
          imageUploadPromises.push(uploadPromise);
        }
      });

      // 等待所有图片上传完成后提交表单
      try {
        await Promise.all(imageUploadPromises);

        // 上传完成后,更新内容
        const updatedContent = doc.body.innerHTML;

        const payload = {
          title: this.title,
          content: updatedContent,
          type: this.type,
        };

        console.log("提交的内容:", payload);

        const response = await fetch("/api/posts", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(payload),
        });
        const data = await response.json();
        console.log("发布成功", data);
      } catch (error) {
        console.error("发布失败", error);
      }
    },

    // 将 dataURL 转换为 File 对象的辅助函数
    dataURLtoFile(dataurl, filename) {
      const arr = dataurl.split(',');
      const mime = arr[0].match(/:(.*?);/)[1];
      const bstr = atob(arr[1]);
      let n = bstr.length;
      const u8arr = new Uint8Array(n);
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, { type: mime });
    },
  },
};
</script>

<style lang="less" scoped>
//TODO
</style>

参考:在vue中Quill富文本编辑器的使用(主题、自定义工具栏、自定义字体选项、图片拖拽上传、图片改变大小)_quill-editor修改工具栏图标颜色-CSDN博客

Vue3使用vue-quill富文本编辑器并实现图片自定义上传替换默认base64格式图片_vue3 quill-CSDN博客

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

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

相关文章

GitLab发送邮件功能详解:如何配置自动化?

GitLab发送邮件的设置指南&#xff1f;怎么优化GitLab发送邮件&#xff1f; GitLab作为一个强大的代码管理平台&#xff0c;不仅提供了代码托管、CI/CD等功能&#xff0c;还集成了发送邮件的功能&#xff0c;使得开发团队能够及时获取项目动态。AokSend将详细介绍如何配置GitL…

暗黑破坏神4第六赛季开荒攻略,如何高效开荒刷图打装备?

暗黑破坏神4的第六赛季将于10月8日开启&#xff01;要是你总觉得电脑开荒刷图打装备效率低&#xff0c;想知道有什么办法在手机上玩暗黑破坏神4&#xff1f;那这款专为游戏玩家打造的远程控制软件——网易GameViewer远程&#xff0c;就太适合你了&#xff01;不仅可以在手机上玩…

Linux下文件/目录操作的相关函数

1.文件系统 把一个磁盘分成一个或多个分区。每个分区可用包含一个文件系统 文件系统是&#xff0c;一组规则&#xff0c;规定对文件的存储及读取的一般方法。文件系统在磁盘格式化过程中指定。 常见的文件系统有&#xff1a;fat32 ntfs exfat ext2 、ext3 、ext4 inode是固定…

WSL进阶体验:gnome-terminal启动指南与中文显示问题一网打尽

起因 我们都知道 wsl 启动后就死一个纯命令行终端&#xff0c;一直以来我都是使用纯命令行工具管理Linux的。今天看到网上有人在 wsl 中启动带图形界面的软件。没错&#xff0c;就是在wsl中启动带有图形界面的Linux软件。比如下面这个编辑器。 ​​ 出于好奇&#xff0c;我就…

革新体验:细数3D在线预览在多个行业的广泛应用

‌3D在线预览展示技术的应用领域非常广泛&#xff0c;涵盖了从电子商务、产品设计、建筑设计到文化遗产保护等多个方面。‌ ‌1、电子商务‌&#xff1a; 在电商领域&#xff0c;3D展示技术为商品提供了全方位的展示&#xff0c;包括产品的外观、功能和卖点。这种交互式的购物…

影刀RPA实战:java结合影刀同步采购订单数据

1.实战目标 本次实战我们用java语言结合影刀&#xff0c;实现从自用ERP系统同步订单到旺店通中&#xff0c;在工作中&#xff0c;有时候我们的运营数据不是直接在旺店通ERP中操作&#xff0c;比如我们有自己的ERP&#xff0c;完成一些特定的内部工作后&#xff0c;再把数据同步…

做一个能适配「手机」的网站需要注意什么

这个问题的答案其实简单。 只要在网站前端开发过程中&#xff0c;将网站做成响应式布局&#xff0c;也就是 RWD &#xff08;Responsive Web Design&#xff09;就可以啦&#xff01;当手机或者不同设备打开网站时&#xff0c;通过检测视口分辨率来自动呈现不同的尺寸布局内容…

小程序弹出框是没办法遮挡住底部的tabbar的,解决的办法是使用自定义tabbar。。uni-app小程序如何自定义tabbar

原生小程序方法自定义 tabBar | 微信开放文档 如果是uni-app的小程序应该怎么自定义呢&#xff1f; 不是用page.json里面的tabbar就需要修改page.json.加上 "custom": true 注意list数组还是按照正常的来写。所以不使用但是也不能删除。 我们知道uni-app里面的页…

数字人形象自定义制作:readyplayer

网址&#xff1a; https://readyplayer.me/ 支持上传照片和拍照&#xff0c;会自动识别变成卡通风格 其他选项是配置选项&#xff1a;穿着、样貌等 上面弄好后右上角点击next&#xff0c;创建的模型可以下载3d glb文件 glb文件在线打开&#xff1a; https://gltf-viewer.d…

docker-文件复制(docker cp:用于在Docker主机和容器之间拷贝文件或目录)

文章目录 1、把宿主机的文件复制到容器内部1.1、查询 宿主机 root 下的文件1.2、docker cp /root/anaconda-ks.cfg spzx-redis:/root1.3、查看 spzx-redis 容器 中/root目录下是否有 anaconda-ks.cfg 文件 2、把容器中的文件 复制 到宿主机中2.1、查看 spzx-redis 容器 / 下的文…

Spring Boot框架在甘肃非遗文化网站设计中的运用

3 系统分析 当用户确定开发一款程序时&#xff0c;是需要遵循下面的顺序进行工作&#xff0c;概括为&#xff1a;系统分析–>系统设计–>系统开发–>系统测试&#xff0c;无论这个过程是否有变更或者迭代&#xff0c;都是按照这样的顺序开展工作的。系统分析就是分析系…

力扣面试150 添加与搜索单词 - 数据结构设计 字典树

Problem: 211. 添加与搜索单词 - 数据结构设计 &#x1f469;‍&#x1f3eb; 参考题解 public class WordDictionary {// 定义一个内部类 Node&#xff0c;用于表示 Trie&#xff08;前缀树&#xff09;中的每个节点class Node{// 每个节点有一个大小为 26 的数组&#xff0c…

详解swoole框架快速入门

Swoole包含两个主要部分&#xff1a;一个是用C语言开发的PHP扩展&#xff0c;作为核心功能&#xff1b;另一个是通过PHP代码编写的框架&#xff0c;类似于yii、TP和Laravel。 Swoole扩展本身具备web服务器功能&#xff0c;可以取代php-fpm。当仅使用Swoole框架时&#xff0c;可…

国产人形机器人突破,教会人形机器人如何像人类一样移动

与远在大洋彼岸的特斯拉机器人使用相同的训练设备&#xff0c;Humanoid Robot(上海)有限公司正在使用Xsens动作捕捉系统和ai训练人形机器人模仿人类运动&#xff0c;执行复杂任务。 关键要点: 人形机器人市场正在快速扩张:人形机器人市场将在未来大幅增长&#xff0c;据统计数…

傅里叶变换的python实现

周期信号的频谱   为了能既方便又明白地表示一个信号在不同频率下的幅值和相位&#xff0c;可以采用成为频谱图的表示方法。   在傅里叶分析中&#xff0c;把各个分量的幅度|Fn|或 Cn 随着频率nω1的变化称为信号的幅度谱。   而把各个分量的相位 φn 随角频率 nω1 变化…

ZUploader 之 文件上传

文件上传是前端开发很常用的一个功能, 通常文件上传都是异于表单提交, 使用起来配置繁多, 校验不统一, 展示不统一。 效果对比 特点 简化使用数据双向绑定样式统一带预览和下载功能 依赖 封装的组件 FileViewDialog (文件预览与下载,不需要此功能的话,可删除) 文件返回接口…

用户体验分享 | YashanDB V23.2.3安装部署

近期崖山新版体验过程中&#xff0c;总能看到用户提问&#xff1a;openssl版本问题、monit命令找不到问题、yashan用户权限问题、数据库重装问题 今日整理了多位用户的安装经验&#xff0c;希望能够帮助到大家~ 1.Lucifer三思而后行 &#xff1a;YashanDB 个人版数据库安装部…

稳居赛道销量前三的制造业巨头:数据安全建设的高效实践

作为一家迅速扩展的全球化制造企业&#xff0c;我们的分支和业务遍布国内多个城市及海外&#xff0c;员工流动频繁&#xff0c;终端设备多样&#xff0c;研发流程复杂。因此&#xff0c;我们需要一个灵活且强大的数据安全策略。经过深入的市场调研和严格POC测试&#xff0c;我们…

使用Postman搞定各种接口token实战

现在许多项目都使用jwt来实现用户登录和数据权限&#xff0c;校验过用户的用户名和密码后&#xff0c;会向用户响应一段经过加密的token&#xff0c;在这段token中可能储存了数据权限等&#xff0c;在后期的访问中&#xff0c;需要携带这段token&#xff0c;后台解析这段token才…

虚拟机的安装和使用

一、虚拟机的简单介绍 虚拟机可以使你在一台机器上同时运行二个或更多Windows、LINUX等系统&#xff0c;它可以模拟一个标准PC环境。这个环境和真实的计算机一样&#xff0c;都有芯片组、CPU、内存、显卡、声卡、网卡、软驱、硬盘、光驱、串口、并口、USB控制器等。 二、虚拟机…