仿微信@功能

仿微信@功能,第1张

基于vue2.x + vant2.x 实现的仿微信@功能(稍作修改即可支持原生js和react),兼容pc端和手机端,如有bug,欢迎提出~

年后分配到一个新项目 - 企业微信论坛。项目涉及到发帖子、评论、留言等功能,刚好和我的个人博客功能类似,不能说一模一样吧,也八九不离十了(内心偷乐😁😁)。

但是,令人头疼的问题来了,附加了一个@功能,即在评论框中输入@实现通知用户的功能。这个可以说触及到我的的知识盲点了,但其实很多应用都有这类功能了,如:微博、QQ、微信、企业微信… 哎,需求需要,不得不做,静下心来好好研究研究叭~

一、技术方案分析

方案很多,适合自己、适合团队才称得上完美。
这里归纳了几种常用的方案:

textarea、input (例:新浪微博) 这种方式我感觉是最最最复杂的,而且坑也巨多。具体原因参考@提及如何实现-包含了使用textarea实现@功能的解析。相信我如果你手写,你不会快乐的!!!所以推荐下面的库给大家、只要稍作改动就可以使用啦~~Tribute.js(推荐)At.js (JQ) contenteditable (例:QQ空间, 掘金) HTML5新属性,表示元素是否可被用户编辑,即像textarea文本框那样可以输入内容。自己试了下这种方法,注意点很多,bug也不少 (比如:实现到最后,刚看到了一丝丝希望QAQ,但是,光标移至中间位置继续向右移动,光标最终会消失),没找到解决办法,最终,放弃了😂😂。contenteditable-MDNcontenteditable实现编辑器,光标、输入法处理 富文本 (例:企业微信TAPD) 拥有丰富的配置与强大的API,支持 文本、富文本、图片、表情等。考虑到扩展性与踩坑的深浅、api的丰富程度,最终选择 quill富文本 做为最终的方案。(PS:因为使用vue开发所以这里使用的是vue-quill-editor)推荐几个常用的富文本quill、wangeditor(不得不夸一下wangeditor,前一天在Issues提出@功能需求,隔天就做出了一版@功能的插件,可惜我已经用前者实现了👽👽) 二、效果和功能描述

最终目标:实现仿微信@用户功能。

demo地址: zugelu - 仿微信@功能

1. 效果图

2. 主要功能 在输入框内任何地方输入@,或点击@按钮(demo中Show @ Menu按钮),d出选择用户d框人员d框支持搜索功能、支持异步选择人员,在光标后追加@名称,并绑定人员相关数据@名称作为整体,光标不可游走其中删除时,将@名称作为一个整体进行删除

实现以上功能,可以说已经完成了一个高仿微信@功能。

三、准备工作

本案例是基于vue-quill-editor富文本编辑器(v3.0.6)和quill-mention(v3.1.0)来实现的。需下载quill相关依赖。

npm i vue-quill-editor quill-mmention --save

初始化项目结构

<template>
  <div id="at">
    
    <quill-editor
      ref="myQuillEditor"
      v-model="content"
      :options="editorOption"
    />
    
    <div id="toolbar">div>
  div>
template>

<script>
import { quillEditor } from 'vue-quill-editor'
import 'quill/dist/quill.snow.css'
import 'quill-mention'

export default {
  name: 'at-mention',
  components: {
    quillEditor
  },
  data () {
    return {
      content: '', // 富文本html
      isClickMention: false, // 是否点击@按钮打开@菜单d框
      isChineseInputMethod: false, // 是否中文输入法状态
      show: false, // d框显示状态
      editorOption: {
        placeholder: '说点什么呢。。。',
        modules: {
          toolbar: { // 自定义toolbar,本案例隐藏
            container: '#toolbar',
          },
          mention: { // 将 quill-mention 配置传递给 quill
            mentionDenotationChars: ["@"], // 指定哪些字符可以触发@提及
            source: function (searchTerm, renderList, mentionChar) { // @提及回调
              console.log(searchTerm, renderList, mentionChar)
              renderList([], searchTerm) // 因为我们要自定义d框,所以这里把默认的@用户数据置空
            }
          }
        }
      }
    }
  },
  computed: {
    editor () {
      return this.$refs.myQuillEditor.quill
    }
  },
}
script>

<style >
/* quill-toolbar */
.ql-toolbar {
  padding: 0 !important;
  border: 0 !important;
}
style>

初始化完成,就可以使用基于quill-mention实现的@功能了,但现有功能并不能满足我的需求(@之后从底部d出用户列表),需要在现有基础上进行改造升级。

提示:

mention -> source 中,renderList([], searchTerm), 因为我们要自定义d框,所以这里把默认的@用户数据置空。css样式中.ql-toolbar ,去除默认边距,目的隐藏toolbar后续data所用到的数据,在初始化阶段已全部列出 四、实现步骤 1. 中文输入法的判断

中文模式下输入@要进行判断,如:输入“说点什么呢@”,这个时候不能监听@事件。

如何判断中文输入?
当用户使用中文输入法开始输入中文时,compositionstart事件就会被触发。当文中文输入完成或取消时,compositionend事件将被触发。利用这个机制我们就可以判断是否中文状态。

compositionstart事件 当用户使用拼音输入法开始输入汉字时,事件就会被触发。compositionend事件 当中文输入完成或取消时,事件将被触发。
<template>
  <div id="at">
    
    <quill-editor
      v-model="content"
      @compositionstart.native="onCompositionstart"
      @compositionend.native="onCompositionend"
    />
  div>
template>

<script>
export default {
  data () {
    return {
      isChineseInputMethod: false, // 是否中文输入法状态
    }
  },
  methods: {
    // 中文输入触发
    onCompositionstart () {
      this.isChineseInputMethod = true
    },
    // 中文输入关闭
    onCompositionend () {
      this.isChineseInputMethod = false
    }
    ...
  }
}
script>
2. @事件的监听

判断设备类型(适配电脑和手机端)

// 判断设备是否为 Mobile (提示:请勿在浏览器调试模式下,切换手机模式,否则会导致@功能失效)
isMobile () {
  return navigator.userAgent.match(/(iPhone|iPod|Android|ios|iOS|iPad|Backerry|WebOS|Symbian|Windows Phone|Phone)/i)
},

根据终端判断用户是否输入@符号

// 判断是否输入 @符号
isAtCode (e) {
  return this.isMobile() ?
    ((e.keyCode === 229 || e.keyCode === 50) && e.code === 'Digit2' && e.key === '@')
    : (((e.keyCode === 50 && e.key === '@') || (e.keyCode === 229 && e.code === 'Digit2')) && e.shiftKey)
}

监听富文本keydown事件,判断是否为非中文状态下键入的@符号,如是,则打开用户列表d框

// 键盘按下
onKeyDown (e) {
  // 判断状态非中文输入法,并且监听到了@的事件
  if (!this.isChineseInputMethod && this.isAtCode(e)) {
    // 输入@打开@菜单d框
    this.show = true
  }
},

PS:本案例用户列表的代码就不贴了,可根据需求自定义,或前往at-mention获取demo代码。

3. 点击用户生成@标签

使用quill-mention提供的API - insertItem来实现。
当点击@列表中的想要@的用户,则触发selectItem事件,把@的内容插入到对应位置。

// 选择要@的用户
selectItem (item) {
  this.insertItem(item)
  this.show = false
},
// 插入@内容,item即为用户信息
insertItem (item) {
  const mention = this.editor.getModule('mention')
  mention.insertItem({ id: item.id, value: item.name, denotationChar: '@' }, true)
}

这样会有一个问题,@用户的时候多了一个@符号,原因是insertItem会默认帮我们添加一个@符号,加上手动输入的@符号就多出一个@。
所以这里需要特殊处理一下,调用history.undo()撤销API(需要额外配置下history参数):

editorOption: {
  modules: {
    ...
    history: { // history 配置(History模块负责处理Quill的撤销和重做)
      delay: 0 // 将延迟设置为0,那么几乎每次输入字符都会被记录成一个变化,然后,撤销动作就会一次撤销一个字符
    }
  }
},
// 选择要@的用户
selectItem (item) {
  // 如果不是通过@按钮打开的d框,则需要删除多余的@符号
  if (!this.isClickMention) {
    // 撤销一步,删除手动输入的@符号(需在modules中配置history: { delay: 0 })
    this.undo()
  }
  this.insertItem(item)
  this.show = false
},
// 撤销
undo () {
  this.editor.history.undo();
},
4. 点击外部的@按钮插入@标签

非常简单,直接调用API - insertItem 来插入@标签即可。(会默认添加@符号)

五、总结

这个功能我自己测试没问题,兼容性也不错(并未进行详细测试、可能会存在其他问题),如果使用中遇到问题,欢迎提出反馈,希望能和大家一起进步~

本文首发于足各路的博客,后续会同步更新到掘金、知乎、CSDN。关注足各路、前端不迷路!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1320197.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-11
下一篇 2022-06-11

发表评论

登录后才能评论

评论列表(0条)

保存