要在你的 Vue 项目中使用表情包输入组件,首先需要进行安装和配置,以下是详细步骤:
npm install emoji-mart @vueuse/core
main.js
中添加:import EmojiPicker from './components/EmojiPicker.vue';
createApp(App)
.component('EmojiPicker', EmojiPicker)
.mount('#app');
<template>
<div class="chat-container">
<textarea v-model="message" ref="messageInput" placeholder="输入消息..."></textarea>
<button @click="toggleEmojiPicker">
<i class="fas fa-smile"></i>
</button>
<EmojiPicker
v-if="showEmojiPicker"
@select="insertEmoji"
:recent-emojis="recentEmojis"
/>
<button @click="sendMessage">发送</button>
</div>
</template>
<script>
import { ref, onMounted } from 'vue';
export default {
setup() {
const message = ref('');
const showEmojiPicker = ref(false);
const recentEmojis = ref([]);
const messageInput = ref(null);
const toggleEmojiPicker = () => {
showEmojiPicker.value = !showEmojiPicker.value;
};
const insertEmoji = (emoji) => {
const input = messageInput.value;
const start = input.selectionStart;
const end = input.selectionEnd;
message.value = message.value.substring(0, start) +
emoji +
message.value.substring(end);
input.focus();
input.selectionStart = input.selectionEnd = start + emoji.length;
// 更新最近使用表情
if (!recentEmojis.value.includes(emoji)) {
recentEmojis.value.unshift(emoji);
if (recentEmojis.value.length > 20) {
recentEmojis.value.pop();
}
}
};
const sendMessage = () => {
if (message.value.trim()) {
// 处理消息发送逻辑
console.log('发送消息:', message.value);
message.value = '';
}
};
return {
message,
showEmojiPicker,
recentEmojis,
messageInput,
toggleEmojiPicker,
insertEmoji,
sendMessage
};
}
}
</script>
以下是表情包组件的封装实现:
<!-- EmojiPicker.vue -->
<template>
<div class="emoji-picker" ref="container">
<!-- 搜索框 -->
<div class="search-container">
<input
type="text"
v-model="searchText"
placeholder="搜索表情..."
@input="searchEmojis"
>
</div>
<!-- 表情分类导航 -->
<div class="categories">
<button
v-for="category in categories"
:key="category.id"
:class="{ active: activeCategory === category.id }"
@click="switchCategory(category.id)"
>
<i :class="category.icon"></i>
</button>
</div>
<!-- 表情内容区域 -->
<div class="emoji-container">
<!-- 最近使用表情 -->
<div v-if="activeCategory === 'recent' && recentEmojis.length > 0" class="emoji-group">
<div
v-for="emoji in recentEmojis"
:key="emoji"
class="emoji-item"
@click="selectEmoji(emoji)"
>
{{ emoji }}
</div>
</div>
<!-- 按分类显示表情 -->
<div v-else class="emoji-group">
<div
v-for="emoji in filteredEmojis"
:key="emoji"
class="emoji-item"
@click="selectEmoji(emoji)"
>
{{ emoji }}
</div>
</div>
</div>
</div>
</template>
<script>
import { ref, computed, onMounted, watch } from 'vue';
import emojiList from './emojiList.json'; // 表情数据
export default {
name: 'EmojiPicker',
props: {
recentEmojis: {
type: Array,
default: () => []
}
},
setup(props, { emit }) {
const container = ref(null);
const searchText = ref('');
const activeCategory = ref('recent');
const filteredEmojis = ref([]);
// 表情分类
const categories = ref([
{ id: 'recent', icon: 'fas fa-clock' },
{ id: 'smileys', icon: 'fas fa-smile' },
{ id: 'animals', icon: 'fas fa-paw' },
{ id: 'food', icon: 'fas fa-utensils' },
{ id: 'activities', icon: 'fas fa-futbol' },
{ id: 'travel', icon: 'fas fa-plane' },
{ id: 'objects', icon: 'fas fa-lightbulb' },
{ id: 'symbols', icon: 'fas fa-heart' },
{ id: 'flags', icon: 'fas fa-flag' }
]);
// 根据分类过滤表情
const getCategoryEmojis = (category) => {
if (category === 'recent') return [];
return emojiList[category] || [];
};
// 搜索表情
const searchEmojis = () => {
if (!searchText.value.trim()) {
filteredEmojis.value = getCategoryEmojis(activeCategory.value);
return;
}
const searchTerm = searchText.value.toLowerCase();
const result = [];
Object.values(emojiList).forEach(category => {
category.forEach(emoji => {
if (emoji.toLowerCase().includes(searchTerm)) {
result.push(emoji);
}
});
});
filteredEmojis.value = result;
};
// 切换分类
const switchCategory = (category) => {
activeCategory.value = category;
filteredEmojis.value = getCategoryEmojis(category);
};
// 选择表情
const selectEmoji = (emoji) => {
emit('select', emoji);
};
// 初始化
onMounted(() => {
filteredEmojis.value = getCategoryEmojis(activeCategory.value);
});
// 监听搜索文本变化
watch(searchText, searchEmojis);
return {
container,
searchText,
activeCategory,
filteredEmojis,
categories,
searchEmojis,
switchCategory,
selectEmoji
};
}
}
</script>
<style scoped>
.emoji-picker {
width: 320px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 10px;
position: absolute;
z-index: 100;
}
.search-container {
margin-bottom: 10px;
}
.search-container input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
outline: none;
}
.categories {
display: flex;
justify-content: space-around;
padding: 8px 0;
border-bottom: 1px solid #eee;
}
.categories button {
background: none;
border: none;
cursor: pointer;
font-size: 18px;
padding: 5px;
color: #888;
transition: color 0.2s;
}
.categories button.active {
color: #007bff;
}
.emoji-container {
height: 240px;
overflow-y: auto;
padding: 5px;
}
.emoji-group {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 8px;
}
.emoji-item {
font-size: 20px;
padding: 5px;
text-align: center;
cursor: pointer;
transition: transform 0.2s;
}
.emoji-item:hover {
transform: scale(1.2);
}
</style>
emojiList.json
文件来添加或删除表情,也可以通过 props 传入自定义表情数据。.emoji-picker {
--primary-color: #007bff;
--border-radius: 8px;
--box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.emoji-picker {
opacity: 0;
transform: translateY(10px);
transition: opacity 0.2s ease, transform 0.2s ease;
}
.emoji-picker.active {
opacity: 1;
transform: translateY(0);
}
// 在 EmojiPicker.vue 中添加
const loadCategoryEmojis = async (category) => {
if (category === 'recent') return [];
// 模拟异步加载
if (!emojiList[category]) {
const response = await fetch(`/emojis/${category}.json`);
emojiList[category] = await response.json();
}
return emojiList[category];
};
下面是一个完整的聊天界面示例,展示如何集成表情包组件:
<template>
<div class="chat-app">
<div class="chat-header">
<h1>聊天应用</h1>
</div>
<div class="chat-messages" ref="messagesContainer">
<div
v-for="(message, index) in messages"
:key="index"
class="message"
:class="{ 'user-message': message.type === 'user', 'bot-message': message.type === 'bot' }"
>
<div class="message-content">
<p>{{ message.text }}</p>
</div>
</div>
</div>
<div class="chat-input">
<div class="emoji-button" @click="toggleEmojiPicker">
<i class="fas fa-smile"></i>
</div>
<textarea
v-model="message"
ref="messageInput"
placeholder="输入消息..."
@focus="showEmojiPicker = false"
></textarea>
<button @click="sendMessage">发送</button>
<EmojiPicker
v-if="showEmojiPicker"
:recent-emojis="recentEmojis"
@select="insertEmoji"
/>
</div>
</div>
</template>
<script>
import { ref, onMounted, nextTick } from 'vue';
import EmojiPicker from './components/EmojiPicker.vue';
export default {
components: {
EmojiPicker
},
setup() {
const messagesContainer = ref(null);
const messageInput = ref(null);
const message = ref('');
const showEmojiPicker = ref(false);
const messages = ref([
{ type: 'bot', text: '你好!我是聊天机器人,有什么可以帮助你的吗?' }
]);
const recentEmojis = ref([]);
const toggleEmojiPicker = () => {
showEmojiPicker.value = !showEmojiPicker.value;
};
const insertEmoji = (emoji) => {
const input = messageInput.value;
const start = input.selectionStart;
const end = input.selectionEnd;
message.value = message.value.substring(0, start) +
emoji +
message.value.substring(end);
input.focus();
input.selectionStart = input.selectionEnd = start + emoji.length;
// 更新最近使用表情
if (!recentEmojis.value.includes(emoji)) {
recentEmojis.value.unshift(emoji);
if (recentEmojis.value.length > 20) {
recentEmojis.value.pop();
}
}
};
const sendMessage = () => {
if (!message.value.trim()) return;
// 添加用户消息
messages.value.push({
type: 'user',
text: message.value
});
// 模拟机器人回复
setTimeout(() => {
messages.value.push({
type: 'bot',
text: '我收到了你的消息: ' + message.value
});
scrollToBottom();
}, 500);
message.value = '';
showEmojiPicker.value = false;
scrollToBottom();
};
const scrollToBottom = () => {
nextTick(() => {
if (messagesContainer.value) {
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight;
}
});
};
onMounted(() => {
scrollToBottom();
});
return {
messagesContainer,
messageInput,
message,
showEmojiPicker,
messages,
recentEmojis,
toggleEmojiPicker,
insertEmoji,
sendMessage
};
}
}
</script>
<style scoped>
.chat-app {
display: flex;
flex-direction: column;
height: 100vh;
max-width: 800px;
margin: 0 auto;
}
.chat-header {
padding: 16px;
background: #007bff;
color: white;
text-align: center;
border-radius: 8px 8px 0 0;
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 16px;
background: #f8f9fa;
}
.message {
margin-bottom: 16px;
display: flex;
}
.user-message {
justify-content: flex-end;
}
.bot-message {
justify-content: flex-start;
}
.message-content {
padding: 12px;
border-radius: 8px;
max-width: 70%;
}
.user-message .message-content {
background: #007bff;
color: white;
}
.bot-message .message-content {
background: white;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.chat-input {
display: flex;
align-items: center;
padding: 16px;
background: white;
border-radius: 0 0 8px 8px;
box-shadow: 0 -1px 3px rgba(0,0,0,0.1);
position: relative;
}
.emoji-button {
font-size: 20px;
margin-right: 12px;
cursor: pointer;
color: #6c757d;
}
textarea {
flex: 1;
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
resize: none;
outline: none;
}
button {
margin-left: 12px;
padding: 12px 24px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background 0.2s;
}
button:hover {
background: #0069d9;
}
.emoji-picker {
bottom: 70px;
right: 20px;
}
</style>
这个表情包输入组件不仅功能完整,而且具有良好的可扩展性和用户体验。你可以根据项目需求进一步定制样式和功能,比如添加 GIF 搜索、自定义表情上传等高级功能。
Vue, 表情包输入组件,完整实现代码,使用教程,Vue 组件开发,前端开发,JavaScript,HTML,CSS, 表情包插件,Vue 实战,前端组件,用户界面设计,交互式组件,前端开发教程
资源地址:
https://pan.quark.cn/s/a85a3b247036
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有