163 lines
3.4 KiB
Vue
163 lines
3.4 KiB
Vue
<template>
|
|
<view class="emoji-picker" v-if="visible">
|
|
<view class="emoji-mask" @click="handleClose"></view>
|
|
<view class="emoji-panel">
|
|
<!-- 分类标签 -->
|
|
<view class="emoji-tabs">
|
|
<view
|
|
v-for="category in categories"
|
|
:key="category.key"
|
|
class="emoji-tab"
|
|
:class="{ active: currentCategory === category.key }"
|
|
@click="handleCategoryChange(category.key)"
|
|
>
|
|
{{ category.name }}
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 表情列表 -->
|
|
<scroll-view class="emoji-list" scroll-y>
|
|
<view class="emoji-grid">
|
|
<view
|
|
v-for="(emoji, index) in currentEmojis"
|
|
:key="index"
|
|
class="emoji-item"
|
|
@click="handleEmojiClick(emoji)"
|
|
>
|
|
<text class="emoji-icon">{{ emoji.code }}</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed } from 'vue'
|
|
import { emojiCategories } from '@/utils/emoji.js'
|
|
|
|
const props = defineProps({
|
|
visible: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
})
|
|
|
|
const emit = defineEmits(['close', 'select'])
|
|
|
|
const categories = ref(emojiCategories)
|
|
const currentCategory = ref('common')
|
|
|
|
// 当前分类的表情列表
|
|
const currentEmojis = computed(() => {
|
|
const category = categories.value.find(c => c.key === currentCategory.value)
|
|
return category ? category.emojis : []
|
|
})
|
|
|
|
// 切换分类
|
|
const handleCategoryChange = (key) => {
|
|
currentCategory.value = key
|
|
}
|
|
|
|
// 选择表情
|
|
const handleEmojiClick = (emoji) => {
|
|
emit('select', emoji.code)
|
|
}
|
|
|
|
// 关闭面板
|
|
const handleClose = () => {
|
|
emit('close')
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.emoji-picker {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
z-index: 999;
|
|
|
|
.emoji-mask {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background-color: rgba(0, 0, 0, 0.3);
|
|
}
|
|
|
|
.emoji-panel {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 500rpx;
|
|
background-color: #fff;
|
|
border-radius: 24rpx 24rpx 0 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.emoji-tabs {
|
|
display: flex;
|
|
border-bottom: 1rpx solid #eee;
|
|
padding: 0 24rpx;
|
|
|
|
.emoji-tab {
|
|
flex: 1;
|
|
text-align: center;
|
|
padding: 24rpx 0;
|
|
font-size: 28rpx;
|
|
color: #666;
|
|
position: relative;
|
|
|
|
&.active {
|
|
color: #ff6b6b;
|
|
font-weight: 600;
|
|
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 40rpx;
|
|
height: 4rpx;
|
|
background-color: #ff6b6b;
|
|
border-radius: 2rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.emoji-list {
|
|
flex: 1;
|
|
padding: 24rpx;
|
|
|
|
.emoji-grid {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
|
|
.emoji-item {
|
|
width: 14.28%;
|
|
aspect-ratio: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
.emoji-icon {
|
|
font-size: 48rpx;
|
|
}
|
|
|
|
&:active {
|
|
background-color: #f5f5f5;
|
|
border-radius: 8rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|