Bootstrap

uni-app 表情、键盘切换输入组件

组件内容

<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>

;