一般情况下评论区的表情宽和高是固定显示,所以有些尺寸相对较大的表情包是缩放显示的,模糊不说还可能导致误解表情包的含义,本教程为表情图案添加了一个简单的放大弹出层,非常的实用。

教程

其实实现的原理很简单,就是创建一个盒子,将表情包的内容放在盒子里面,再读取图片的 Alt 等描述属性现在在盒子中,最后控制盒子位置和显示隐藏即可。而在表情包放大逻辑方面,基本属性为:2 倍放大显示,最大显示宽高为 200px(如若超过,按比例对应缩小)。

表情包逻辑

实现

具体到实现,就是利用 observer 观察评论区元素新增的节点,根据相关选择器过滤出含表情包的节点,添加对应的事件,以 Artalk 评论系统为例处理到的选择器为:

/**
* 放大项:
* ① 表情包选择
* ② 评论内容
* ③ 预览窗(只有一张图)
* ④ 预览窗(任意)
*/
const dom = mutations[i].addedNodes
if(dom[0]?.classList?.contains('atk-grp')
|| dom[0]?.classList?.contains('atk-comment-wrap')
|| (!!dom[0]?.attributes && !!dom[0]?.attributes['atk-emoticon'])
|| (typeof dom[0]?.querySelector === 'function' && dom[0]?.querySelector('img[atk-emoticon]'))) {
dom[0].onmouseover = (e) => {
//......
}
}

对应的,如果是 Twikoo 评论系统,相应需要修改为:

let owo_body = ''
const dom = mutations[i].addedNodes
if (dom.length == 2 && dom[1].className == 'OwO-body') owo_body = dom[1]
else if (dom.length == 1 && dom[0].className == 'tk-comment') owo_body = dom[0]
else continue
owo_body.onmouseover = (e) => {
//.......
}

代码

JavaScript
以下代码适用于 Artalk,需要自行调用。
/**
* 表情包放大
* @param target 表情包 DOM
*/
function showOwoBig(target) {
const ratio = 2
const maxLength = 200
const body = document.querySelector('body')

let div = document.createElement('div')
if (document.querySelector('#owo-big')) {
div = document.querySelector('#owo-big')
} else {
div.id = 'owo-big'
body.appendChild(div)
}

const observer = new MutationObserver(mutations => {
for (let i = 0; i < mutations.length; i++){
let flag = 1
let owoTime = 0
const dom = mutations[i].addedNodes
if(dom[0]?.classList?.contains('atk-grp')
|| dom[0]?.classList?.contains('atk-comment-wrap')
|| (!!dom[0]?.attributes && !!dom[0]?.attributes['atk-emoticon'])
|| (typeof dom[0]?.querySelector === 'function' && dom[0]?.querySelector('img[atk-emoticon]'))) {
dom[0].onmouseover = (e) => {
// 如果需要只放大表情包可以添加 && !!e.target.attributes['atk-emoticon']
if (flag && e.target.tagName === 'IMG') {
flag = 0;
owoTime = setTimeout(() => {
const alt = e.path[0].alt || '';
const clientHeight = e.path[0].clientHeight
const clientWidth = e.path[0].clientWidth
if(clientHeight <= maxLength && clientWidth <= maxLength) {
const naturalHeight = e.path[0].naturalHeight
const naturalWidth = e.path[0].naturalWidth
const zoomHeight = clientHeight * ratio
const zoomWidth = clientWidth * ratio
const height = naturalHeight > clientHeight ? zoomHeight < naturalHeight && naturalHeight < maxLength ? zoomHeight : naturalHeight : clientHeight
const width = naturalWidth > clientWidth ? zoomWidth < naturalWidth && naturalWidth < maxLength ? zoomWidth : naturalWidth : clientWidth
let tempWidth = 0;
let tempHeight = 0;
if(width / height >= 1) {
if(width >= maxLength) {
tempWidth = maxLength
tempHeight = (height * maxLength) / width
} else {
tempWidth = width
tempHeight = height
}
} else {
if(height >= maxLength) {
tempHeight = maxLength
tempWidth = (width * maxLength) / height
} else {
tempWidth = width
tempHeight = height
}
}
const top = e.y - e.offsetY
let left = (e.x - e.offsetX) - (tempWidth - e.path[0].clientWidth) / 2
if ((left + tempWidth) > body.clientWidth) left -= ((left + tempWidth) - body.clientWidth + 10)
if (left < 0) left = 10
if (alt !== '') tempHeight += 10
div.style.cssText = `display:block;height:${tempHeight+34}px;width:${tempWidth+34}px;left:${left}px;top:${top}px;`;
div.innerHTML = `<img src="${e.target.src}"><p>${alt}</p>`
}
}, 300);
}
};
dom[0].onmouseout = () => {
flag = 1
div.style.display = 'none'
clearTimeout(owoTime)
}
}
}
})
observer.observe(target, { subtree: true, childList: true }) // 监听的 元素 和 配置项
}
CSS
#owo-big {
position: fixed;
align-items: center;
background-color: #ffffff;
border: 1px #aaa solid;
border-radius: 10px;
z-index: 9999;
display: none;
transform: translate(0, -105%);
overflow: hidden;
animation: owoIn 0.3s cubic-bezier(0.42, 0, 0.3, 1.11);
padding: 16px;
}
#owo-big img {
width: 100%;
border-radius: 10px;
}
#owo-big p {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
text-align: center;
font-size: 12px;
margin: 0;
}
@keyframes owoIn {
0% {
transform: translate(0, -95%);
opacity: 0;
}
100% {
transform: translate(0, -105%);
opacity: 1;
}
}

评论