vue-quill-edtior实现@用户和视频插入纪录

一、插入视频

主要是用了blots/block/embed 插入的换行的块级元素

import { Quill } from 'vue-quill-editor';
const BlockEmbed = Quill.import('blots/block/embed');
class Video 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('videoCover', value.videoCover || '')
    node.setAttribute('videoTime', value.videoTime || '')
    node.setAttribute('size', value.size || '')
    node.setAttribute('webkit-playsinline', true)
    node.setAttribute('playsinline', true)
    node.setAttribute('x5-playsinline', true)
    node.setAttribute('controlslist', value.controlslist || '')
    return node;
  }
  static value (node) {
    return {
      url: node.getAttribute('src'),
      controls: node.getAttribute('controls'),
      width: node.getAttribute('width'),
      height: node.getAttribute('height'),
      videoCover: node.getAttribute('videoCover'),
      videoTime: node.getAttribute('videoTime'),
      size: node.getAttribute('size'),
      controlslist: node.getAttribute('controlslist'),
    };
  }
}
Video.blotName = 'video'; 
Video.className = 'ql-video';
Video.tagName = 'video'; 
export default Video;

使用方法:

import Video from './video';
Quill.register(Video, true);
// 具体插入视频的方法
insertEle(url) {
      let quill = this.$refs.myTextEditor.quill;
      let length = quill.selection.savedRange.index;
      quill.insertEmbed(length, 'video', {
        url,
        controls: 'controls',
        width: '100%',
        height: 'auto',
        videoCover: this.videoCover,
        videoTime: this.videoTime,
        size: this.videoSize
      });
      // 调整光标到最后
      quill.setSelection(length + 1);
},

二、插入@用户

实践过两种方式,但是第一种有很多坑(比如删除的时候光标会提前之类的)
第一种也纪录一下吧,主要用的是blots/embed

import { Quill } from 'vue-quill-editor';

const Embed = Quill.import('blots/embed');

class EmbedBlot extends Embed {
  static create(value) {
    let node = super.create();
    if(typeof value === "string"){ //编辑回显处理
      // 匹配到需要的span内容  
      const res = value.match(/<span class="atUser" (.*?)>(.*?)<\/span>/g);
      node.innerHTML = res;
      return node;
    }
    EmbedBlot.buildSpan(value, node);
    return node;
  }

  static value(node) {
    return node.innerHTML;
  }

  static buildSpan(value, node) {
    let emojiSpan = document.createElement('span');
    emojiSpan.classList.add(this.emojiClass);
    emojiSpan.innerText = value.text;
    emojiSpan.setAttribute('id', value.id);
    node.appendChild(emojiSpan);
  }
}

EmbedBlot.blotName = 'atTag';
EmbedBlot.emojiClass = 'atUser'
EmbedBlot.tagName = 'span';

export default EmbedBlot;

第二种是最完美的方法,插入一个行内元素:

import { Quill } from 'vue-quill-editor';
const Parchment = Quill.imports.parchment;
class EmbedTag extends Parchment.Embed {
  static create(value) {
    // 正常span标签就直接返回node对象
    if(value.nodeName==='SPAN'){
      return value;
    }
    const node = super.create(value);
    node.contentEditable = 'false';
    this.contentNode = document.createElement('span');
    this.contentNode.classList.add('atUser');
    this.contentNode.setAttribute("id",value.id)
    this.contentNode.innerText = value.text;
    node.appendChild(this.contentNode);
    return node;
  }
  static value(node) {
    return node;
  }
}
EmbedTag.blotName = "atTag" 
EmbedTag.tagName = "SPAN"
EmbedTag.className = "customTag"; // 这个一定要加,不然富文本中其他样式用到了span标签的也会读取这个自定义blot,比如会导致我背景颜色取消的时候找不到原始方法报错。。。。。
export default EmbedTag;

使用方法:


import atTag from './atTag';
Quill.register(atTag, true); 

// 插入@用户方法
addTagUser(obj){
      const {nick,beanId} = obj;
      let text = nick?`@${nick} `: '';
      let quill = this.$refs.myTextEditor.quill;
      let length = quill.selection.savedRange.index; // 获取原来光标位置
      quill.insertEmbed(length, 'atTag', {
        id: beanId,
        text,
      },Quill.sources.USER);
      quill.setSelection(length + 1, Quill.sources.USER);
 },

艰辛摸索过程纪录:
需求:想实现一个@用户 和 表情包的功能,需要支持高亮 和一键删除功能。
主要用到了contentEditable=false这个属性,让元素可以一键删除,但是发现<span contenteditable='false'>@花儿与少年</span>这种写法,点击元素后面没有光标,无法聚焦,后来发现了<span contenteditable="false"><span class="atUser" id="2825639815600373760">@梦与千寻 </span></span>这种包一层的话,就可以聚焦光标了(在发现这种写法之前,试过很多种的办法,这里就不描述了,只是这样说出来显得很单薄简单),这种也可以应用于自定义的输入框中实现插入表情包等需要高亮和一键删除的需求。
记录一下:上面说里面包一层span的写法,后面又发现可以不用包一层也可以聚焦,之前不聚焦大致是因为给了span标签display:inline-block属性导致的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352