vue-quill-editor富文本编辑器

效果图:

1、下载安装vue-quill-editor

npm install vue-quill-editor --save

图片缩放、拖拽

npm install quill-image-drop-module -S    //允许粘贴图像并将其拖放到编辑器中。
npm install quill-image-resize-module -S  //允许调整图像大小

<template><div style="position: relative"><!--		@blur="setValue" 原本是用失去焦点返回值的--><QuillEditorref="myQuillEditor"id="richText"theme="snow":key="value"v-model:content="content":options="editorOptions"contentType="html"class="rt-ql-editor"style="height: 300px; box-sizing: content-box"/><a-spin :spinning="spinning" tip="上传中..." style="position: absolute; top: 80px; left: 50%" /><!-- 使用自定义图片上传,如未使用下方的图片上传和视频上传,将直接转成base64形式存储 --><inputtype="file"multipleaccept="image/*"id="richImg"class="richImg richButton-hidden"style="display: none"@change="uploadImage"/><inputtype="file"accept="video/*"id="richVideo"class="richVideo richButton-hidden"style="display: none"@change="uploadVideo"/><!--		<button @click="moni" style="margin-top:30px;">模拟图片上传</button>--></div>
</template><script>// import { $axios, $get, $post } from "@/utils/axios.ts";import { Quill, QuillEditor } from '@vueup/vue-quill'import '@vueup/vue-quill/dist/vue-quill.snow.css'import 'quill-image-resize-module/image-resize.min.js'import video from './video.js'import fileApi from '@/api/dev/fileApi'import { ImageDrop } from 'quill-image-drop-module'Quill.register('modules/imageDrop', ImageDrop)Quill.register(video)export default {name: 'RichText',components: { QuillEditor },props: ['value'],data() {return {spinning: false,content: '',editorOptions: {modules: {// imageDrop:true,imageResize: {displayStyles: {backgroundColor: 'black',border: 'none',color: 'white'},modules: ['Resize', 'DisplaySize', 'Toolbar']},toolbar: {container: [['bold', 'italic', 'underline', 'strike'],['blockquote', 'code-block'],[{ size: ['small', false, 'large', 'huge'] }],[{ font: [] }],[{ align: [] }],[{ list: 'ordered' }, { list: 'bullet' }],[{ indent: '-1' }, { indent: '+1' }],[{ header: 1 }, { header: 2 }],['image', 'video'],[{ direction: 'rtl' }],[{ color: [] }],[{ background: [] }]],handlers: {//如果需要上传图片/视频 到后台,然后在富文本框添加图片的地址,则可在handlers 里添加图片/视频处理函数。如果可以接受图片在富文本框中是base64形式,则无需设置。image: function (value) {if (value) {document.querySelector('.richImg').click()}},video: function (value) {if (value) {document.querySelector('.richVideo').click()}}}}},placeholder: '请输入内容...'},titleConfig: [{ 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: '编号列表' },{ Choice: '.ql-list[value="bullet"]', title: '项目列表' },{ Choice: '.ql-direction', title: '文本方向' },{ Choice: '.ql-header[value="1"]', title: 'h1' },{ Choice: '.ql-header[value="2"]', title: 'h2' },{ 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-script[value="sub"]', title: '下标' },{ Choice: '.ql-script[value="super"]', 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: '两端对齐' }]}},watch: {//获取父组件的值,更新内容value: {handler(newData, oldData) {this.setInitValue()},deep: true,immediate: false}},created: function () {console.log(this.value, 999999)this.content = JSON.parse(JSON.stringify(this.value))},mounted() {this.addQuillTitle()this.$el.children[0].value = this.value},methods: {//模拟图片上传moni() {this.upFile('test', 'image')},//设置初始值async setInitValue() {if (this.value) {let szContent = JSON.parse(JSON.stringify(this.value))this.content = szContent}},//上传图片 多张图片async uploadImage(e) {// this.upFile('a','image');var files = document.getElementById('richImg').filesconsole.log('图片', files[0])for (let i = 0; i < files.length; i++) {await this.upFile(files[i], 'image')}e.target.value = ''},//上传视频async uploadVideo(e) {var file = document.getElementById('richVideo').files[0]await this.upFile(file, 'video')e.target.value = ''},//上传文件的apiasync upFile(file, type) {this.spinning = true//上传方法:const data = new FormData()//使用append存储信息,append('键名','键值')data.append('file', file)await fileApi.fileUploadTencentReturnUrl(data).then((res) => {this.spinning = falseif (res) {this.insertImgOrVideo(res, type)} else {this.$message.warning(res.msg)}}).catch((e) => {this.$message.warning(e.msg)})},//插入图片或视频insertImgOrVideo(url, type) {let quill = this.$refs.myQuillEditor.getQuill()// 获取光标所在位置const length = quill.getSelection().indexconst reader = new FileReader()//range 是光标位置,但是这里找不到let range = quill.getSelection()// let length = (this.content).length || 0;//无法获取光标的位置,暂时先放在文本最后。如果你有解决方案,欢迎告知~//let length = quill.getSelection().index;if (type === 'image') {quill.insertEmbed(length, type, url)} else {quill.insertEmbed(length, 'simpleVideo', {url: url,controls: 'controls',width: '50%',height: '50%'})}quill.setSelection(length + 1)reader.onerror = function (error) {console.log('error', error)}},//值返回父组件setValue() {this.$emit('on-richText', this.content)},//toobar的提示addQuillTitle() {let titleConfig = JSON.parse(JSON.stringify(this.titleConfig))// console.log('this.titleConfig', titleConfig);document.getElementsByClassName('ql-editor')[0].dataset.placeholder = ''for (let item of titleConfig) {let tip = document.querySelector('.ql-toolbar ' + item.Choice)if (!tip) continuetip.setAttribute('title', item.title)}}}}
</script><style scoped>.rt-ql-editor {height: 200px;}.ql-toolbar.ql-snow .ql-formats {margin-right: 5px;}/* 调整样式 */:deep(.ql-editor) {min-height: 180px;}:deep(.ql-formats) {height: 21px;line-height: 21px;}.richButton-hidden {display: none;}
</style>

video.js 

const BlockEmbed = Quill.import('blots/block/embed')
/*** 用于插入视频的Blot*/
class VideoBlot extends BlockEmbed {static create (value) {let node = super.create()node.setAttribute('src', value.url)node.setAttribute('controls', value.controls)node.setAttribute('width', value.width)node.setAttribute('height', value.height)node.setAttribute('webkit-playsinline', true)node.setAttribute('playsinline', true)node.setAttribute('x5-playsinline', true)return node;}static value (node) {return {url: node.getAttribute('src'),controls: node.getAttribute('controls'),width: node.getAttribute('width'),height: node.getAttribute('height')};}
}
VideoBlot.blotName = 'simpleVideo'
VideoBlot.tagName = 'video'
export default VideoBlot;

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

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

相关文章

TCP是怎样工作的网络拥塞控制理论和算法部分记录

参考资料 https://github.com/ituring/tcp-book 流量控制、窗口控制和拥塞控制的关系 流量控制、窗口控制和拥塞控制的关系如图所示 窗口控制是上层的概念&#xff0c;核心思路是基于滑动窗口技术传输数据。而确定发送窗口大小的方法有流量控制和拥塞控制两种 流量控制&…

NVR管理平台EasyNVR多个NVR同时管理对接天翼云云存储的一些关键信息和优势

在视频监控领域&#xff0c;随着技术的不断进步&#xff0c;存储方式的选择变得尤为重要。传统的本地存储方式受限于硬件容量&#xff0c;而云存储则以其强大的数据处理能力和弹性扩展性&#xff0c;成为视频数据存储的理想选择。NVR管理平台EasyNVR作为一款领先的视频汇聚与管…

饲料加工机器设备由搅拌机粉碎机颗粒机组成

饲料加工机器设备在现代养殖业中扮演着至关重要的角色&#xff0c;它们不仅提高了饲料的生产效率&#xff0c;还优化了饲料的营养价值。其中&#xff0c;饲料粉碎机、搅拌机和颗粒机是饲料加工流程中的三大核心设备。 想象一下&#xff0c;一把把粗糙的原料&#xff0c;在粉碎…

oracle数据坏块处理(二)-逻辑坏块重新格式化处理

1、问题描述 在使用duplicate搭建DG时报错 包括rman copy&#xff0c;rman备份 2、问题分析 由于数据文件逻辑坏块导致物理备份不能正常进行。 使用rman检查数据文件47 SELECT tablespace_name, segment_type, owner, segment_name FROM dba_extents WHERE file_id 47 a…

在IDEA使用arthas实现jar包方法耗时统计

1.背景 对于依赖jar包中的方法内部耗时统计&#xff0c;传统的手写StopWatch不适用&#xff0c;这儿采用arthas统计。 官网文档比较详细&#xff0c;trace | arthas 使用版本&#xff1a; arthas-boot version: 4.0.2 IntelliJ IDEA 2023.3.3 2.使用介绍 2.1.启动需要检…

用于图像识别的判别图正则化技术

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;编程探索专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月8日13点32分 点击开启你的论文编程之旅https://www.aspiringcode.com/content?id17210272021224&uid64a84f9640714755a…

Android Handler

Handler用于多线程消息分发和处理。与handler相关的几个对象&#xff1a;Message, Looper&#xff0c;MessageQueue, ThreadLocal. Handler是Message的消费者。 MessageQueue是容器。 Looper是整个Message分发的驱动。 Handler中有多种发送消息的方法&#xff0c;其中postxx…

Windows/Linux部署Qt并通过Qt Installer Framework制作安装包

本文参考 Qt Installer Framework Manual。 若要使用 Qt Installer Framework&#xff08;简称 QIF&#xff09;&#xff0c;需要在 Qt Online Installer 或 Qt Maintenance Tool 中确保该组件已安装&#xff08;QIF 组件在 Qt->Developer and Design Tools 下&#xff09;&…

【大数据学习 | kafka】消费者的分区分配规则

1. 概述 上面我们提到过&#xff0c;消费者有的时候会少于或者多于分区的个数&#xff0c;那么如果消费者少了有的消费者要消费多个分区的数据&#xff0c;如果消费者多了&#xff0c;有的消费者就可能没有分区的数据消费。 那么这个关系是如何分配的呢&#xff1f; 现在我们…

【开发】关于Java中String与Integer的小小知识点(使用等号对比引用对象)

一个很简单的小知识点 我们都知道&#xff0c;如果使用对比包装类型或对象&#xff0c;那么比较的都是两者之间的地址&#xff08;指针或句柄&#xff09;&#xff0c;而非对象本身&#xff0c;那么且看下方的代码。 public class A {public static void main(String[] args)…

2025年山东省考报名流程图解

2025年山东公务员考试备考开始 为大家整理了从笔试到录用的全部流程&#xff0c;希望可以帮助到你们&#xff01;参考2024年山东省考公告整理&#xff0c;请以最新公告为准&#xff01; 一、阅读公告和职位表 二、职位查询 三、网上报名 四、确认缴费 五、网上打印准考证 六、参…

网络安全入门篇之详细学习路线

什么是网络安全 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面性&…

什么是大数据治理?在企业数字化转型过程中有什么用?

建设背景 有效的数据治理不仅能够确保数据的安全和质量&#xff0c;还能为企业提供深入的业务洞察&#xff0c;推动决策制定和创新。数据治理是数字化转型的基础&#xff0c;是数据资源成为数据资产的基础&#xff0c;只有经过了数据治理&#xff0c;相应的数据资源才能产生价…

Kalshi PK Polymarket,谁更胜一筹

https://kalshi.com https://polymarket.com/ 在刚过去的2024 美大选中&#xff0c;这两个网站可谓风光无限。这两者究竟有何区别呢&#xff0c;今天咱们一起来扒一扒。 Kalshi与Polymarket主要有以下区别&#xff1a; 监管与合法性方面&#xff1a; Kalshi&#xff1a;经过美…

UI测试还在Selenium,难怪你会被淘汰

一、前言 在UI自动化测试的领域中&#xff0c;Selenium无疑是一颗璀璨的明星&#xff0c;它以其强大的浏览器自动化能力&#xff0c;长期以来一直是众多测试工程师的首选工具。它很经典&#xff0c;地位也毋庸置疑&#xff0c;但也是过去式了&#xff0c;现在我采用的自动化方…

基于ssm的网上药房管理系统的设计与实现(源码+LW+调试)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。今天给大家介绍一篇基于java的ssm网上药房管…

godot——主题、Theme、StyleBox

我刚开始被这些术语吓到了&#xff0c;一直不敢去接触它们&#xff0c;都用的默认样式。现在好不容易有点思路了&#xff0c;记录下来。 下面看看怎么自定义样式。 1.先新建一个Theme 2.再次点击创建好的Theme 得到 图1 这样一个面板。&#xff08;看不懂没事&#xff0c;继…

如何利用Python API接口实战中高效地获取商品详情信息

在电商数据分析和商品信息集成领域&#xff0c;高效地获取商品详情信息是至关重要的。本文将介绍如何使用Python结合API接口&#xff0c;从淘宝/天猫平台获取商品详情信息&#xff0c;并提供实战代码示例。 一、理解API接口的重要性 API&#xff08;应用程序编程接口&#xff…

【Linux】编辑器vim 与 编译器gcc/g++

目录 一、编辑器vim&#xff1a; 1、对vim初步理解&#xff1a; 2、vim的模式&#xff1a; 3、进入与退出&#xff1a; 4、vim命令模式下的指令集&#xff1a; 移动光标&#xff1a; 删除&#xff1a; cv&#xff1a; 撤销&#xff1a; 其他&#xff1a; 5、vim底行模…

不支持UEFI的老显卡修改vBIOS进行支持

前段时间要在办公室玩恐怖黎明,但是联想自带的GT730实在是有点慢,后来闲鱼收了一张HD7750,虽然也是老掉牙,但是性能也有3成提升,聊胜于无吧.但是存在HD7750不支持UEFI的问题.具体表现为: 系统是win11未进系统时,什么都不显示,不能进BIOS.刚换卡未装驱动的时候,即使已经进入系统…