组件内容
<template>
<view v-if="showInputEmoji" class="icon-img-emoji">
<view class="pop_pinglun" :style="{bottom: keyHeight + 'px'}">
<view class="mask" @click="showInputEmoji = false"></view>
<view class="warp" @tap.stop>
<textarea
placeholder="请输入内容"
:maxlength="maxContent"
:focus="focusKey"
v-model="content"
:cursor="cursorIndex"
@input="inputChange"
@focus="focusChange"
@blur="blurChange"
:show-confirm-bar="false" />
<view class="btn-bottom">
<text class="left">{{numberContent}}/{{maxContent}}</text>
<view class="right">
<text v-if="showEmoji" class="iconfont biaoqing" @click="openEmoji"></text>
<text v-else class="iconfont jianpan" @click="openInput"></text>
<button class="btn" @click="handleSubmit" :disabled="numberContent <= 0">发表</button>
</view>
</view>
<swiper v-show="!showEmoji" class="swiper-list" :indicator-dots="true">
<swiper-item v-for="(parentItem, parentIndex) in dataList" :key="parentIndex">
<view class="swiper-item">
<image
v-for="item in parentItem"
:src="item.value | textOrEmoji"
:key="item.value"
@click="clickEmoji(item)"
mode="aspectFit"></image>
</view>
</swiper-item>
</swiper>
</view>
</view>
</view>
</template>
<script>
import config from '@/config/index.js'
export default {
data() {
return {
keyHeight: 0,
startIndex: -1,
cursorIndex: 0,
content: '',
showEmoji: true,
showInputEmoji: false,
focusKey: false,
numberContent: 0,
dataList: [
[
{lable: '[爱你]', value: 'aini'},
{lable: '[奥特曼]', value: 'aoteman'},
{lable: '[拜拜]', value: 'baibai'},
{lable: '[抱抱]', value: 'baobao'},
{lable: '[悲伤]', value: 'beishang'},
{lable: '[并不简单]', value: 'bingbujiandan'},
{lable: '[鄙视]', value: 'bishi'},
{lable: '[闭嘴]', value: 'bizui'},
{lable: '[馋嘴]', value: 'chanzui'},
{lable: '[吃惊]', value: 'chijing'},
{lable: '[打哈欠]', value: 'dahaqi'},
{lable: '[打脸]', value: 'dalian'},
{lable: '[敲头]', value: 'ding'},
{lable: '[狗头]', value: 'doge'},
{lable: '[二哈]', value: 'erha'},
{lable: '[费解]', value: 'feijie'},
{lable: '[肥皂]', value: 'feizao'},
{lable: '[感冒]', value: 'ganmao'},
{lable: '[鼓掌]', value: 'guzhang'},
{lable: '[哈哈]', value: 'haha'},
{lable: '[害羞]', value: 'haixiu'},
{lable: '[汗]', value: 'han'},
{lable: '[呵呵]', value: 'hehe'},
{lable: '[嘿嘿嘿]', value: 'heiheihei'}
],
[
{lable: '[黑线]', value: 'heixian'},
{lable: '[哼]', value: 'heng'},
{lable: '[坏笑]', value: 'huaixiao'},
{lable: '[花心]', value: 'huaxin'},
{lable: '[急眼]', value: 'jiyan'},
{lable: '[可爱]', value: 'keai'},
{lable: '[可怜]', value: 'kelian'},
{lable: '[酷]', value: 'ku'},
{lable: '[骷髅]', value: 'kulou'},
{lable: '[困]', value: 'kun'},
{lable: '[懒得理你]', value: 'landelini'},
{lable: '[泪]', value: 'lei'},
{lable: '[怒]', value: 'nu'},
{lable: '[怒骂]', value: 'numa'},
{lable: '[钱]', value: 'qian'},
{lable: '[亲亲]', value: 'qinqin'},
{lable: '[傻眼]', value: 'shayan'},
{lable: '[生病]', value: 'shengbing'},
{lable: '[失望]', value: 'shiwang'},
{lable: '[衰]', value: 'shuai'},
{lable: '[睡觉]', value: 'shuijiao'},
{lable: '[思考]', value: 'sikao'},
{lable: '[太开心]', value: 'taikaixin'},
{lable: '[摊手]', value: 'tanshou'}
],
[
{lable: '[舔]', value: 'tian'},
{lable: '[偷笑]', value: 'touxiao'},
{lable: '[吐]', value: 'tu'},
{lable: '[挖鼻孔]', value: 'wabishi'},
{lable: '[委屈]', value: 'weiqu'},
{lable: '[污]', value: 'wu'},
{lable: '[笑哭]', value: 'xiaoku'},
{lable: '[星星眼]', value: 'xingxingyan'},
{lable: '[嘻嘻]', value: 'xixi'},
{lable: '[嘘]', value: 'xu'},
{lable: '[阴险]', value: 'yinxian'},
{lable: '[疑问]', value: 'yiwen'},
{lable: '[右哼哼]', value: 'youhengheng'},
{lable: '[晕]', value: 'yun'},
{lable: '[允悲]', value: 'yunbei'},
{lable: '[抓狂]', value: 'zhuakuang'}
]
]
}
},
watch: {
content(newValue, oldValue) {
this.numberContent = newValue.length
}
},
props: {
// 按钮文字
btnText: {
type: String,
default: () => {
return '发表'
}
},
// 字数限制
maxContent: {
type: Number,
default: 100
}
},
filters:{
textOrEmoji(value) {
return `${config.imgUrl}/emoji/d_${value}.gif`
}
},
methods: {
// 打开关闭输入
openOrOut() {
this.showInputEmoji = !this.showInputEmoji
this.$nextTick(() => {
this.focusKey = true
})
},
// 打开键盘
openInput() {
this.showEmoji = true
this.focusKey = true
},
// 打开表情
openEmoji() {
let _this = this
_this.showEmoji = false
},
// 弹出键盘
focusChange(event) {
this.openInput()
this.keyHeight = event.detail.height
},
// 失去光标
blurChange(event) {
this.keyHeight = 0
this.startIndex = event.detail.cursor
this.focusKey = false
},
// 输入时光标的位置
inputChange(event) {
this.startIndex = event.detail.cursor
},
// 选中表情
clickEmoji(item) {
if (this.startIndex > 0) {
const start = this.content.substring(0, this.startIndex)
const end = this.content.substring(this.startIndex, this.content.length)
this.content = start + item.lable + end
} else {
this.content += item.lable
}
this.startIndex += item.lable.length
},
// 发表内容
handleSubmit() {
const content = JSON.parse(JSON.stringify(this.content))
this.content = ''
this.$emit('inputEmojiSubmit', content)
}
}
}
</script>
<style scoped lang="scss">
.icon-img-emoji{
overflow: auto;
.pop_pinglun{
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 99;
.mask{
background-color: rgba($color: #000000, $alpha: 0.2);
width: 100%;
height: 100%;
}
.warp{
background-color: #fff;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
z-index: 9;
.btn-bottom{
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
padding: 20upx;
border-top: 1upx solid $c_02;
height: 90upx;
.left{
font-size: 22upx;
color: #999999;
}
.right{
display: flex;
align-items: center;
.iconfont{
font-size: 45upx;
color: $c_03;
margin-right: 30upx;
}
.biaoqing{
font-size: 40upx;
}
}
.btn{
@include btn-reset;
color: $c_01;
padding-left: 20upx;
border-left: 1upx solid $c_02;
margin: 0;
font-size: 30upx;
line-height: 40upx;
}
.btn[disabled]{
color: rgba($color: $c_01, $alpha: 0.6);
}
}
textarea{
border: 1px solid $c_02;
background-color: $c_02;
border-radius: 4upx;
margin: auto;
text-align: left;
padding: 10upx;
margin: 20upx;
display: block;
width: auto;
height: 140upx;
}
}
}
.swiper-list{
padding-top: 20upx;
background-color: $c_02;
.swiper-item{
display: flex;
align-items: center;
flex-wrap: wrap;
image{
width: 12.5%;
height: 60upx;
margin-bottom: 20upx;
}
}
}
}
</style>
使用方式
<view class="input-list">
<view class="input-item" type="text" @click="focusInput('input01')">{{input01}}</view>
<view class="input-item" type="text" @click="focusInput('input02')">{{input02}}</view>
<input-emoji
btnText="发表"
@inputEmojiSubmit="inputEmojiSubmit"
ref="inputEmoji"></input-emoji>
</view>
focusInput(data) {
this.$refs.inputEmoji.openOrOut()
this.$refs.inputEmoji.content = this[data]
this.curContent = data
},
inputEmojiSubmit(data) {
console.log(this.curContent)
this[this.curContent] = data
this.$refs.inputEmoji.openOrOut()
}
效果
表情包下载
链接:https://pan.baidu.com/s/1ryGWo7xTTo9CGTzpnnjpqQ
提取码:b4f6
怎么显示表情
定义好一个组件匹配 [ ] 这样就可以回显代码了
<template>
<view class="rich-view">
<rich-text :nodes="nodes" class="rich-text" :class="['omit' + isOmit]"><span style="color:#ccc;" v-if="placeholder">{{placeholder}}</span></rich-text>
</view>
</template>
<script>
import config from '@/config/index.js'
export default {
data() {
return{
dataList: {
爱你: 'aini',
奥特曼: 'aoteman',
拜拜: 'baibai',
抱抱: 'baobao',
悲伤: 'beishang',
并不简单: 'bingbujiandan',
鄙视: 'bishi',
闭嘴: 'bizui',
馋嘴: 'chanzui',
吃惊: 'chijing',
打哈欠: 'dahaqi',
打脸: 'dalian',
敲头: 'ding',
狗头: 'doge',
二哈: 'erha',
费解: 'feijie',
肥皂: 'feizao',
感冒: 'ganmao',
鼓掌: 'guzhang',
哈哈: 'haha',
害羞: 'haixiu',
汗: 'han',
呵呵: 'hehe',
嘿嘿嘿: 'heiheihei',
黑线: 'heixian',
哼: 'heng',
坏笑: 'huaixiao',
花心: 'huaxin',
急眼: 'jiyan',
可爱: 'keai',
可怜: 'kelian',
酷: 'ku',
骷髅: 'kulou',
困: 'kun',
懒得理你: 'landelini',
泪: 'lei',
怒: 'nu',
怒骂: 'numa',
钱: 'qian',
亲亲: 'qinqin',
傻眼: 'shayan',
生病: 'shengbing',
失望: 'shiwang',
衰: 'shuai',
睡觉: 'shuijiao',
思考: 'sikao',
太开心: 'taikaixin',
摊手: 'tanshou',
舔: 'tian',
偷笑: 'touxiao',
吐: 'tu',
挖鼻孔: 'wabishi',
委屈: 'weiqu',
污: 'wu',
笑哭: 'xiaoku',
星星眼: 'xingxingyan',
嘻嘻: 'xixi',
嘘: 'xu',
阴险: 'yinxian',
疑问: 'yiwen',
右哼哼: 'youhengheng',
晕: 'yun',
允悲: 'yunbei',
抓狂: 'zhuakuang'
},
nodes:''
}
},
props:{
richString:{
type:String,
default: () => {
return ''
}
},
placeholder:{
type:String,
default: null
},
// 是否限制显示行数
isOmit:{
type: String,
default: 'n'
}
},
watch:{
richString(newValue,oldValue) {
this.nodes = newValue
if(this.nodes){
this.replace()
}else{
this.nodes = `<span style="color:#ccc;">${this.placeholder}</span>`
}
}
},
methods:{
replace() {
// 处理富文本图片无法显示问题
this.nodes = this.nodes.replace(/\<img/gi, '<img style="max-width:100%;height:auto"')
// 处理表情
let temp = []
let reg = /\[.*?\]/g
while((temp = reg.exec(this.nodes))){
let str = temp[0].substring(1,temp[0].length-1)
if(this.dataList[str]){
let value = this.dataList[str]
let html = `<img src='${config.imgUrl}/emoji/d_${value}.gif' style='width:18px;height:18px;vertical-align: middle;'></img>`
this.nodes = this.nodes.replace(temp[0],html)
}
}
}
},
created() {
this.nodes = this.richString
this.replace()
}
}
</script>
<style scoped lang="scss">
.rich-view{
// display: inline-block;
.rich-text{
word-break: break-all;
white-space: pre-line;
}
}
.omit4{
@include p-n(4);
max-height: 400upx;
}
.omit3{
@include p-n(3)
}
</style>