小工具知识网

当前位置: 首页 > 行业知识 > 前端聊天怎么实现艾特@功能?高亮@信息,仿微信、qq艾特功能

行业知识

前端聊天怎么实现艾特@功能?高亮@信息,仿微信、qq艾特功能

2026-11-12 22:39:09 来源:互联网转载

此demo使用vue3

实现效果图

声明:这只是个demo,不涉及与后端交互,不过会在该交互的地方标记,如需实际应用于项目,请根据实际情况进行改造完善!

艾特列表组件定义

        
  • {{ user.name }}
import { ref, defineProps, toRefs, onMounted, defineEmits } from "vue";/** * @param userGroup 聊天群员列表 * @param userGroupPosition 列表组件显示定位 */const props = defineProps(["userGroup", "userGroupPosition"]);// 选择群员事件const emit = defineEmits(["atUser"]);const { userGroup, userGroupPosition } = toRefs(props);// 此变量用来使用键盘上下按钮时,选择群员let activeIndex = ref(-1);// 给window挂载键盘事件,这样使用键盘上下键时可以选择群员onMounted(() => { window.addEventListener("keydown", keyboardSelect);});// 键盘事件 通过修改activeIndex值,达到选择群员function keyboardSelect(e) { if (e.key === "ArrowDown") { if (activeIndex.value !== userGroup.value.length - 1) { activeIndex.value++; } else { activeIndex.value = 0; } } else if (e.key === "ArrowUp") { if (activeIndex.value activeIndex.value = userGroup.value.length - 1; } else { activeIndex.value--; } } else if (e.key === "Enter") { selectAtUser(userGroup.value[activeIndex.value]); }}// 给父组件传递选择的群员function selectAtUser(user) { emit("atUser", user);} position: fixed;}.user-list { list-style: none; padding: 0; border: 1px solid #e1e1e1; border-radius: 6px;}.user-item { height: 50px; line-height: 50px; padding: 0 20px; cursor: pointer; background-color: white; &:hover, &.active { background-color: #e1e1e1; } &:not(:last-of-type) { border-bottom: 1px solid #e1e1e1; } img { width: 30px; vertical-align: middle; }} name: "用户A", id: 1, avatar: require("@/assets/logo.png") }, { name: "用户B", id: 2, avatar: require("@/assets/logo.png") }, { name: "用户C", id: 3, avatar: require("@/assets/logo.png") },]);// 用户列表定位const userGroupPosition = reactive({ x: "0px", y: "0px",});let showAtSelect = ref(false);
p定义输入事件,当输入@时,获取输入框光标相对页面坐标,并显示输入框组件。(失焦时,在失焦事件getAfterBlurIndex里,使用 setTimeout(() => {

showAtSelect.value = false;}, 100);隐藏艾特组件)

// 输入框输入事件function msgInputFun(e) {  if (e.data === "@") {    setTimeout(() => {      const { x, y } = getCursorPosition();      showAtSelect.value = true;      userGroupPosition.x = x + "px";      userGroupPosition.y = y + "px";    }, 100);  } else {    showAtSelect.value = false;  }}// 获取输入框中的光标相对页面的坐标function getCursorPosition() {  let sel = window.getSelection();  let range = document.createRange();  range.selectNode(sel.focusNode);  range.setStart(sel.focusNode, sel.focusOffset);  const { x, y } = range.getBoundingClientRect();  return { x, y };}

这个时候可以显示出来群员选择列表了,再来定义键盘事件,在列表组件显示时阻止上下按钮的默认行为。如果不显示且按下回车时发送消息

// 显示艾特选择组件时,阻止输入框默认上下按键及回车行为function msgInputKeyDown(e) {  if (showAtSelect.value && ["ArrowUp", "ArrowDown", "Enter"].includes(e.key)) {    return e.preventDefault();  }  if (e.key === "Enter") {    e.preventDefault();    sendMsg();  }}

然后编写选择群员事件,先获取并设置输入框选区,创建一个span标签节点,把被艾特人相关信息填入后插入到输入框子节点里。注意:创建的span标签里写了一个@,所以需要chatInputOffset.deleteContents()删除原@字符

function selectAtUser(user) {  showAtSelect.value = false;  msgInput.value.blur();  getInputSelection();  chatInputOffset.setStart(focusNode, focusOffset.value - 1);  chatInputOffset.setEnd(focusNode, focusOffset.value);  chatInputOffset.deleteContents();  const atElement = `${user.id}' userName='${user.name}' contentEditable="false"  >@${user.name} `;  chatInputOffset.collapse(false);  const node = chatInputOffset.createContextualFragment(atElement);  let c = node.lastChild;  chatInputOffset.insertNode(node);  if (c) {    chatInputOffset.setEndAfter(c);    chatInputOffset.setStartAfter(c);  }  let j = window.getSelection();  j.removeAllRanges();  j.addRange(chatInputOffset);}

这个时候就可以把@消息发送出去了

let msgType = ref("text"); // 发送的消息类型function sendMsg() {  console.log("msgInput:", msgInput);  chatMsgRecord.value = ""; // 先清空一下旧消息  msgType.value = "text"; // 初始化消息类型  msgInput.value.childNodes.forEach((element) => {    // 如果是emoji表情图片的话,则转义    if (element.nodeName === "IMG" && element.className === "emoji") {      chatMsgRecord.value += element.alt;    } else if (element.className === "at-msg") {      chatMsgRecord.value += element.innerText + " ";      msgType.value = "groupChatAt"; // 根据实际约束类型修改    } else {      chatMsgRecord.value += element.data;    }  });  // 清空输入框中的内容  msgInput.value.innerHTML = "";  msgInput.value.innerText = "";  // 在这里使用websocket把数据发送给后端  // socketSend({text:chatMsgRecord,type:msgType})}

如有更好的意见欢迎在评论区指出!

上一篇:怎么样查找网站服务器?

下一篇:服务器 端口在哪里?