在 nextjs 中集成 quill 所见即所得编辑器

周奶娘
• 阅读 360

这几天在学习 nextJs 的过程中,发现 nextjs 应用和 react 应用还是有很大差异,毕竟是 服务端渲染的。在打算引入一个所见即所得的编辑器时,遇到了一点问题。昨天熬到凌晨两点,终于搞定,实现方式略有点 dirty,后续再整改吧。 现代所见即所得的编辑器,其实那些加粗加横线啥的都不重要,最主要是对插入图片和视频之类的支持,而视频一般直接用链接跳转到第三方视频网站就完了,图片的话,需要实现一个上传控件。上传控件我就不叙述了,参见 https://juejin.cn/post/7082679181288407070 这个资料吧。(代码中的 Uploader 就是用的这个实现) wysiwyg 控件,我选择的是 quill,https://quilljs.com/,请参考这篇 查看如何将 quill 集成进 nextjs.

进行到这步后,quill 能正常工作,但是 toolbar 上的行为不可控,所以我们还不能修改 图片按钮点击的事件。现在我们需要参照 这里 的 custom toolbar 部分,自定义 toolbar 的行。

最终的办法是,点击图片上传 icon 时,调用的是自定义的 insertImage 方法,这个方法把 quill 对象设置 为 window 的一个属性,把当前光标位置也设置在 window 的一个属性。上传完成后,回调方法通过 window 对象获取到 quill 对象,并用 quill 类的 clipboard 接口来将自定义的 html 写入。

最后完整的代码如下:

import dynamic from 'next/dynamic'

const QuillNoSSRWrapper = dynamic(import('react-quill'), {
  ssr: false,
  loading: () => <p>Loading ...</p>,
})

const CustomToolbar = () => (
  <div id="toolbar">
    <span className="ql-formats">
      <select className="ql-header" defaultValue="3">
        <option value="1">Heading</option>
        <option value="2">Subheading</option>
        <option value="3">Normal</option>
      </select>
      <select className="ql-font" defaultValue="sailec">
        <option value="sailec">Sailec Light</option>
        <option value="sofia">Sofia Pro</option>
        <option value="slabo">Slabo 27px</option>
        <option value="roboto">Roboto Slab</option>
        <option value="inconsolata">Inconsolata</option>
        <option value="ubuntu">Ubuntu Mono</option>
      </select>
    </span>
    <span className="ql-formats">
      <button className="ql-bold"></button>
      <button className="ql-italic"></button>
      <button className="ql-underline"></button>
    </span>
    <span className="ql-formats">
      <button className="ql-list" value="ordered"></button>
      <button className="ql-list" value="bullet"></button>
      <select className="ql-align" defaultValue="false">
        <option label="left"></option>
        <option label="center" value="center"></option>
        <option label="right" value="right"></option>
        <option label="justify" value="justify"></option>
      </select>
    </span>
    <span className="ql-formats">
      <button className="ql-link"></button>

      <button className="ql-video"></button>
    </span>
    <span className="ql-formats">
      <button className="ql-formula"></button>
      <button className="ql-code-block"></button>
    </span>
    <span className="ql-formats">
      <button className="ql-clean"></button>
    </span>

    <button className={'ql-image'}></button>
  </div>
)

function insertImage() {
  const cursorPosition = this.quill.getSelection().index
  window.cursorPosition = this.quill.getSelection().index

  this.quill.insertText(cursorPosition, '')
  this.quill.setSelection(cursorPosition + 1)
  window.quill = this.quill
  setTimeout(() => {
    document.getElementsByClassName('rt-file-input')[0].click()
  }, 200)
}
const modules = {
  toolbar: {
    container: '#toolbar',
    handlers: {
      image: insertImage,
    },
  },
}

const formats = [
  'header',
  'font',
  'size',
  'bold',
  'italic',
  'underline',
  'strike',
  'blockquote',
  'list',
  'bullet',
  'indent',
  'link',
  'image',
  'video',
]
export default function QuillEditor() {
  const onUpload = file => {
    window.quill.clipboard.dangerouslyPasteHTML(window.cursorPosition, "<img src='" + file.data + "'/>")
  }
  return (
    <>
      <CustomToolbar />
      <QuillNoSSRWrapper modules={modules} formats={formats} theme="snow" />
      <Upload action={'/api/item/upload'} onSuccess={onUpload} id={'uploader'} className={'xup-uploader'}>
        <button className="ql-image"></button>
      </Upload>
    </>
  )
}

欢迎前往原文讨论:https://github.com/xurenlu/404ms/issues/7

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
1年前
二、Nextjs 最新版本的应用路由教程
Nextjs最新版本的应用路由教程本文基于nextjs的最新版本14.2.5Nextjs最新版本的优点Nextjs在13版本以后,新增加了approuter,官方建议用这个相对于之前的pages,是有一定的好处的。如下1.ReactServerCompon
待兔 待兔
1年前
nextjs教程三:获取数据
数据的获取数据获取是任何应用程序中最重要的部分,本文将介绍,如何在react,nextjs中获取数据主要有种方法可以获取数据在服务端,用fetch获取数据在客户端,通过路由处理器获取数据下面分别介绍一下这4种获取数据的方式一、fetch获取数据nextjs
Stella981 Stella981
4年前
Python Challenge Level 18
初学Python,挑战一下流行的PythonChallenge,很不幸,卡在了18关~~被字符字节码之间的转换搞得焦头烂额,不过终于搞定了还是很happy的~~~主要的问题就是16进制形式的字符如何转成字节码(注意:不是encoding)如:\'89','50','4e','47','0d','0a','1a','0a','00
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
待兔 待兔
1年前
一、nextjs 服务端渲染及环境搭建
一、nextjs服务端渲染及环境搭建从今天开始,我们会出一系列的nextjs文章,助力您快速掌握这一前端框架的精髓。我们知道,nextjs是基于react的服务端渲染的框架。所以必须要会react当然基于vue的服务端渲染框架,也有,叫nuxt,现在已经出
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
周奶娘
周奶娘
Lv1
接天莲叶无穷碧,映日荷花别样红。
文章
3
粉丝
0
获赞
0