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

news2025/2/27 23:20:44

问题描述:

我们在开发过程中经常会遇到使用富文本编辑器进行操作,当前插件市场上关于富文本的编辑器挺多的,我们就不一一个介绍了,现在我们主要讲解一些vue-quill-editor富文本编辑器的使用操作和注意事项。

效果图

在这里插入图片描述

具体操作使用

1. 安装

npm install vue-quill-editor -S

2. 引入到项目中

有两种挂载方式: 全局挂载 和 在组件中挂载,根据自己的项目需求选择,一般用到富文本编辑都是在某一个项目中,我们这里为了方便大家选择,两种引用方案都写下来以便大家参考:

(1),页面中引用

import { quillEditor } from 'vue-quill-editor'
 
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'
 
export default {
  components: {
    quillEditor
  }
}

(2),全局中引用

import Vue from 'vue'
import VueQuillEditor 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, /* { 默认全局 } */)

3. 页面上面具体实现

<template>
	<quill-editor 
	   class="ql-editor"
	   v-model="content" 
	   ref="myQuillEditor" 
	   :options="editorOption" 
	   @blur="onEditorBlur($event)" 
	   @focus="onEditorFocus($event)"
	   @change="onEditorChange($event)">
	</quill-editor>
</template>
 
<script>
export default {
    data() {
        return {
	       content: `<p>这是 vue-quill-editor 的内容!</p>`, //双向数据绑定数据
		  // 富文本编辑器配置
	      editorOption: {
	        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: ['12px', false, '16px', '18px', '20px', '30px'] }], // 字体大小
					  [{ header: [1, 2, 3, 4, 5, 6, false] }], // 标题
					  [{ color: [] }, { background: [] }], // 字体颜色、字体背景颜色
					  [{ font: [false, 'SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial'] }], // 字体种类
					  [{ align: [] }], // 对齐方式
					  ['clean'], // 清除文本格式
					  ['link', 'image', 'video'] // 链接、图片、视频
		        },
		        placeholder: '请输入正文'
	      	} 
	      }
	  		},
    methods: {
       // 失去焦点事件
		  onEditorBlur(quill) {
		    console.log('editor blur!', quill)
		  },
		// 获得焦点事件
		  onEditorFocus(quill) {
		    console.log('editor focus!', quill)
		  },
		// 准备富文本编辑器
		  onEditorReady(quill) {
		    console.log('editor ready!', quill)
		  },
		// 内容改变事件
		  onEditorChange({ quill, html, text }) {
		    console.log('editor change!', quill, html, text)
		    this.content = html
		  }
    }
}
</script>

到这里一个默认的富文本编辑器已经导入使用了,如下图所视!
在这里插入图片描述

4.为了更好配合使用,样式上面进行优化,使用中文标识方便查看

(1),重新自定义字体类型

import Quill from 'quill' // 引入编辑器
// 自定义字体大小
const Size = Quill.import('attributors/style/size')
Size.whitelist = ['10px', '12px', '16px', '18px', '20px', '30px', '32px']
Quill.register(Size, true)

// 自定义字体类型
var fonts = ['SimSun', 'SimHei', 'Microsoft-YaHei', 'KaiTi', 'FangSong', 'Arial', 'sans-serif']
var Font = Quill.import('formats/font')
Font.whitelist = fonts
Quill.register(Font, true)

(2),自定义对应样式

// 给文本内容加高度,滚动条
.quill-editor /deep/ .ql-container {
    min-height: 220px;
  }

  .ql-container {
    min-height: 230px;
  }

 /deep/ {
    .ql-snow .ql-tooltip [data-mode="link"]::before {
      content: "请输入链接地址:";
      left: 0;
    }

    .ql-snow .ql-tooltip.ql-editing {
      left: 0 !important;
    }

    .ql-snow .ql-tooltip {
      left: 0 !important;
    }

    .ql-snow .ql-editor {
      max-height: 300px;
    }

    .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" !important;
      font-size: 14px;
    }

    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="10px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="10px"]::before {
      content: "10px" !important;
      font-size: 10px;
    }

    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="12px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="12px"]::before {
      content: "12px" !important;
      font-size: 12px;
    }

    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="16px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="16px"]::before {
      content: "16px" !important;
      font-size: 16px;
    }

    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="18px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="18px"]::before {
      content: "18px" !important;
      font-size: 18px;
    }

    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="20px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="20px"]::before {
      content: "20px" !important;
      font-size: 20px;
    }

    .ql-snow .ql-picker.ql-size .ql-picker-label[data-value="30px"]::before, .ql-snow .ql-picker.ql-size .ql-picker-item[data-value="30px"]::before {
      content: "30px" !important;
      font-size: 30px;
    }

    .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" !important;
      font-size: 32px;
    }

    .ql-snow .ql-picker.ql-header .ql-picker-label::before, .ql-snow .ql-picker.ql-header .ql-picker-item::before {
      content: "文本" !important;
    }

    .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" !important;
    }

    .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" !important;
    }

    .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" !important;
    }

    .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" !important;
    }

    .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" !important;
    }

    .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" !important;
    }

    .ql-snow .ql-picker.ql-font .ql-picker-label::before, .ql-snow .ql-picker.ql-font .ql-picker-item::before {
      content: "标准字体" !important;
    }

    .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: "衬线字体" !important;
    }

    .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: "等宽字体" !important;
    }

    .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: "宋体" !important;
      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: "黑体" !important;
      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: "微软雅黑" !important;
      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: "楷体" !important;
      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: "仿宋" !important;
      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" !important;
      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" !important;
      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" !important;
      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";
    }

    .ql-snow.ql-toolbar .ql-formats .ql-revoke {
      background-image: url("../../../../assets/images/icons8-rotate-left-18.png");
      width: 20px;
      height: 20px;
      filter: grayscale(100%);
      opacity: 1;
    }

    .ql-snow.ql-toolbar .ql-formats .ql-revoke:hover {
      background-image: url("../../../../assets/images/icons8-rotate-left-18.png");
      width: 20px;
      height: 20px;
      filter: none;
      opacity: 0.9;
    }

    img {
      filter: grayscale(100%);
      opacity: 1;
    }

    img:hover {
      filter: none;
      opacity: 0.9;
    }

    /*加上height和滚动属性就可以,滚动条样式是系统默认样式,可能不同*/
    .ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options {
      border-color: #ccc;
      height: 125px;
      overflow: auto;
    }
  }

(3),注意点:富文本里面的下拉框默认是不滚动的,想要滚动效果,加上下面的css

/*加上height和滚动属性就可以,滚动条样式是系统默认样式,可能不同*/
.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options {
  border-color: #ccc;
  height: 125px;
  overflow: auto;
}

在这里插入图片描述

5.上传图片到七牛云

vue-quill-editor 默认的是以 base64 保存图片,会直接把图片 base64 和内容文本一起以字符串的形式提交到后端。这样小图片还行,如果要上传大图片会提示上传失败,优秀的前端打字员显然不会这样做。

思路
可以先将图片上传至服务器,再将图片链接插入到富文本中显示
图片上传可以自定义一个组件或者使用 element-ui 的上传图片的组件(我在项目中使用的是自定义的组件,这里演示使用 element-ui 组件上传)
上传图片的组件需要隐藏,点击图片上传时调用element-ui 的图片上传,上传成功后返回图片链接。
在编辑器项中配置配置项


<el-upload
  v-show="false"
  class="avatar-uploader"
  :data='fileUpload'
  :show-file-list="false"
  :http-request="onUploadHandler"
 >
</el-upload>

在option中配置上传操作,之前的option就耀稍作修改

handlers: {
              'image': function (value) {
                if (value) { // value === true
                  document.querySelector('.avatar-uploader input').click()
                } else {
                  this.quill.format('image', false)
                }
              }
            }
 点击富文本上的上传图片,就会触发这里的handlers,将操作引到upload的函数上,在这个函数里面需要做的操作是,将图片上传到七牛云,并拿到返回的在线链接,然后将图片链接插入到页面对应位置上。这里我的上传是自己封装了函数。
async onUploadHandler(e) {
      const imageUrl = 上传七牛云后返回来的一串在线链接
 
      // 获取光标所在位置
      let quill = this.$refs.myQuillEditor.quill
      let length = quill.getSelection().index
      // 插入图片  
      quill.insertEmbed(length, 'image', imageUrl)
      // 调整光标到最后
      quill.setSelection(length + 1)
      // this.content += url
    }

6.自定义控制图片大小

(1),安装插件

 npm i quill-image-resize-module -S

(2),在文件中导入包

import Quill from 'quill' 
import ImageResize from 'quill-image-resize-module' 
Quill.register('modules/imageResize', ImageResize)  

(3),在原本的配置项上添加(与toolbar平级进行配置)

toolbar: {},
// 调整图片大小
  imageResize: {
      displayStyles: {
          backgroundColor: 'black',
          border: 'none',
          color: 'white'
      },
      modules: [ 'Resize', 'DisplaySize', 'Toolbar' ]
  }

效果:
在这里插入图片描述

7.自定义toobar样式设计

//在quill中使用
toolbar: {
      container: toolbarOptions,
      handlers: {
        **report: this.openWorkReport**
      }
    }
// 方法中使用
	openWorkReport () {
      this.$emit('openWorkReport')
    },

// 样式
/* 自定义toobar样式设计 */
/* 工作汇报弹窗 */
.ql-snow.ql-toolbar .ql-formats .ql-report{
    background: url("../images/meeting/report.png") no-repeat;
    background-size: contain;
    display: inline-block;
    height: 18px;
    margin: 3px 5px;
    width: 28px;
}

效果

在这里插入图片描述
有关视频上传参考:视频上传

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

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

相关文章

是什么让学习 Web 开发在未来几年变得有价值?

&#x1f482; 个人网站:【海拥】【摸鱼游戏】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f30a; 本文首发…

React中ref的使用方法和使用场景(详解)

摘要 不管在Vue中还是React&#xff0c;如果我们想使用一个元素的DOM&#xff0c;不需要通过JS中操纵DOM的方法&#xff0c;它们提供了一个专属的API就是ref。 而Vue中的ref可能比较简单&#xff0c;这一篇主要讲一下如何在React中使用ref&#xff0c;以及使用ref的场景。 1…

如何创建vue3项目

目录 如何创建vue3项目 1、用vue cli创建 2、使用vite直接创建 3、使用vue3官方推荐创建方式 如何创建vue3项目 创建vue3我们常用的有三种方式&#xff1a; 1、用vue cli创建 1.使用vue cli环境前提条件&#xff1a; node -vv16.13.0 npm -v8.1.0 vue -Vvue/cli 4.5.15 …

微信小程序中使用vant组件库(超详细)

目录前言Vant Weapp的安装与使用1、安装 node.js2、通过 npm 安装3、修改 app.json4、修改 project.config.json5、构建 npm 包6、使用组件全局引入和局部引入全局引入局部引入Toast 组件的使用官方文档 API 详解Props 参数Events 事件Slot 插槽外部样式类前言 Vant是一个轻量…

vue中this.$router.push()路由传值和获取的两种常见方法

今天接到了比较大的需求&#xff0c;由于这个公司的接口调用方法和上一段实习那家公司的写法很不一样&#xff0c;我花了很多时间在摸索&#xff0c;“踏出第一步总是最困难的”&#xff0c;果然没错&#xff0c;第一个很费劲&#xff0c;但完成之后有了思路&#xff0c;下面的…

登录功能的实现(包括前后端)

目录:&#x1f349;&#x1f349;&#x1f349;UPDATE:✨✨✨前言✨✨✨概述✨✨✨技术栈✨✨✨效果图✨✨✨代码✨✨✨github链接&#x1f349;&#x1f349;&#x1f349;UPDATE: 突然发现喜提榜一&#xff0c;蟹蟹读者老爷们的支持(づ&#xffe3; 3&#xffe3;)づ 润色了…

微信小程序完整项目实战(前端+后端)

基于微信小程序的在线商城点单系统 前言&#xff1a;闲来无事&#xff0c;想以后自己开一个小超市或者小吃店&#xff0c;能够支持线上下单&#xff0c;既方便客户也方便自己。系统采用C#语言作为后端实现与小程序的交互&#xff0c;给用来学习或者想自己开个小店的朋友当个参考…

如何在 WordPress 中嵌入 iFrame

&#x1f482; 个人网站:【海拥】【摸鱼游戏】【神级源码资源网站】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f4ac; 免费且…

【uniapp小程序开发】—— 组件封装之【自定义轮播图】

文章目录&#x1f34b;前言&#xff1a;&#x1f34d;正文1、首先了解swiper组件1.1、小小的demo示例&#xff1a;1.2、自定义轮播图效果展示说明2、完成自定义轮播图效果3、组件封装——自定义轮播图3.1、创建swiper-doc.vue组件3.2、组件调用&#xff0c;封装完成&#x1f38…

session、cookie、token的区别?

前言 今天就来理一理session、cookie、token这三者之间的关系&#xff01; 1.为什么会有它们&#xff1f; 我们都知道 HTTP 协议是无状态的&#xff0c;所谓的无状态就是客户端每次想要与服务端通信&#xff0c;都必须重新与服务端链接&#xff0c;意味着请求一次客户端和服…

React组件通信-父子组件间的通信

文章目录React父子组件通信认识组件嵌套组件通信父传子参数验证子传父React父子组件通信 认识组件嵌套 组件之间存在嵌套关系&#xff1a; 在之前的案例中&#xff0c;我们只是创建了一个组件App&#xff1b; 如果我们一个应用程序将所有的逻辑都放在一个组件中&#xff0c;那…

适合我的前端学习路线(学习前端不迷路)

适合我的前端学习路线&#xff08;学习前端不迷路&#xff09; 小伙伴们想学习前端&#xff0c;但是却不知如何入手&#xff0c;上网查前端学习路线&#xff0c;第一页往往充斥着各种培训公司的广告&#xff0c;又或者是搜前端学习路线图时&#xff0c;出现大量的路线图导致你还…

【学Vue就跟玩一样】Vue中的路由与多种守卫

1.vue-routervue的一个插件库&#xff0c;专门用来实现对SPA应用的单页Web应用(single page web application, SPA)。整个应用只有一个完整的页面。点击页面中的导航链接不会刷新页面&#xff0c;只会做页面的局部更新。数据需要通过ajax请求获取。2.什么是路由一个路由就是一组…

Tomcat服务器部署+Web项目搭建

Tomcat服务器部署&#xff0b;Web项目搭建 1.Tomcat服务器 1 . Tomcat下载 2 . Tomcat启动与关闭 3 . 配置端口号2.IDEA搭建Web项目 1 . web项目创建 2 . 本地服务器配置 Tomcat下载 tomcat官网&#xff1a;tomcat 1.选择与自己电脑对应的位数下载&#xff0c;我们…

HTML跳动爱心代码|最近很火的爱心代码你还没收到吗

最近很火的跳动爱心代码HTML实现可DIY 看效果 QQ录屏20221108115545点个赞吧,养成好习惯 不想动手的小伙伴可以直接&#x1f447;&#x1f447; 阿里云盘直接提取 阿里云盘 DIY版----提取码: f30q 使用说明 主体代码来源于网络,让我们为原作者点赞&#x1f44d;我用css3的anim…

云服务器部署 Web 项目

一: 搭建 Java 部署环境1: 安装 JDK2: 安装 Tomcat总结3: 安装 MySQL(1): 依次安装(2): 更改配置(3): 启动(4): 测试连接二: 部署 web 项目1: 给服务器准备好依赖的数据2: 微调我们的 Java 代码3: 重新打包4: 上传到服务器上5: 验证一: 搭建 Java 部署环境 之前说过 yum这个命…

手把手教你安装VSCode(附带图解步骤)

一、前端工具vscode 1.1、概述 前端开发是创建Web页面或app等前端界面呈现给用户的过程&#xff0c;通过HTML&#xff0c;CSS及JavaScript以及衍生出来的各种技术、框架、解决方案&#xff0c;来实现互联网产品的用户界面交互 [1] 。它从网页制作演变而来&#xff0c;名称上有…

Node安装及配置

目录一、Node安装二、Node环境配置2.1 下载国内淘宝镜像三、下载Node.js项目一、Node安装 首先我们进入Node的官网链接: 下载链接 点击下载&#xff0c;选择自己对应的版本&#xff0c;博主这边使用的Windows 安装包 (.msi) 下载之后双击运行下载包点击下一步 点击change 安装完…

【Vue】悬浮窗和聚焦登录组件经验总结

前言 ​ 本文整理了实现悬浮窗以及聚焦登录组件的功能。 ​ 为的是方便大家和自己的学习。 ​ 省流&#xff1a;可以只看1.2 和 2的代码即可 1 悬浮窗 现在各大流行视频网站的平台都在使用这种悬浮显示的效果&#xff0c;我就想这种东西是怎样搞出来的呢&#xff01;几经尝…

Vue项目保持用户登录状态(localStorage + vuex 刷新页面后状态依然保持)

在前端项目开发中&#xff0c;实现用户的登陆注册功能时常常会有一个问题&#xff0c;那就是我们设置的登录状态&#xff0c;在浏览器页面刷新后就消失了&#xff0c;这其实只是因为我们没有保存用户状态。 这里小马演示使用的是 localStorage vuex 方法&#xff08;其他诸如…