小程序渲染微信表情方案

391 阅读3分钟

2024-07-02 创建于墨问

微信表情通常用方括号+文字来表示,例如 [某某表情]

把 [某某表情] 替换为对应的表情图片即可,替换后图片和文字在一起,也就是图文混排

图文混排时,display 有 inline-block 和 inline,图片有 background 和 image 方式,表情的大小推荐字号+4,垂直居中可以通过 background-position 和 transform: translateY 来调整,水平间距则通过 width 或占位文字宽度调整。

有几个不同的场景,分别有不同的处理方式:

1. 展示所有文字,并支持选中复制文字

inline-block + background

使用背景图渲染表情,将文字显示出来,然后限制最大宽度、透明隐藏掉,这样能保证能选中并复制文字。美中不足是,选中时选区会呈现空白,只支持 webview 渲染模式,效果如下:

// wxml
<text class="paragraph" user-select>
  <text
    class="wechat-emotion"
    style="background-image: url({{emotionUrl}})"
  >
    [某某表情]
  </text>
  <block>文字</block>
</text>
// scss

.paragraph {
  font-size: 16px;
  line-height: 25.6px;
  letter-spacing: 0.8px;
}

.wechat-emotion {
  display: inline-block;
  width: 21px;
  background: no-repeat center top 2px / 20px 20px;
  color: transparent;
  white-space: nowrap;
}

2. 展示单行、多行文字,超出省略,不支持选中

代码片段:

developers.weixin.qq.com/s/PONVbnme7…

2.1 skyline 模式

inline-block + image

使用图片渲染表情,而且要使用 overflow 属性,而不是 css,否则会导致表情图片无法完整展示。

另外表情会略微撑高行高(见 #262

// wxml 限制单行、超出显示省略号

<text
  class="skyline-line"
  overflow="ellipsis"
>

  <image class="wechat-emotion" src="{{emotionUrl}}" />
  <block>文字</block>
</text>

// wxml 限制 2 行、超出显示省略号
<text
  class="skyline-line"
  overflow="ellipsis"
  max-lines="2"
>
  <image class="wechat-emotion" src="{{emotionUrl}}" />
  <block>文字</block>
</text>
// wxss
.line {
  font-size: 16px;
  line-height: 25.6px;
  letter-spacing: 0.8px;
}

.wechat-emotion {
  display: inline-block;
  width: 19px; // 字号 + 4
  height: 19px;
  transform: translateY(3px);
  transform: translateY(4.3px); // (行高 25.6 - 尺寸 19) / 2 + 1
}

2.2 webview 模式

inline + background

使用背景图渲染表情,并且使用 inline 模式 ,宽度则由英文符号点和线来撑开,线的宽度略宽一点儿,例如....和..|||

如果用 inline-block,会出现省略号消失、或者省略号出现在第一行的奇怪现象

2025年3月27日更新,可以使用一个汉字宽度 + 4px 字间距:

// wxml 限制单行

<text
  class="line"
>
  <text
    class="wechat-emotion"
    style="background-image: url({{emotionUrl}})"
    space="ensp"
  >{{'  '}}</text>
  <block>文字</block>
</text>

// wxml 限制 2 行
<text
  class="mut-line"
>
  <text
    class="wechat-emotion"
    style="background-image: url({{emotionUrl}})"
    space="ensp"
  >{{'  '}}</text>
  <block>文字</block>
</text>
// scss
.line {
  font-size: 16px;
  line-height: 25.6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mut-line {
  font-size: 16px;
  line-height: 25.6px;
  letter-spacing: 0.8px;
  color: #222;
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; // 限制 2 行
  text-overflow: ellipsis;
}

2025年3月27日更新,可以使用一个汉字宽度 + 4px 字间距:

.wechat-emotion {
  display: inline;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: 20px 20px; // 字号 + 4
  // color: transparent;
  white-space: nowrap;
  letter-spacing: 2px;
}

补充:如何拆分文字和表情?

使用 wxs 和正则表达式即可

// 分割微信表情,例如 '文字[微笑]文字',输出['文字', '[微笑]', '文字']

module.exports = function wechatEmotion (text) {

  var regex = getRegExp('(\[\S*?\])', 'g')

  return text.split(regex)

}