当前位置: 首页 > article >正文

【前端】Twemoji(Twitter Emoji)

目录

  • 注意
  • 使用
    • Vue / React 项目
  • 验证

  • Twemoji 的作用:
    Twemoji 会把你网页/应用中的 Emoji 字符(如 😄)自动替换为 Twitter 风格的图片(SVG/PNG);
    它不依赖系统字体,因此在 Android、Windows、macOS、iOS 等系统上都能显示统一的视觉效果;但显示出来的 不是 Apple emoji的风格,而是 Twitter 的风格。
场景是否能解决
安卓显示苹果风格 Emoji无法使用 Apple 的图形❌
安卓系统不支持新 Emoji,无法显示用图像替代,兼容所有新旧设备
各系统 Emoji 风格不统一Twemoji 保证所有平台一致
不依赖用户系统字体
可自定义大小、样式、加载策略

注意

npm 包用的也是maxcdn的地址,但是maxcdn已经崩溃了。
之后所有的twemoji.parse都应该修改base

import twemoji from 'twemoji';export default {install(app: any) {app.directive('twemoji', {mounted(el: HTMLElement) {twemoji.parse(el, {base: 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/'});},updated(el: HTMLElement) {twemoji.parse(el,{base: 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/'});}});}
};
//这样就可以正常加载了

国内源https://cdn.jsdmirror.com/gh/twitter/twemoji@14.0.2/assets/
cdn.jsdmirror.com

  • emoji显示大小调整
    Twemoji 默认插入的 <img> 标签没有限制尺寸,导致显示时占用过多空间。
/* 全局限制 twemoji img 大小 */
img.emoji, img.emoji-svg {display:inline-block;width: 1em;height: 1em;vertical-align: -0.1em; /* 调整与文字基线对齐 */
}

使用

  1. CDN引入
<script src="https://twemoji.maxcdn.com/v/latest/twemoji.min.js"></script>
  1. 在页面加载后执行解析
<script>document.addEventListener('DOMContentLoaded', function () {twemoji.parse(document.body, {folder: 'svg', // svg 或 72x72(PNG 图片)ext: '.svg'    // 或 '.png'});});
</script>

Vue / React 项目

  • 安装
npm install twemoji
  • 全局应用 Twemoji(也就是全站的 Emoji 都自动替换为 Twemoji 风格)方案:
框架推荐方式说明
Vue 3创建自定义指令 / 全局组件自动处理所有含 Emoji 的元素
React使用全局解析函数(如 HOC 或 Layout hook)在渲染后全局替换 DOM 中 Emoji
//vue 全局应用 
//(用于 layout组件 或 app.vue)
<script setup>
import { onMounted } from 'vue';
import twemoji from 'twemoji';onMounted(() => {twemoji.parse(document.body, {folder: 'svg',ext: '.svg'});
});
</script>//react全局应用
//方法1 在 Layout / App.jsx 中统一解析
import React, { useEffect } from 'react';
import twemoji from 'twemoji';function App() {useEffect(() => {twemoji.parse(document.body, {folder: 'svg',ext: '.svg'});}, []);//只会在组件首次渲染(挂载)到 DOM 之后执行一次,return (<div><h1>Hello React 😄❤️🎉</h1>{/* 其他页面组件 */}</div>);
}
export default App;//方法2 创建高阶组件(HOC)包裹需要解析的组件
//接收组件 返回包装好的新组件
import twemoji from 'twemoji';
import { useEffect, useRef } from 'react';export function withTwemoji(Component) {return function Wrapped(props) {const ref = useRef();useEffect(() => {if (ref.current) {//ref.current 指的就是 useRef 返回的 ref 对象所实际引用的值twemoji.parse(ref.current, {folder: 'svg',ext: '.svg'});}}, []);return (<div ref={ref}><Component {...props} /></div>);};
}
//需要使用的组件直接使用:
const TwemojiPage = withTwemoji(MyPageComponent);

twemoji.parse() 的作用是:它会扫描传入的 DOM 元素(在这里是 ref.current 所引用的元素)内部的文本内容,找到其中的 Unicode Emoji 字符,然后将这些字符替换成 <img> 标签,而<img>标签的 src 属性指向 Twemoji 的 SVG 图片。ref.current 这个变量本身(它存储的内存地址)没有改变,它依然指向同一个 div 元素。但这个 div 元素内部的子节点和内容被 twemoji.parse 方法修改了。

  • 但vue全局应用的方法可能出现问题:没有生效
    解析时 DOM 内容还没真正渲染完,App.vue 的 onMounted() 仅保证 Vue 根组件挂载,但此时子组件内容可能尚未完全渲染进 DOM;
    解决方法有两种
  1. 用 Layout 页面来做解析(推荐用于中大型项目)
    不要在 App.vue 直接解析,而是把解析放到页面 Layout 或页面组件(如 MainLayout.vue 或 HomePage.vue)中的 onMounted() 中,这样确保 Emoji 渲染后再替换
    推荐在主页面区域加个 id=“main-content” 来明确定位,不要直接操作整个 document.body。
    保证这个区域包裹需要解析的区域
import { onMounted, ref } from 'vue';
import twemoji from 'twemoji';onMounted(() => {const el = document.getElementById('main-content'); // 指定 DOM 区域if (el) {twemoji.parse(el, { folder: 'svg', ext: '.svg' });}
});//最好是使用nextTick 保证获取到的是最新内容
onMounted(() => {nextTick(() => {//等待 Vue 完成本轮 DOM 更新后再执行代码,确保你访问到的是已经渲染进 DOM 的最终结果。if (contentRef.value) {twemoji.parse(contentRef.value, {folder: 'svg',ext: '.svg'});}});//如果带emoji的内容是通过异步加载或父组件传入,也可能不会生效
//Vue 渲染晚于 onMounted,那 Twemoji 在执行时内容还没出现在 DOM。
//解决方法:用 watch 监听变化后再解析
import { watch } from 'vue';
watch(content, () => {nextTick(() => {twemoji.parse(emojiBox.value, { folder: 'svg', ext: '.svg' });});
});//如果内容使用了 v-html,Vue 不会触发 DOM 更新钩子,
// 则twemoji.parse 不会自动处理
  1. 封装成全局自定义指令(最推荐)
    使用 v-twemoji 指令来保证解析的是已经渲染完的 DOM 元素
// plugins/twemoji.js
import twemoji from 'twemoji';export default {install(app) {app.directive('twemoji', {mounted(el) {twemoji.parse(el, { folder: 'svg', ext: '.svg' });},updated(el) {twemoji.parse(el, { folder: 'svg', ext: '.svg' });}});}
};
//在 App.vue、Layout.vue 或任意组件这样使用
<template><div v-twemoji>Hello 😊🎉</div>
</template>
  • 部分应用
//部分应用
//vue
<template><div ref="emojiContainer">{{ message }}</div>
</template><script setup>
import { onMounted, ref } from 'vue';
import twemoji from 'twemoji';const emojiContainer = ref(null);
const message = '你好 Vue 😊❤️🎉';onMounted(() => {twemoji.parse(emojiContainer.value, {folder: 'svg',ext: '.svg'});
});
</script>//react
import React, { useEffect, useRef } from 'react';
import twemoji from 'twemoji';const EmojiText = ({ text }) => {const ref = useRef();useEffect(() => {twemoji.parse(ref.current, {folder: 'svg',ext: '.svg'});}, []);return <div ref={ref}>{text}</div>;
};export default function App() {return <EmojiText text="Hello 😄🎉 from React!" />;
}

验证

使用浏览器开发者工具,检查是否 emoji 被替换为<img>,src来自twemoji…cdn…地址

http://www.lryc.cn/news/2392222.html

相关文章:

  • Electron 桌面程序读取dll动态库
  • 实时技术对比:SSE vs WebSocket vs Long Polling
  • js 手写promise
  • HTTP 与 HTTPS 深度解析:原理、实践与大型项目应用
  • QT6.9中opencv引用路径的其中一种设置
  • k8s pod启动失败问题排查
  • Java类中各部分内容的加载执行顺序
  • git提交信息错误,如何修改远程git提交的备注信息
  • API Gateway CLI 实操入门笔记(基于 LocalStack)
  • 基于MATLAB实现SFA(Slow Feature Analysis,慢特征分析)算法
  • 数据分析案例-基于红米和华为手机的用户评论分析
  • leetcode617.合并二叉树:递归思想下的树结构融合艺术
  • 深度学习入门:从零搭建你的第一个神经网络
  • 【HTML-13】HTML表格合并技术详解:打造专业数据展示
  • 鸿蒙OSUniApp 制作自定义的进度条组件#三方框架 #Uniapp
  • 【Python办公】Excel简易透视办公小工具
  • m1 运行renrenfastvue出现的问题和解决方案
  • 开源模型应用落地-qwen模型小试-Qwen3-8B-推理加速-vLLM-Docker(二)
  • 【C/C++】记录一次麻烦的Kafka+Json体验
  • Linux系列-2 Shell常用命令收集
  • MATLAB使用多个扇形颜色变化表示空间一个点的多种数值
  • mysql:MVCC机制
  • Vue3 + Element Plus 实现树形结构的“单选 + 只选叶子节点 + 默认选中第一个子节点”
  • CAD精简多段线顶点、优化、删除多余、重复顶点——CAD c#二次开发
  • 输电线路的“智慧之眼”:全天候可视化监测如何赋能电网安全运维
  • Spring 核心知识点补充
  • 两阶段法目标检测发展脉络
  • Flannel 支持的后端
  • 小白的进阶之路系列之六----人工智能从初步到精通pytorch数据集与数据加载器
  • SQL进阶之旅 Day 5: 常用函数与表达式