vue聊天发送Emoji表情
在用web端写聊天发送表情的功能中,使用web端有系统自带的unicode表情会出现每端不统一的情况,不好用不能统一,在这里我想到了一个非常好的思路,可以解决这个问题!
那就是发送表情用图片的形式呈现,然后发给后端解析成自定义的编码标识,靠这个标识来回显!
具体的实现思路是这样的:
先编辑好json数据:
{"/::1f600::/": {"code": "/::1f600::/","name": "Grinning Face","unified": "1f600","img_url": "/static/images/apple_emoji/1f600.png"},"/::1f603::/": {"code": "/::1f603::/","name": "Smiling Face with Open Mouth","unified": "1f603","img_url": "/static/images/apple_emoji/1f603.png"},"/::1f604::/": {"code": "/::1f604::/","name": "Smiling Face with Open Mouth and Smiling Eyes","unified": "1f604","img_url": "/static/images/apple_emoji/1f604.png"},
}
这是一个表情包数据,里面有图片有name还有标识,以键值对的形式,/::1f600::/是相当于一个表情包标识
数据处理好了,接下来最难的是输入框,当我想让表情包在输入框里显示,一般的输入框是不行的,这里用到了div的contenteditable="true"属性,可以让这个div处于编辑模式,跟富文本编辑器一样
先展示html:
<template><div class="chat-room"><div class="input-message mt-5 mb-5 scrollbar" contenteditable="true" @keydown="handleKeyDown" @blur="handleBlur"></div></div>
</template>
表情包用上面那个json数据,展示出来,效果图:
当我点一下这个表情的时候,执行写好的js逻辑,把这个表情图片放到div编辑器里,代码如下:
inputMessage.focus()
var contextMenu = document.createElement('img')//创建一个img元素
contextMenu.setAttribute('data-code', value.code) // 添加自定义属性
contextMenu.className = 'emoji-img'
contextMenu.style.margin = '0 1px'
contextMenu.src = emojiJSON[value.code] ? emojiJSON[value.code].img_url : ''
// 获取当前选区
var selection = window.getSelection()
if (selection.rangeCount > 0) {// 获取选区中的第一个范围var range = selection.getRangeAt(0)// 将范围的起点移到插入节点之前range.insertNode(contextMenu)// 创建一个新的范围,用于设置光标位置var newRange = document.createRange()// 将新范围的起点设置为新插入元素之后newRange.setStartAfter(contextMenu)newRange.collapse(true) // 折叠范围,这样光标就会在新插入元素后// 清空当前选区,并添加新的范围selection.removeAllRanges()selection.addRange(newRange)
}
// 等待 DOM 更新后滚动到底部
nextTick(() => {inputMessage.scrollTop = inputMessage.scrollHeight
})
插入表情效果图:
给你们看下dom结构:
表情跟文字的结合:
现在已经实现了文字跟表情在输入框里显示,接下来继续处理输入框里面的逻辑,实现换行编辑,模仿微信的效果:
//文本域键盘事件
const handleKeyDown = (event) => {if (event.ctrlKey && event.key === 'Enter') {event.preventDefault() // 阻止默认行为const div = document.createElement('div') // 创建一个 <div> 元素div.setAttribute('data-type', 'br') // 添加自定义属性const br = document.createElement('br') // 创建一个 <br> 元素div.appendChild(br) // 将 <br> 元素添加到 <div> 中const selection = window.getSelection()if (selection.rangeCount > 0) {const range = selection.getRangeAt(0)range.deleteContents() // 删除当前选区内容(如果有)range.insertNode(div) // 插入换行符range.setStartAfter(div) // 将光标移到换行符之后range.collapse(true) // 折叠选区selection.removeAllRanges() // 清除所有选区selection.addRange(range) // 添加新的选区}// 等待 DOM 更新后滚动到底部nextTick(() => {inputMessage.scrollTop = inputMessage.scrollHeight})return}if (event.key === 'Enter') {// 在这里执行按下Enter时的操作event.preventDefault() // 阻止默认的回车换行行为sendMessage()}//回退事件if (event.key === 'Enter') {}
}
const handleBlur = () => {inputMessage.focus()
}
现在实现发送效果,这里是核心代码,在发送之前先处理一下数据,解析成后端可以保存的格式:
const sendMessage = () => {const div = document.createElement('div') // 创建一个 <div> 元素div.innerHTML = inputMessage.innerHTML// 使用正则表达式进行替换function replaceNestedDivs(html) {// 定义正则表达式以匹配 <div data-type="br">...</div> 标签,并捕获其中的内容和 <img> 标签(如果有的话)const regex = /<div\s+data-type="br">(.*?)(<img[^>]*>)?/gi// 使用替换函数对匹配到的内容进行处理return html.replace(regex, function (match, p1, p2) {const content = p1 ? p1.trim() : '' // 去除捕获文本内容的前后空格const imgTag = p2 ? ` ${p2}` : '' // 如果捕获的 <img> 标签存在,则返回空格加上该标签// 返回处理后的内容和 <img> 标签return `\n${content}${imgTag}`})}div.innerHTML = replaceNestedDivs(div.innerHTML)div.innerHTML = div.innerHTML.replace(/<img\s+data-code="([^"]+)"[^>]*>/g, '$1')state.message = div.innerText// 如果文本内容不为空,则执行提交操作if (state.message) {state.messageList.push({id: 2,content: initMessage(state.message),time: '2024-6-5 15:41',type: 'system_user',avatar: 'https://www.wenpblog.com/cdn/static/header/2812.png',})state.message = ''inputMessage.innerHTML = ''initScroll()} else {if (state.sendTipTimeout) {return}state.sendTip = truestate.message = ''inputMessage.innerHTML = ''state.sendTipTimeout = setTimeout(() => {state.sendTip = falsestate.sendTipTimeout = null}, 1500)}
}//处理聊天数据
const initMessage = (text) => {// 定义一个函数来将特定格式的字符串替换为图片function replaceWithEmojiImages(text) {// 定义一个正则表达式来匹配 /::1f600::/ 格式的字符串const regex = /\/::(.*?)::\//g// 使用 replace 方法和回调函数进行替换return text.replace(regex, (match, p1) => {// 构建图片标签const imgSrc = `${emojiJSON[match] ? emojiJSON[match].img_url : ''}` // 假设图片存储在这个路径return `<img data-code="${match}" src="${imgSrc}" class="emoji-img"/>`})}// 调用函数进行替换const outputText = replaceWithEmojiImages(text)return outputText
}
传给后端的解析后数据:
/::1f600:://::1f602::/啊是大飒飒的啊是大/::1f60d::/,太搞笑; /::1f602::/
注意:回显消息的时候,需要用v-html去显示
最终效果图:
相关文章:

vue聊天发送Emoji表情
在用web端写聊天发送表情的功能中,使用web端有系统自带的unicode表情会出现每端不统一的情况,不好用不能统一,在这里我想到了一个非常好的思路,可以解决这个问题! 那就是发送表情用图片的形式呈现,然后发给…...

360数字安全:2024年4月勒索软件流行态势分析报告
勒索软件传播至今,360 反勒索服务已累计接收到数万勒索软件感染求助。随着新型勒索软件的快速蔓延,企业数据泄露风险不断上升,勒索金额在数百万到近亿美元的勒索案件不断出现。勒索软件给企业和个人带来的影响范围越来越广,危害性…...

【MySQL】日志详解
本文使用的MySQL版本是8 日志概览 它们记录了数据库系统中的不同操作和事件,以便于故障排除、性能优化和数据恢复。本文将介绍MySQL中常见的几种日志,同时也会介绍一点常用的选项。 官方文档:MySQL :: MySQL 8.0 Reference Manual :: 7.4 M…...
MyBatis 延迟加载,一级缓存,二级缓存设置
MyBatis不仅提供了一级缓存和二级缓存机制,还支持延迟加载(Lazy Loading),以进一步优化性能。 1. 延迟加载(Lazy Loading) 延迟加载是在需要时才加载数据,而不是在查询时立即加载所有相关数据。…...

Linux 基本指令2
cp 指令 cp[选项]源文件 目标文件 将源文件的内容复制到目标文件中,源文件可以有多个,最后一个文件为目标文件,目标文件也可以是一段路径,若目的地不是一个目录的话会拷贝失败。若没有路径上的目录则会新建一个,若源是…...
联邦学习的基本流程,联邦学习权重聚合,联邦学习权重更新
目录 联邦学习的基本流程是 S_t = np.random.choice(range(K), m, replace=False) 联邦学习权重聚合 model.state_dict() 联邦学习权重更新 下载数据集 https://ossci-datasets.s3.amazonaws.com/mnist/train-images-idx3-ubyte.gz 联邦学习的基本流程是 **1. server初始…...

React保姆级教学
React保姆级教学 一、创建第一个react项目二、JSX基本语法与react基础知识1、 插值语法:2、 循环一个简单列表3、 实现简单条件渲染4、 实现复杂的条件渲染5、 事件绑定6、 基础组件(函数组件)7、 使用useState8、 基础样式控制9、 动态类名1…...

数据结构和矩阵细节用法:double、cell和complex #matlab
矩阵建立 建立矩阵用[]; 矩阵的同一行内的元素用逗号或者空格隔开; 矩阵的不同行的元素用分号隔开 eg. 矩阵 A 1 2 3 4 5 6 7 8 9 在matlab中矩阵A表示为: clc;clear; A[1,2,3;4,5,6;7,8,9]; %或者A[1 2 3;4 5 …...

12. Django 第三方功能应用
12. 第三方功能应用 因为Django具有很强的可扩展性, 所以延伸了第三方功能应用. 通过本章的学习, 读者能够在网站开发过程中快速实现API接口开发, 验证码生成与使用, 站内搜索引擎, 第三方网站实现用户注册, 异步任务和定时任务, 即时通信等功能.12.1 Django Rest Framework框…...
UnityWebRequest获取本地txt文件,其中中文乱码问题(踩坑记录)
Unity获取本地streamingassert下txt文件,遇到点问题,就是用UnityWebRequest下载一个txt文件的时候,原txt在资源管理器用notepad打开显示正常,但是Unity里调试,打印内容却是乱码, 在notepad 转存为utf-8&…...

轮到国产游戏统治Steam榜单
6月10日晚8点,《黑神话:悟空》实体版正式开启全款预售,预售开启不到5分钟,所有产品即宣告售罄。 Steam上,《黑神话:悟空》持续占据着热销榜榜首的位置。 但在《黑神话:悟空》傲人的光环下,还有一款国产游戏取得出色的成绩。 6月10日&#…...

不想搭集群,直接用spark
为了完成布置的作业,需要用到spark的本地模式,根本用不到集群,就不想搭建虚拟机,hadoop集群啥的,很繁琐,最后写作业还用不到集群(感觉搭建集群对于我完成作业来说没有什么意义)&…...

【MATLAB源码-第225期】基于matlab的计算器GUI设计仿真,能够实现基础运算,三角函数以及幂运算。
操作环境: MATLAB 2022a 1、算法描述 界面布局 计算器界面的主要元素分为几大部分:显示屏、功能按钮、数字按钮和操作符按钮。 显示屏 显示屏(Edit Text):位于界面顶部中央,用于显示用户输入的表达式和…...
Scikit-learn 基础教程:机器学习的初步指南
Scikit-learn 是一个用于数据挖掘和数据分析的机器学习库,建立在 NumPy、SciPy 和 matplotlib 之上。它提供了简单而高效的工具来进行数据分析和建模。本文将为您介绍 Scikit-learn 的安装方法、核心组件,以及如何应用这些组件进行一个简单的机器学习项目…...

开源WebGIS全流程常用技术栈
1 数据生产 1.1 uDig uDig(http://udig.refractions.net/)是一个基于Java开源的桌面应用框架,它构建在Eclipse RCP和GeoTools(一个开源的Java GIS包)上。可以进行shp格式地图文件的编辑和查看;是一个开源空间数据查看…...
前端开发之HTTP协议认识
上一篇👉: 前端开发之WebSocket通信 文章目录 1. HTTP 1.0 和 HTTP 1.1 之间有哪些区别1.连接方面:2.资源传输优化:3.缓存机制增强:4.主机头识别5.请求方法扩展 2.HTTP 1.1 和 HTTP 2.0 的区别1. 二进制分帧层:2.多路…...
力扣刷题总结 -- 数组26
76. 所有奇数长度子数组的和(简单) 题目要求: 给定一个正整数数组 arr ,计算所有奇数长度子数组的和。 子数组定义为原数组中的一个连续子序列。 返回 arr 中 所有奇数长度子数组的和 。 题目分析: 先得到所有子…...

无线MODBUS通讯模块在供水系统中的应用
一、项目背景 我国是人口大国、农业大国,同时也是贫水大国。由于大量工业废水污染了部分河流、地表的浅层水资源,并且有逐年加重的趋势,再加上农业、绿化等灌溉对水资源的大量消耗,这些因素综合作用进一步加剧了我国水资源紧缺的…...
linux为什么不是实时操作系统
Linux为什么不是实时操作系统? 从我们接触Linux系统开始,一直听到的都是它是非实时操作系统,怎么理解这个非实时呢? 我的理解,非实时,就是中断响应不及时,任务调度不及时。那么,真…...

【STM32】飞控设计
【一些入门知识】 1.飞行原理 【垂直运动】 当 mg>F1F2F3F4,此时做下降加速飞行 当 mg<F1F2F3F4,此时做升高加速飞行 当 mgF1F2F3F4 ,此时垂直上保持匀速飞行。 【偏航飞行】 ω 4 ω 2 ≠ ω 1 ω 3 就会产生水…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...

ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...

中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...