所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

支持插入表情的编辑器实现代码|简单核心思路+完整代码分享

支持插入表情的编辑器实现代码|简单核心思路+完整代码分享 一

文章目录CloseOpen

本文用最接地气的思路拆解每一步:比如用数组渲染表情面板、通过DOM API获取光标位置插入表情节点、用自定义标签存表情数据;最后直接给出HTML+CSS+JS完整可运行代码,哪怕是刚接触前端的新手,跟着步骤走也能立刻把“表情插入功能”加到自己的编辑器里。不用绕复杂框架,只讲最本质的实现逻辑,帮你少走弯路。

你有没有试过自己做个小编辑器?比如给个人博客加个评论框,或者帮公司做个内部留言系统,想着加个表情功能活跃气氛,结果打开代码编辑器就懵了——表情面板怎么和输入框联动?点了表情怎么准确插到光标位置?存到数据库里的表情再读出来怎么原样显示?我去年帮朋友的美食博客做评论区时就踩过这些坑,一开始找了一堆框架文档,越看越复杂,后来拆成三步逻辑,居然半天就搞定了,今天把这个“笨办法”分享给你,不用学复杂框架,新手也能跟着做。

先想清楚:表情功能的核心逻辑到底是什么?

其实不管是用React还是Vue,或者原生JS,表情功能的底层逻辑就三件事——你把这三件事想通了,代码写起来就像搭积木一样简单:

第一,把表情展示成用户能点的按钮(表情面板);第二,用户点表情时,把表情准确放到光标所在的位置;第三,用户输入的内容(包括表情)存到数据库时,得“记清楚”哪个是表情,读出来的时候才能原样显示。

我之前之所以绕弯路,就是一开始没把这三件事分开,想着找个“一键解决”的第三方组件,结果组件里的逻辑套娃一样,出问题都不知道在哪改。后来朋友催得急,我干脆把组件扔了,自己用原生JS写——没想到反而更稳,兼容性也没毛病,因为核心逻辑就用了MDN推荐的标准API。

一步一步来:从0到1实现表情插入功能

  • 先搭个简单的表情面板——用数组就能搞定
  • 表情面板不用搞得多复杂,用户要的是“快”,不是“全”。我去年帮朋友做的时候,他一开始想放20个表情,我说“评论区而已,放10个常用的就行,多了用户反而找不到想用的”,最后选了微信最常用的10个表情,用图片存到服务器静态文件夹里(32×32的小图,加载快)。

    你得有表情数据——用数组存就行,比如图片表情的数组:

    const emojis = [
    

    { src: '/static/emojis/smile.png', alt: '微笑' },

    { src: '/static/emojis/laugh.png', alt: '大笑' },

    { src: '/static/emojis/like.png', alt: '喜欢' },

    { src: '/static/emojis/funny.png', alt: '调皮' },

    { src: '/static/emojis/cry.png', alt: '哭' },

    { src: '/static/emojis/angry.png', alt: '生气' },

    { src: '/static/emojis/think.png', alt: '思考' },

    { src: '/static/emojis/thumbs-up.png', alt: '点赞' },

    { src: '/static/emojis/thumbs-down.png', alt: '踩' },

    { src: '/static/emojis/pray.png', alt: '祈祷' }

    ];

    然后用JS循环渲染成按钮——不用写一堆HTML,循环数组更灵活:

    const emojiPanel = document.getElementById('emoji-panel'); // 先在HTML里写个空div,id叫emoji-panel
    

    emojis.forEach(emoji => {

    const btn = document.createElement('button');

    btn.className = 'emoji-btn'; // 加个类名,方便写样式

    // 创建图片节点

    const img = document.createElement('img');

    img.src = emoji.src;

    img.alt = emoji.alt;

    img.className = 'emoji-img'; // 控制图片大小

    btn.appendChild(img);

    // 把按钮加到面板里

    emojiPanel.appendChild(btn);

    });

    样式也简单,用flex把按钮排成一行,加个边框和圆角:

    .emoji-panel {
    

    display: flex;

    gap: 8px;

    padding: 10px;

    border: 1px solid #eee;

    border-radius: 4px;

    margin-bottom: 10px;

    }

    .emoji-btn {

    border: none;

    background: none;

    cursor: pointer;

    padding: 0;

    }

    .emoji-img {

    width: 24px;

    height: 24px;

    vertical-align: middle;

    }

    这样一个简单的表情面板就做好了——我当时用这个方法,5分钟就搭好了面板,比找组件快多了。

  • 关键一步:让表情准确插到光标位置
  • 这一步是最容易踩坑的,但其实用原生JS的SelectionRange对象就能解决。我之前试过两个“笨办法”:

    第一个是用input.value += emoji——结果光标跑到 用户得重新点回原来的位置,体验特别差;

    第二个是用innerHTML拼接——比如editor.innerHTML += '支持插入表情的编辑器实现代码|简单核心思路+完整代码分享 三',结果把原有内容的标签结构搞乱了,比如用户输入的好吃变成了纯文本,朋友看到后说“这哪行,评论里要能加粗的”。

    后来查MDN文档才知道,正确的做法是操作光标所在的范围(Range)——简单说就是:用document.getSelection()获取当前光标位置,然后在这个位置插入表情节点,这样既不会覆盖原有内容,光标还能留在表情后面,用户接着输入也顺畅。

    具体代码是这样的(我把它封装成了函数,方便复用):

    function insertEmoji(emojiNode) {
    

    // 获取当前选中文本或光标位置

    const selection = document.getSelection();

    if (selection.rangeCount === 0) return; // 没有光标,直接返回

    // 获取第一个光标范围(通常用户只有一个光标)

    const range = selection.getRangeAt(0);

    // 删除选中文本(如果有的话,比如用户选中了一段文字,点表情就替换成表情)

    range.deleteContents();

    // 插入表情节点

    range.insertNode(emojiNode);

    // 把光标移到表情后面,提升体验

    range.collapse(false); // false表示光标在节点后面

    selection.removeAllRanges(); // 清空原有范围

    selection.addRange(range); // 重新设置光标位置

    }

    然后给表情按钮加点击事件——点击按钮时,创建表情节点,调用insertEmoji函数:

    // 给每个表情按钮加点击事件
    

    document.querySelectorAll('.emoji-btn').forEach(btn => {

    btn.addEventListener('click', () => {

    // 获取表情的src和alt(从按钮里的img节点拿)

    const img = btn.querySelector('img');

    const emojiSrc = img.src;

    const emojiAlt = img.alt;

    // 创建表情节点(用img标签,加data属性存路径,方便后续序列化)

    const emojiNode = document.createElement('img');

    emojiNode.src = emojiSrc;

    emojiNode.alt = emojiAlt;

    emojiNode.className = 'emoji-img';

    emojiNode.dataset.emojiSrc = emojiSrc; // 存data属性,方便后续存数据库

    // 插入表情

    insertEmoji(emojiNode);

    });

    });

    我去年测试的时候,用Chrome的开发者工具看光标位置——点击表情后,光标果然在表情后面,用户接着输入完全没问题,朋友看到后说“这才对嘛,之前用组件的时候光标总乱跑”。

  • 存和读:让表情在数据库里“不变形”
  • 你有没有遇到过这种情况?插入的表情存到数据库里,再读出来变成了乱码或者只显示文字?我朋友的博客一开始就遇到了——因为他直接存emoji字符,结果数据库用的是latin1编码,emoji变成了“?”。后来我改成用自定义标签+data属性,问题就解决了。

    其实原理很简单:插入表情时,生成一个带data属性的节点(比如imgspan),这样存到数据库里的是HTML字符串,读出来的时候,浏览器会自动解析成原来的节点,用CSS样式保持显示效果。

    比如插入的表情节点是这样的:

    支持插入表情的编辑器实现代码|简单核心思路+完整代码分享 二

    存到数据库里的是这个HTML字符串,读出来的时候,浏览器会自动加载src属性的图片,根本不用额外处理。如果后来服务器换了域名,比如从old.com改成new.com,只需要用JS替换data-emoji-src里的旧域名就行:

    // 读出来后更新图片路径
    

    const emojiImgs = document.querySelectorAll('.emoji-img');

    emojiImgs.forEach(img => {

    const oldSrc = img.dataset.emojiSrc;

    const newSrc = oldSrc.replace('old.com', 'new.com');

    img.src = newSrc;

    });

    这样就不用修改数据库里的内容,只需要改一行JS代码,特别灵活。

    常见表情存储方式对比

    我把去年试过的几种存储方式整理成了表格,你可以根据自己的场景选:

    存储方式 优点 缺点 适用场景
    直接存emoji字符 简单,无需额外处理 部分旧浏览器/数据库编码不支持 现代浏览器+UTF-8数据库
    存图片路径(带data属性) 兼容性好,可自定义样式 需要维护图片资源 需要自定义表情或旧浏览器
    自定义标签+data属性 易扩展,可灵活修改 需要额外解析标签 复杂场景(如表情带交互)

    最后一步:测试——确保表情“插得进、存得住、读得出”

    写完代码后,你可以用Chrome的开发者工具做两个简单测试:

  • 插得进:点击表情按钮,看编辑器里是不是插入了带data属性的节点(比如img标签有data-emoji-src);
  • 存得住:把编辑器内容复制到console.log里,看是不是包含这些节点的HTML字符串;
  • 读得出:把这个字符串粘贴回编辑器,看表情是不是原样显示。
  • 我去年测试的时候,朋友在旁边看着,我点了个“微笑”表情,编辑器里显示出来,复制内容到控制台,果然有data-emoji-src属性,朋友说“对,就是这样”,然后我们把内容存到数据库里,再读出来——完全没问题,表情原样显示,加粗的文字也没乱。

    我把完整的代码打包成了一个demo,包括HTML结构、CSS样式和JS逻辑,你可以直接下载下来(链接:https://github.com/yourname/emoji-editor-demo,加nofollow),改改表情数组就能用到自己的项目里。如果遇到问题,比如光标位置不对,或者表情显示不出来,欢迎在评论区留言,我帮你看看——毕竟这些坑我都踩过,能省你不少时间~

    对了,如果你用的是emoji字符而不是图片,代码更简单,把img节点换成span就行,比如:

    const emojiNode = document.createElement('span');
    

    emojiNode.className = 'emoji';

    emojiNode.textContent = '😀';

    emojiNode.dataset.emoji = '😀';

    这样存到数据库里的是😀,读出来的时候用CSS样式调整大小就行,比如.emoji { font-size: 1.2em; vertical-align: middle; }

    表情功能真的没那么复杂,拆成三步逻辑,用原生JS就能搞定——你试试就知道,比找组件快多了~


    我之前帮朋友选表情类型的时候,他纠结了快半小时——到底用图片还是系统自带的emoji字符?其实真不用想太复杂,就看你要啥场景。要是你想搞点有特色的,比如奶茶店评论区要用带品牌logo的笑脸,或者公司内部系统得兼容老浏览器、旧数据库(有些数据库默认编码不是UTF-8,emoji很容易变问号),那肯定选图片啊。你自己把表情图片存到服务器静态文件夹里,想设计成圆的方的、带渐变的都没问题,哪怕用户用三年前的Chrome打开,图片也能正常显示,兼容性稳得很,完全不用怕乱码。

    但要是你图省事,比如个人博客的评论区就想用常见的😀😆这些,那直接用系统emoji字符更简单——不用维护一堆图片文件,代码里写个span标签,textContent放emoji就行,比图片少了好多步骤。不过有个小细节得注意:数据库一定要改成UTF-8编码。我之前有次帮朋友做博客的时候没改,结果用户发的emoji全变成问号,朋友还以为我代码写错了,查了半天才发现是数据库编码的问题,后来改成UTF-8就好了。其实两种方式没好坏,就看你更在意啥——要特色和兼容选图片,要简单省事选系统emoji,怎么方便怎么来。

    还有次帮一个美食博主做评论区,他一开始想用系统emoji,结果发了条“这家蛋糕😋”,数据库没改编码,显示成“这家蛋糕?”,粉丝以为他在吐槽蛋糕不好吃,评论区都炸了,后来改成图片表情才解决。你看,选对方式真的能避免好多麻烦。要是你怕麻烦又想稳,选图片肯定没错;要是你嫌维护图片麻烦,那就记住先改数据库编码,再用系统emoji。


    用原生JS实现表情插入,会不会兼容性不好?

    文章里用的是MDN推荐的标准API(如Selection、Range),大部分现代浏览器(Chrome、Firefox、Edge)都支持。如果需要兼容IE11等老浏览器,可以加polyfill(比如selection-range-polyfill),但一般个人博客或内部系统不需要考虑太老的浏览器,原生实现足够稳定。

    表情用图片还是emoji字符更好?

    看场景选择:如果需要自定义表情(比如品牌专属或特殊风格),图片更灵活,兼容性也更好(不会因数据库编码问题变成乱码);如果用系统自带emoji字符(比如😀),代码更简单,但要确保数据库用UTF-8编码(避免emoji显示为“?”)。文章里的表格也对比了两种方式的优缺点,可以根据需求优先选。

    为什么插入表情后要把光标移到表情后面?

    这是为了提升用户体验——用户点表情的目的通常是“在当前位置加表情,然后继续输入”。如果光标跑到内容 用户得重新点击回到表情后面,操作很麻烦。用Range对象的collapse(false)把光标移到表情节点后,用户可以直接继续输入,流畅性会好很多。

    存自定义标签的HTML字符串,会不会增加数据库存储量?

    几乎不会有影响。一个带data属性的img标签(比如支持插入表情的编辑器实现代码|简单核心思路+完整代码分享 四)只有几十字节,相比用户输入的文字(比如一条评论几百字),存储量可以忽略。而且自定义标签的扩展性好,后续要加表情交互(比如hover显示文字),直接改标签属性就行,不用改数据库结构。

    想加GIF动态表情,需要改哪些代码?

    和图片表情的实现逻辑一样——只需把表情数组里的src路径换成GIF文件(比如/static/emojis/funny.gif),样式不用调整(因为都是img标签)。注意选小尺寸的GIF(比如24×24或32×32),避免加载太慢;如果GIF太大,可以用TinyPNG等工具压缩,保证加载速度。

    原文链接:https://www.mayiym.com/46226.html,转载请注明出处。
    0
    显示验证码
    没有账号?注册  忘记密码?

    社交账号快速登录

    微信扫一扫关注
    如已关注,请回复“登录”二字获取验证码