H5页面小程序如何实现emoji表情?
发表时间:2023-10-05 17:54:16
文章来源:炫佑科技
浏览次数:211
菏泽炫佑科技 菏泽炫佑小程序开发 菏泽炫佑app制作 炫佑科技
H5页面小程序如何实现emoji表情?
Emoji表情大家都很熟悉。 例如,微信的对话窗口可以发送表情符号。
但如果你仔细观察,你会发现一个重要的发现。 例如,如果朋友给你发了一个表情符号,你在聊天会话列表页面查看*近的消息,你会发现有些不同,如下所示:
前者是默认的表情符号,后者是自定义的表情符号。 显然,如果你在微博上按住微信的【曰比】,就无法显示微信的【困困】表情。
本文介绍了这两个emoji表情在H5和微信小程序下的实现。
自定义表情符号
定制,顾名思义,就是由你自己定义的表达方式。 它不是一个通用的表达方式。 它是按照你自己系统的一套解析规则来实现的,只能在我的系统中识别。
表达式定义
首先,您需要定义自己的一组正则表达式,它们是绝对路径表达式。 例如:
export default emojiData = {
"买买买": ["1",true,1]
}
这里我们约定表情图片有统一的路径格式,如:。所以“买买买”其实对应的是
这里定义了表情文案“买买买”对应的表情符号的路径。 当然,自定义表情的文案和图片一定要一一对应。
为了方便区分用户的普通文案,我们通常会在自定义表达方式中添加“[]”。 例如“买买买”*终显示为“[买买买]”。 为了保证之前用过的表情能够正常显示,系统中的【买买买】只能对应这个图片路径。 这里定义了一个数组,接下来的两个参数我们稍后解释。
表达到文本
有了文案和图片的对应关系,根据业务需求,就可以在表情面板上渲染表情了。 这样就可以在页面的表情面板中显示该表情的图片路径了。 然后用户选择一个表达式,相应的表达式就会显示在文本框中。 显示图片的文案,比如【买买买】,当然也是系统数据库中存储的文案【买买买】。
"买买买": ["1",true,1]
这里数组中的true值表示当前表情是否还在使用。 对于离线表情,我们需要在渲染表情面板时将其移除,但是生成的表情如果存在的话仍然需要显示在页面上。
数据中的 1 代表表达式显示在表达式面板的哪个屏幕上。 这里**屏是0,所以1代表第二屏。
function getFaceList(panelIndex) {
let arr = [];
for (let txt in emojiData) {
if (emojiData[txt][2] == panelIndex) { // 找到对应面板的显示。
if (emojiData[txt][1]) {// 保证该表情未下线
let s = getFaceUrl(emojiData[txt]);
s = `${txt}"> ${s}">`;
arr.push(s);
}
}
}
return arr;
}
这是渲染表达式面板。 数据根据渲染的面板索引进行渲染。 不离线时,只有表情才能渲染到面板中。
function getFaceUrl(emoji) {
return `https://wq.360buyimg.com/fd/wx/img/gwq/face/${emoji[0]}.png`
}
文字转图像
后台查询的复制文本可能包含表达式。 当页面显示的时候,我们需要将文字转换成图片。
function text2pic(txt) {
if (!txt) {
return '';
}
txt = txt.replace(/\[([^\]]+)\]/g, function (v1, v2) {
//v1: [买买买] v2:买买买
let d = emojiData[v2];
return d ? ' + getFaceUrl(d) + '" />' : v1;
});
return txt;
}
这里,需要显示的文字是搜索[xxx]的内容,然后与我们自定义的表情符号进行匹配。 如果匹配,则说明是自定义表情,然后我们输出一个img图像标签。
当然,没有办法区分这个表情是你在面板上选择的表情符号【买买买】还是你在文本框中输入的文案【买买买】。 你还会发现微信的【偰尰】其实是区分表情和文字的。 如果我们也需要这样做的话,我们在传入后台的时候就不能只传入文案【买买买】,比如【买买买】,那么我们之前的识别也需要遵循这个规则。 如果你有兴趣并且需要的话,可以尝试一下。
由于这里将普通文本转换为富文本,所以要特别注意xss的问题。 在转换表达式之前先进行xss处理。 在将富文本内容渲染到页面之前,请确保不存在 xss 问题。
系统默认emoji表情
以上自定义表情可以解决我们系统中对具有特殊含义的emoji表情的需求。 例如,表达方式“买买买”是我们业务的特殊表达方式。 事实上,没有这样的表情符号。
不过,你应该注意系统的表情符号。 它在不同系统中可能显示的样式会略有不同。 不过,不用担心,笑还是笑。 在任何制度下都不会变成哭泣。 如果要求不是那么高的话,问题不大。 大,只知道存在这种显示差异。
代码 emoji 表情
笑吗?:\uD83D\uDE04
当用户在输入法中输入默认的emoji表情时,我们需要对其进行处理,将其转换成代码进行存储,比如调用方法进行转换。
function emoji2Unicode (emoji) {
let str = '';
if (emoji && emoji.length > 0) {
for (const char of emoji) {
const index = char.codePointAt(0);
if (index > 65535) {
const h =
'\\u' +
(Math.floor((index - 0x10000) / 0x400) + 0xd800).toString(
16
);
const c =
'\\u' + ((index - 0x10000) % 0x400 + 0xdc00).toString(16);
str = str + h + c;
} else {
str += char;
}
}
}
return str;
}
如果emoji作为代码存储在后台,返回前端时不需要特殊使用或者vue的v-html来显示。 只需将其显示为普通文本即可。 例如,以下两个都可以显示为表情符号?:
document.getElementById("emojiWrap").innerHTML='\uD83D\uDE04';
document.getElementById("emojiWrap").innerText='\uD83D\uDE04';
如果我们通过传递参数代码来调用后端,比如\uD83D\uDE04,那么前端查询返回时,也需要是文本\uD83D\uDE04。 这里后端数据库需要支持字符存储。 本文暂不讨论。 有兴趣的可以读一下。 。
HTML 实体存储 emoji 表情
除了使用代码来存储emoji表情之外,我们还可以使用html实体存储来实现。
用户使用手机输入法输入表情后,我们需要将其转换为物理存储。
表情符号==> html
function emoji2HtmlEntity (str) {
const patt = /[\ud800-\udbff][\udc00-\udfff]/g;
str = str.replace(patt, function (char) {
let H, L, code;
if (char.length === 2) {
H = char.charCodeAt(0); // 取出高位
L = char.charCodeAt(1); // 取出低位
code = (H - 0xd800) * 0x400 + 0x10000 + L - 0xdc00; // 转换算法
return '' + code + ';';
} else {
return char;
}
});
return str;
}
这里,表达式被转换为实体存储。 这个html对数据库存储没有要求,只要能存储字符串就可以了。 例如:
emoji2HtmlEntity('?') ==> 😄
把这个html实体&#存储在后台,然后前端查询的时候原样返回。
html ==> 表情符号
通常我们也可以直接渲染html实体,比如:
document.getElementById("emojiWrap").innerHTML='😄';
但是,我们仍然不能用它来显示html。 它只会按原样显示文本。 另外,在微信小程序中很难显示,所以我们可以统一将html转换成代码来显示。
如下:he.js
const regexInvalidEntity = /(?:[xX][^a-fA-F0-9]|[^0-9xX])/;
const regexDecode = /&(Gt|GT|ii);|&(gt|lt)(?!;)([=a-zA-Z0-9]?)|([0-9]+)(;?)|[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+)/g;
const decodeMapNumeric = { '0': '\uFFFD', '128': '\u20AC', '130': '\u201A', '131': '\u0192', '132': '\u201E', '133': '\u2026', '134': '\u2020', '135': '\u2021', '136': '\u02C6', '137': '\u2030', '138': '\u0160', '139': '\u2039', '140': '\u0152', '142': '\u017D', '145': '\u2018', '146': '\u2019', '147': '\u201C', '148': '\u201D', '149': '\u2022', '150': '\u2013', '151': '\u2014', '152': '\u02DC', '153': '\u2122', '154': '\u0161', '155': '\u203A', '156': '\u0153', '158': '\u017E', '159': '\u0178' };
const invalidReferenceCodePoints = [1, 2, 3, 4, 5, 6, 7, 8, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 64976, 64977, 64978, 64979, 64980, 64981, 64982, 64983, 64984, 64985, 64986, 64987, 64988, 64989, 64990, 64991, 64992, 64993, 64994, 64995, 64996, 64997, 64998, 64999, 65000, 65001, 65002, 65003, 65004, 65005, 65006, 65007, 65534, 65535, 131070, 131071, 196606, 196607, 262142, 262143, 327678, 327679, 393214, 393215, 458750, 458751, 524286, 524287, 589822, 589823, 655358, 655359, 720894, 720895, 786430, 786431, 851966, 851967, 917502, 917503, 983038, 983039, 1048574, 1048575, 1114110, 1114111];
const stringFromCharCode = String.fromCharCode;
const object = {};
const hasOwnProperty = object.hasOwnProperty;
const has = function (object, propertyName) {
return hasOwnProperty.call(object, propertyName);
};
const contains = function (array, value) {
let index = -1;
const length = array.length;
while (++index < length) {
if (array[index] == value) {
return true;
}
}
return false;
};
const merge = function (options, defaults) {
if (!options) {
return defaults;
}
const result = {};
let key;
for (key in defaults) {
// A `hasOwnProperty` check is not needed here, since only recognized
// option names are used anyway. Any others are ignored.
result[key] = has(options, key) ? options[key] : defaults[key];
}
return result;
};
const parseError = function (message) {
throw Error('Parse error: ' + message);
};
const codePointToSymbol = function (codePoint, strict) {
let output = '';
if ((codePoint >= 0xD800 && codePoint <= 0xDFFF) || codePoint > 0x10FFFF) {
if (strict) {
parseError('character reference outside the permissible Unicode range');
}
return '\uFFFD';
}
if (has(decodeMapNumeric, codePoint)) {
if (strict) {
parseError('disallowed character reference');
}
return decodeMapNumeric[codePoint];
}
if (strict && contains(invalidReferenceCodePoints, codePoint)) {
parseError('disallowed character reference');
}
if (codePoint > 0xFFFF) {
codePoint -= 0x10000;
output += stringFromCharCode(codePoint >>> 10 & 0x3FF | 0xD800);
codePoint = 0xDC00 | codePoint & 0x3FF;
}
output += stringFromCharCode(codePoint);
return output;
};
const decode = function (html, options) {
options = merge(options, decode.options);
const strict = options.strict;
if (strict && regexInvalidEntity.test(html)) {
parseError('malformed character reference');
}
return html.replace(regexDecode, function ($0, $1, $2, $3, $4, $5, $6, $7, $8) {
let codePoint;
let semicolon;
let decDigits;
let hexDigits;
if ($4) {
// Decode decimal escapes, e.g. `𝌆`.
decDigits = $4;
semicolon = $5;
if (strict && !semicolon) {
parseError('character reference was not terminated by a semicolon');
}
codePoint = parseInt(decDigits, 10);
return codePointToSymbol(codePoint, strict);
}
if ($6) {
// Decode hexadecimal escapes, e.g. `𝌆`.
hexDigits = $6;
semicolon = $7;
if (strict && !semicolon) {
parseError('character reference was not terminated by a semicolon');
}
codePoint = parseInt(hexDigits, 16);
return codePointToSymbol(codePoint, strict);
}
// If we’re still here, `if ($7)` is implied; it’s an ambiguous
// ampersand for sure. https://mths.be/notes/ambiguous-ampersands
if (strict) {
parseError(
'named character reference was not terminated by a semicolon'
);
}
return $0;
});
};
decode.options = {
'isAttributeValue': false,
'strict': false
};
export default decode;
这个的实现过程我就不详细说了。 有兴趣的同学可以看一下,比较简单。
拿到文本后,我们首先使用he来处理:
import decode from './he';
text = decode(text);
这样html实体就转换成了可以直接显示的emoji表情微信表情制作小程序H5页面小程序如何实现emoji表情?,也可以直接在小程序中显示。 当然,这个强大的库不仅仅只是转换emoji表情,你可以参考: