JavaScript聊天框插入表情: 点击表情时输入框失焦, 无法插入到输入框.
文章目录
- Preface
- 问题原因
- 解决问题
- 源代码
- svg 表情
Preface
最近在尝试做一个聊天框,但是在我做表情插入的时候被一个问题卡住了。
表情是使用的 img
标签;
本次最大问题就是: 点击表情时输入框失焦, 无法插入到输入框.
问题原因
当点击表情的时候, 输入框失去焦点, 聚焦到点击的标清处或失去焦点.
我尝试过点击的时候, 聚焦到输入框, 但是又出现了聚焦位置问题... 真是一波三折
解决问题
一开始做的时候, 我一直有个简单的解决思路, 但是我就是没去尝试. 就去搜索各种问题和解决办法.
最后还是妥协了
解决思路 : 既然是因为点击表情的时候, 焦点聚焦到表情选择了, 那我就不让表情选择框不能选中. 👍🏻 还真管用了.
给输入框加这个样式就可以解决, 如果要做兼容 记得添加属性前缀 -webkit-
等…
.input {
user-select: none;
}
效果:
源代码
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>Document</title>
<link rel="stylesheet" href="/index.css" />
<style>
.emoji-box {
width: 300px;
user-select: none;
}
.emoji-box .emoji {
display: inline-block;
padding: 3px;
}
._emoji {
display: inline-block;
width: 18px;
height: 18px;
margin: 0 1px;
vertical-align: middle;
}
.input {
border: 1px solid orange;
width: 300px;
height: 120px;
outline: none;
display: inline-block;
font-size: 14px;
}
</style>
</head>
<body>
<!-- tabindex: 让元素可聚焦, 拥有focus方法、可用tab切换焦点; -->
<pre id="input" class="input" tabindex="0" contenteditable></pre>
<script>
// 获取表情 url, 我这里demo使用的是固定的图片.
function getImgUrl() {
return [
'1', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 'sun'
].map((x) => `/image/weather/${x}.png`)
}
// 插入表情列表
function insertUl() {
let ul = document.createElement('div')
ul.className = 'emoji-box'
// 也可以使用 emoji 来作为表情, 但是我觉得太单一, 所以改用了 img方式来做.
// let emojis = '😀 🥹 ☺️ 😉 😗 😝 🤓 😏 😕 😫 😤 😳 😃 😅 😊 😌 😙 😜 😎 😒 😶🌫️ 🫥 🫢 🫢 🫣 🫣 🫠 🤔 🤫 😯 😵'.split(' ')
getImgUrl().forEach((url) => {
// ul.innerHTML += `<span class="emoji" data-type="EMOJI" style="cursor: pointer">${emoji}</span>`
ul.innerHTML += `<div data-type="EMOJI" data-url="${url}" style="display: inline-block;width: 22px; height: 22px; background: url(${url}) no-repeat center / 18px;cursor: pointer;"></div>`
})
document.body.appendChild(ul)
ul.onclick = tapUl
}
// 点击表情事件
function tapUl(event) {
let e = event.target
insertImg(e.dataset.url)
}
// 插入表情到输入框
function insertImg(src) {
if (window.getSelection) {
var sel = window.getSelection();
var range = sel.getRangeAt(0);
var img = new Image();
img.className = '_emoji'
range.deleteContents()
img.src = src;
range.insertNode(img);
range.collapse(false);
}
}
</script>
</body>
</html>
svg 表情
我还使用svg来测试插入表情, 存在一个大问题:
svg 不能够选中, 光标也不能移动到svg标签后.
svg标签的创建方式也比较特殊.
以下为 ts 代码
之前一直不知道 xxNS 的作用, 这下知道用途了
private onClickIcon(iconName: string) {
const ns: string = "http://www.w3.org/2000/svg"
const cNs: string = 'http://www.w3.org/1999/xlink'
// NS 的第一个参数是svg的命名空间URI, svg 和 use 标签都有不同的 URI 注意区分.
const oSvg: any = document.createElementNS(ns, 'svg')
const use: any = document.createElementNS(ns, 'use')
oSvg.setAttribute('style', 'width: 1em;height: 1em;')
oSvg.setAttribute('class', `svg-icon ${iconName}`)
use.setAttributeNS(cNs, 'xlink:href', `#icon-${iconName}`)
oSvg.appendChild(use)
Insert.insertContent(oSvg)
}