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 = true
        state.message = ''
        inputMessage.innerHTML = ''
        state.sendTipTimeout = setTimeout(() => {
            state.sendTip = false
            state.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去显示 

最终效果图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/708579.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

电脑屏幕怎么显示提醒事项 电脑桌面提醒事项设置

在这个信息爆炸的时代&#xff0c;我们每个人都像是被数据洪流裹挟着前进。工作中&#xff0c;生活中&#xff0c;无数琐碎而重要的事情需要我们记忆和处理。有时&#xff0c;仅仅依靠大脑去记住所有事情&#xff0c;真的让人头疼。特别是对于那些整日面对电脑的办公族来说&…

Python基础教程(十一):数据结构汇总梳理

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; &#x1f49d;&#x1f49…

使用C#快速搭建一个在windows运行的exe应用

文章目录 一、前言1.1 编写语言需要工具1.2 选择自己需要的组件进行安装 二、新建项目1.1 新建一个 .NET4.x 的项目1.2 添加一个小案例1.3 对界面进行美化1.3.1、配置Form属性1.3.2、配置Button按钮 1.4 查看组将的相关代码 三、后记 一、前言 这是一个比较旧的内容&#xff0…

java调用GDAL及JTS实现生成泰森多边形(Voronoi图)的一种方法

目录 一、关于泰森多边形 1.泰森多边形的特性 2.本文的目的 二、实现思路 1.gdal和jts库的maven坐标 2.jts生成泰森多边形的关键代码 3.使用GDAL读取源文件信息的关键代码 4.使用GDAL将生成的泰森多边形写入文件 三、实现结果 1.实现的效果 2.完整代码示例 一、关于…

【STM32】飞控设计

【一些入门知识】 1.飞行原理 【垂直运动】 当 mg&#xff1e;F1F2F3F4&#xff0c;此时做下降加速飞行 当 mg&#xff1c;F1F2F3F4&#xff0c;此时做升高加速飞行 当 mgF1F2F3F4 &#xff0c;此时垂直上保持匀速飞行。 【偏航飞行】 ω 4 ω 2 ≠ ω 1 ω 3 就会产生水…

【CT】LeetCode手撕—200. 岛屿数量

目录 题目1-思路2- 实现⭐200. 岛屿数量——题解思路 3- ACM实现 题目 原题连接&#xff1a;200. 岛屿数量 1-思路 利用 dfs 深搜&#xff0c;遇到岛屿直接将岛屿填充为 0 2- 实现 ⭐200. 岛屿数量——题解思路 class Solution {public int numIslands(char[][] grid) {int …

开源WebGIS全流程常用技术栈

1 数据生产 1.1 uDig uDig&#xff08;http://udig.refractions.net/&#xff09;是一个基于Java开源的桌面应用框架&#xff0c;它构建在Eclipse RCP和GeoTools&#xff08;一个开源的Java GIS包)上。可以进行shp格式地图文件的编辑和查看&#xff1b;是一个开源空间数据查看…

5月产品更新 | 10大更新汇总,快来看看你的需求上线了吗?

5月&#xff0c;Smartbi从客户需求出发&#xff0c;并结合企业在数据分析、处理等方面遇到的问题&#xff0c;对数据模型、数据指标等数十项功能进行了优化升级。 Smartbi用户可以在官网下载下载PC端&#xff0c;更新后便可以使用相关功能&#xff0c;也可以在体验中心体验相关…

mybatis之特殊SQL的执行

1.1模糊查询 尝试&#xff1a; //模糊查询用户 List<User> getUserByLike(Param("mohu") String mohu);<select id"getUserByLike" resultType"user">select * from user where username like %#{mohu}% </select>Test publ…

DP:两个数组的dp问题

解决两个数组的dp问题的常用状态表示&#xff1a; 1、选取第一个字符串[0-i]区间以及第二个字符串[0,j]区间作为研究对象 2、根据题目的要求确定状态表示 字符串dp的常见技巧 1、空串是有研究意义的&#xff0c;引入空串可以帮助我们思考虚拟的边界如何进行初始化。 2、如…

jenkins使用注意问题

1.在编写流水线时并不知道当前处在哪个目录&#xff0c;导致名使用不当&#xff0c;以及文件位置不清楚 流水线任务默认路径是&#xff0c;test4_mvn为jenkins任务名 [Pipeline] sh (hide)pwd /var/jenkins_home/workspace/test4_mvn maven任务也是&#xff0c;看来是一样的…

【Linux】Linux环境基础开发工具_6

文章目录 四、Linux环境基础开发工具gdb 未完待续 四、Linux环境基础开发工具 gdb 我们已经可以写代码了&#xff0c;也能够执行代码了&#xff0c;但是代码错了该如何调试呢&#xff1f;Linux中可以使用 gdb 工具进行调试。 我们写一个简单的程序&#xff1a; 但是我们尝试…

微信小程序毕业设计-实验室管理系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

智慧工地:构筑未来建筑的智能脉络

在科技日新月异的今天&#xff0c;智慧城市的建设已不再局限于城市生活的方方面面&#xff0c;而是深入到了城市发展的每一个细胞——工地。本文旨在深度剖析智慧工地的核心价值、关键技术及对建筑业转型升级的深远影响。 一、智慧工地&#xff1a;定义与愿景 智慧工地是指运…

【智能家居控制系统项目】一、项目系统镜像烧录与系统登录

前言 完成本章节将可以获得本项目的系统UI界面功能。本章节主要介绍如何烧录项目系统镜像以及进入系统。配套的视频介绍可以点击跳转到智能家居项目复刻配套视频 1.系统功能页面介绍 完成本章全部步骤&#xff0c;我们将可使用以下项目系统功能界面。 1.1 家居总览界面 主界面…

Zynq学习笔记--AXI4-Stream到视频输出IP是如何工作的?

目录 1. 简介 2. 原理详解 2.1 示例工程 2.2 AXI4-Stream to Video Out 3. Master/Slave Timing Mode 3.1 Slave Timing Mode 3.2 Master Timing Mode 4. 总结 1. 简介 本文主要介绍了 AXI4-Stream 到视频输出 的内容。其中&#xff0c;示例工程展示了一个具体的设计&…

八爪鱼现金流-023-独具特色的加密解决方案

大家一起来记账。 八爪鱼现金流。 独具特色的加密解决方案。金额数据加密后存储到数据库。 保证数据私密性。欢迎试用。 八爪鱼现金流。 点击【八爪鱼现金流-022-mybatis插件加密和国密SM4算法】文章查看详情。

MySQL从入门到高级 --- 15.优化 16.pymysql

文章目录 第十五章 && 第十六章&#xff1a;15.优化15.1 查询SQL执行效率15.2 定位低效率执行SQL15.3 explain分析执行计划 - 基本使用15.4 explain分析执行计划 - id15.5 explain分析执行计划 - select_type15.6 explain分析执行计划 - type15.7 explain分析执行计划 …

实验室管理系统实用性体现在哪些方面?

随着技术的不断进步和应用的不断深入&#xff0c;在当今的检验检测行业中&#xff0c;实验室管理系统的实用性成为了保证质量检测工作正常有效开展的基础&#xff0c;其重要性不言而喻。而实验室信息管理系统&#xff08;LIMS&#xff09;实用性不仅体现在其对实验室日常运作的…

项目实战--文档搜索引擎

在我们的学习过程中&#xff0c;会阅读很多的文档&#xff0c;例如jdk的API文档&#xff0c;但是在这样的大型文档中&#xff0c;如果没有搜索功能&#xff0c;我们是很难找到我们想查阅的内容的&#xff0c;于是我们可以实现一个搜索引擎来帮助我们阅读文档。 1. 实现思路 1…