mi-assessment/uniapp/components/EmojiPicker/index.vue
2026-02-09 14:45:06 +08:00

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>