起因是工作中微信小程序要做一个实时聊天功能并且可以发表情,在微信官方文档中其实是有emoji扩展组件的,用法也大概说明;自己看了一下文档。
之后自己理了理思路,摸索着自己写一个。
以下代码都是使用的上面网址的emoji表情代码
首先分析一下,微信小程序聊天功能还带发表情的思路,我的思路如下
用户在input框输入内容&选择表情,input中显示的是内容和表情(eg:这是内容😵);
前端进行相关转码处理,将input的内容变成(这是内容#emo34_),然后点击发送将转码后的文本内容发送给后端
websocket服务器进行广播,将(这是内容#emo34_)这段文字发给前端
前端对(这是内容#emo34_)这段文字进行解码处理,最后变成(这是内容😵),从而渲染在页面上
直接上代码
准备工作:
//失焦后确认焦点位置
blurcursor: '',
//失焦后的文本
blurText: '',
//用于存储当前表情
currentEmoji: {},
//当前文本内容,用于用户输入框展示
inputText: '',
//当前文本内容,所有表情转换为(#emoxx_)格式,发给后端也是发送inputText_code
inputText_code: '',
//input框光标位置,后续input框删除文字或标签会用到
input_cursor: 0,
//定义一个emoji表情的数组,emoji字段用于展现到页面上,code字段用于传输
emojiArr: [
{ emoji: '😠', code: '#emo30_' },
{ emoji: '😩', code: '#emo31_' },
{ emoji: '😲', code: '#emo32_' },
{ emoji: '😞', code: '#emo33_' },
{ emoji: '😵', code: '#emo34_' },
{ emoji: '😰', code: '#emo35_' },
{ emoji: '😒', code: '#emo36_' },
{ emoji: '😍', code: '#emo37_' },
{ emoji: '😤', code: '#emo38_' },
{ emoji: '😜', code: '#emo39_' },
{ emoji: '😝', code: '#emo40_' },
{ emoji: '😋', code: '#emo41_' },
{ emoji: '😘', code: '#emo42_' },
{ emoji: '😚', code: '#emo43_' },
{ emoji: '😷', code: '#emo44_' },
{ emoji: '😳', code: '#emo45_' },
{ emoji: '😃', code: '#emo46_' },
{ emoji: '😅', code: '#emo47_' },
{ emoji: '😆', code: '#emo48_' },
{ emoji: '😁', code: '#emo49_' },
{ emoji: '😂', code: '#emo50_' },
{ emoji: '😊', code: '#emo51_' },
{ emoji: '😄', code: '#emo53_' },
{ emoji: '😢', code: '#emo54_' },
{ emoji: '😭', code: '#emo55_' },
{ emoji: '😨', code: '#emo56_' },
{ emoji: '😣', code: '#emo57_' },
{ emoji: '😡', code: '#emo58_' },
{ emoji: '😌', code: '#emo59_' },
{ emoji: '😖', code: '#emo60_' },
{ emoji: '😔', code: '#emo61_' },
{ emoji: '😱', code: '#emo62_' },
{ emoji: '😪', code: '#emo63_' },
{ emoji: '😏', code: '#emo64_' },
{ emoji: '😓', code: '#emo65_' },
{ emoji: '😥', code: '#emo66_' },
{ emoji: '😫', code: '#emo67_' },
{ emoji: '😉', code: '#emo68_' },
]
实现:
- 在wxml中将emojiArr遍历,取emoji字段渲染在页面中,data-code为code字段的内容,data-emoji为emoji字段
<view style="display:{{bottom3Isshow}}" class="bottom-3">
<view class="emoji" wx:for="{{emojiArr}}" wx:for-item="item" wx:key="id" bindblur='bindblur' bindtap='changeCurrentEmoji' data-code='{{item.code}}' data-emoji='{{item.emoji}}'>
{{item.emoji}}
</view>
</view>
- 为上面遍历出来的表情都加一个点击事件,用于存储当前表情
//添加当前表情
changeCurrentEmoji(e) {
let tempCursor = this.data.blurcursor
let tempText = (this.data.blurText).split('')
if (tempCursor == tempText.length) {
this.setData({
currentEmoji: e.currentTarget.dataset
}, () => {
this.setData({
inputText: this.data.inputText + this.data.currentEmoji.emoji
})
this.setData({
inputText_code: this.data.inputText_code + this.data.currentEmoji.code
})
})
} else {
let inputText_code = this.data.inputText_code
let inputText = this.data.inputText
inputText_code = inputText_code.split(/[\#,_]/)
//去空
inputText_code = inputText_code.filter(value => value)
inputText = inputText.split('')
for (let i = 0; i < inputText_code.length; i++) {
if (inputText_code[i].indexOf("emo") == -1) {
inputText_code[i] = inputText_code[i].split('')
} else {
inputText_code[i] = ['emo_delet', inputText_code[i]]
}
}
//扁平化
inputText_code = [].concat.apply([], inputText_code);
console.log('inputText_code', inputText_code)
inputText_code.splice(tempCursor, 0, e.currentTarget.dataset.code)
let newCode = inputText_code.filter(value => {
if (value.indexOf('emo_delet') == -1) {
return value
}
})
for (let i = 0; i < newCode.length; i++) {
if (newCode[i].indexOf("emo") != -1) {
// console.log(newCode[i])
let temp = newCode[i].split('')
if(temp[0] != '#'){
newCode[i] = "#" + newCode[i] + "_"
}
}
}
let newCode_1 = [...newCode]
let newCode_2 = ''
for(let i=0;i<newCode_1.length;i++){
newCode_2+=newCode_1[i]
}
for (let i = 0; i < newCode.length; i++) {
if (newCode[i].indexOf("emo") != -1) {
for (let j = 0; j < this.data.emojiArr.length; j++) {
if ((this.data.emojiArr[j].code).indexOf(newCode[i]) != -1) {
newCode[i] = this.data.emojiArr[j].emoji
}
}
}
}
let newText = newCode
let newText_2 = ''
for(let i=0;i<newText.length;i++){
newText_2+=newText[i]
}
this.setData({
inputText:newText_2,
inputText_code:newCode_2
})
console.log('newCode', newCode_2)
console.log('newText', newText_2)
}
},
//监听input焦点
bindblur(e) {
console.log(e.detail) //cursor
this.setData({
blurcursor: e.detail.cursor,
blurText: e.detail.value
})
},
- 为input绑定内容改变事件,用于实时改变inputText(用于显示在用户输入的input框)和inputText_code(用于发送给服务器)的值
gitText(e) {
//获取当前输入和上一次输入的差数
let temp = (e.detail.value).slice((this.data.inputText).length)
//确定光标位置,因为涉及到用户输入内容后可能会删除部分内容,这里做了这个处理,定位到用户想删除的内容从而进行改变inputText_code的值
if (parseInt(e.detail.keyCode) == 8) {
this.setData({
input_cursor: e.detail.cursor
}, () => {
//这里的transcoder()方法后面会写到
this.transcoder()
})
}
else {
this.setData({
inputText: e.detail.value
})
this.setData({
inputText_code: this.data.inputText_code + temp
})
}
},
//文字带表情转为文字+表情code
transcoder() {
let cursor = parseInt(this.data.input_cursor) + 1
let temp = this.data.inputText_code
let temp_1 = temp.split(/[\#,_]/)
//去空字符串
let newtemp = temp_1.filter(value => value)
let count = 0
for (let i = 0; i < newtemp.length; i++) {
if (newtemp[i].indexOf('emo') == -1) {
count += newtemp[i].length
if (count >= cursor) {
let delIndex = newtemp[i].length - (count - cursor) - 1
let temp_2 = newtemp[i].split('')
temp_2[delIndex] = ''
let temp_3 = temp_2.filter(value => value)
let str1 = ''
for (let v = 0; v < temp_3.length; v++) {
str1 += temp_3[v]
}
newtemp[i] = str1
break
}
} else {
count += 2
if (count - 1 == cursor) {
newtemp[i] = ''
}
}
}
let str = ''
for (let y = 0; y < newtemp.length; y++) {
if (newtemp[y].indexOf('emo') != -1) {
str += "#" + newtemp[y] + "_"
} else {
str += newtemp[y]
}
}
this.setData({
inputText_code: str
})
},
- 将服务器发送过来的内容,也就是发给服务器的inputText_code转换为文字+表情
//接收带表情的文字把表情转码
decode(str) {
let tempArr = str.split(/[\#,_]/)
let newArr = tempArr.filter(value => value)
for (let i = 0; i < newArr.length; i++) {
for (let j = 0; j < (this.data.emojiArr).length; j++) {
if (newArr[i].indexOf('emo') != -1 && (this.data.emojiArr[j]).code.indexOf(newArr[i]) != -1) {
newArr[i] = (this.data.emojiArr[j]).emoji
}
}
}
let src = ''
for (let i = 0; i < newArr.length; i++) {
src += newArr[i]
}
return src
},
最后总结一下:
在代码中以数组的方式存储emoji表情,数组的每一个值是一个对象,对象中有emoji表情代码和自定义的表情码,用户在input框输入文字加标签时,显示的是文字+表情代码;实际上传送给后端的是文字+自定义的表情码;当后端有内容传给前端时,前端再对文字+自定义表情码进行转换,最终变成文字+表情代码渲染在页面上。
这样的好处其实是为了减轻后端压力,不必考虑数据库是否可以存放emoji表情代码,数据库中只用存放特定的字符串,发给前端使用时,前端对特定的字符串进行处理