Vue评论留言的表情功能实现
介绍:使用的微信提供的表情包地址,生成img标签,然后用v-html渲染.然后点击标签返回#表情名字;
带有#表情名字;
的内容用正则表达式处理替换成img标签,其他文字不变,然后用v-html渲染出来
大概就是点击标签,然后input/areatext框里面出现#表情名字
,然后content里的#表情名字
会变成
第一步 拥有一个表情名字的数组
为了共用,这个数组可以放到一个js文件里并导出
例:https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/0.gif 这表情就是微笑 ,然后数组中微笑的下标就是0
// 这里是放在 src\assets\js\emotionList.js
export default{emotionList:["微笑","撇嘴","色","发呆","得意","流泪","害羞","闭嘴","睡","大哭","尴尬","发怒","调皮","呲牙","惊讶","难过","酷","冷汗","抓狂","吐","偷笑","可爱","白眼","傲慢","饥饿","困","惊恐","流汗","憨笑","大兵","奋斗","咒骂","疑问","嘘","晕","折磨","衰","骷髅","敲打","再见","擦汗","抠鼻","鼓掌","糗大了","坏笑","左哼哼","右哼哼","哈欠","鄙视","委屈","快哭了","阴险","亲亲","吓","可怜","菜刀","西瓜","啤酒","篮球","乒乓","咖啡","饭","猪头","玫瑰","凋谢","示爱","爱心","心碎","蛋糕","闪电","炸弹","刀","足球","瓢虫","便便","月亮","太阳","礼物","拥抱","强","弱","握手","胜利","抱拳","勾引","拳头","差劲","爱你","不","好","爱情","飞吻","跳跳","发抖","怄火","转圈","磕头","回头","跳绳","挥手","激动","街舞","献吻","左太极","右太极"]}
第二步 编写表情展示组件(一个按钮和一个表情盒子)
- 这个组件(display:inline-block)默认就只展示一个emotion然后点击展示它会展示出一个表情盒子
- 这三部分是同一个文件的,复制到一起直接就可以用了
<template>
<div @click="handleShowClick" class="emotion-box">
<slot>
<span class="emotion">emotion</span>
</slot>
<div v-if="load" v-show="show" class="box">
<span
class="emo"
v-for="(line, i) in emotionArr"
:key="'emojo'+i"
@click.stop="emoClick(line.name)"
v-html="line.url"
></span>
</div>
</div>
</template>
-
点击emotion(可以视为按钮)触发
handleShowClick()
,如果没有加载过表情盒子则去调用loadEmotion()
加载表情盒子(懒加载) -
loadEmotion()
遍历第一步里的数组并生成一个对象数组(对象的名字,img表情完全体) -
在
<template>
中用v-for和emotionArr生成一堆<img ... />
在盒子里 -
然后给每个
设置事件监听,点击时触发
emoClick
并向父组件发送这个表情的名字(子向父传值)
<script>
// emo: 单个span标签标签简写
// TODO 鼠标点击其他地方关闭
// 位置 src\components\common\emotion-box.vue
import emotions from '@/assets/js/emotionList.js'
export default {
name: 'emotion-box',
data() {
return {
show: false, // 是否展示表情框(表情盒子)
load: false, // 是否加载了表情框
emotionArr: null, //表情数组
}
},
methods: {
// 监听span点击来选择展示表情box
handleShowClick() {
// 当第一次点击展开在渲染表情盒子 懒加载
if (this.load == false) this.loadEmotion()
this.show = !this.show //切换表情盒子的展示状况
},
// 表情点击把名字发给父组件(调用者)
emoClick(arg) {
this.show = false // 关闭表情盒子
this.$emit('emotionClick', arg)
},
// 加载表情
loadEmotion() {
const list = emotions.emotionList
let emotionArr = []
list.map((item, index) => {
emotionArr.push({
name: `#${item};`,
url: `<img title="${item}" src="https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/${index}.gif">`,
})
})
this.emotionArr = emotionArr
this.load = true
console.log('表情盒子加载完成')
},
},
}
</script>
- 然后就是随便加点样式,别看代码多主要是设置相对定位和绝对定位,还可以设置下z-index防止被覆盖
<style lang="scss" scoped>
.emotion-box {
// 重要的就是加个相对定位
display: inline-block;
position: relative;
> .emotion {
cursor: pointer;
height: 30px;
user-select: none;
line-height: 30px;
padding: 2px 4px;
border: 1px solid #9c9a9a;
border-radius: 7px;
margin-right: 5px;
&:hover {
background-color: aquamarine;
}
}
// 重要的就是加个绝对定位 其他就是好看的
> .box {
z-index: 10;
position: absolute;
background-color: #fff;
width: 285px;
max-height: 150px;
overflow: scroll;
top: 30px;
border: 1px solid aqua;
// 每个span表情标签样式
.emo {
cursor: pointer;
}
}
}
</style>
然后别的组件导入,注册下这个组件,然后写个函数处理监听到的表情点击事件就可以了
第三步 写个函数利用正则表达式处理带有特殊格式的内容
当有xxx#色;
的文字就会变转成成xxx😍 (就是img标签)
把内容用这个函数处理,然后交给v-html
import emotions from '../assets/js/emotionList.js';
export function processEmotion(str) {
return str.replace(/\#[\u4E00-\u9FA5]{1,3}\;/gi, (words) => {
let word = words.replace(/\#|\;/gi, '')
let index = emotions.emotionList.indexOf(word)
if (index !== -1) {
return `<img src="https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/${index}.gif" align="middle">`
} else {
return words
}
})
}