美文网首页
vue-quill-edtior实现@用户和视频插入纪录

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

作者: wave浪儿 | 来源:发表于2023-01-03 17:58 被阅读0次

    一、插入视频

    主要是用了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属性导致的。

    相关文章

      网友评论

          本文标题:vue-quill-edtior实现@用户和视频插入纪录

          本文链接:https://www.haomeiwen.com/subject/ahplcdtx.html