h5实现一个吸附在键盘上的工具栏
<template>
<div class="keyboard-toolbar-container">
<!-- 聊天内容区域 -->
<div class="chat-container">
<h2 class="chat-title">聊天示例</h2>
<div class="messages" ref="messagesContainer">
<div class="message received">
<img src="https://picsum.photos/id/1005/40/40" alt="对方头像" class="avatar">
<div class="message-content">你好!这个工具栏会在你点击输入框时显示在键盘上方</div>
</div>
<div class="message sent">
<div class="message-content">看起来很不错,有哪些功能呢?</div>
<img src="https://picsum.photos/id/1012/40/40" alt="我的头像" class="avatar">
</div>
<div class="message received">
<img src="https://picsum.photos/id/1005/40/40" alt="对方头像" class="avatar">
<div class="message-content">有表情、图片、文件等常用功能,试试看吧!</div>
</div>
</div>
<!-- 输入区域 -->
<div class="input-area">
<textarea
v-model="message"
@focus="showToolbar = true"
@blur="onInputBlur"
placeholder="输入消息..."
ref="messageInput"
></textarea>
<button @click="sendMessage" class="send-btn">发送</button>
</div>
</div>
<!-- 吸附在键盘上的工具栏 -->
<div
class="toolbar"
:class="{ 'toolbar-visible': showToolbar, 'toolbar-hidden': !showToolbar }"
>
<button class="toolbar-btn" @click="handleToolClick('emoji')">
<i class="fa fa-smile-o"></i>
<span>表情</span>
</button>
<button class="toolbar-btn" @click="handleToolClick('image')">
<i class="fa fa-picture-o"></i>
<span>图片</span>
</button>
<button class="toolbar-btn" @click="handleToolClick('file')">
<i class="fa fa-file-o"></i>
<span>文件</span>
</button>
<button class="toolbar-btn" @click="handleToolClick('mic')">
<i class="fa fa-microphone"></i>
<span>语音</span>
</button>
<button class="toolbar-btn" @click="handleToolClick('location')">
<i class="fa fa-map-marker"></i>
<span>位置</span>
</button>
<button class="toolbar-btn" @click="handleToolClick('more')">
<i class="fa fa-ellipsis-h"></i>
<span>更多</span>
</button>
</div>
</div>
</template>
<script>
export default {
name: 'KeyboardToolbar',
data() {
return {
message: '',
showToolbar: false,
// 用于追踪是否点击了工具栏按钮
toolbarClicked: false
};
},
methods: {
// 处理输入框失焦事件
onInputBlur() {
// 延迟隐藏工具栏,防止点击工具栏按钮时立即隐藏
setTimeout(() => {
if (!this.toolbarClicked) {
this.showToolbar = false;
}
this.toolbarClicked = false;
}, 200);
},
// 处理工具栏按钮点击
handleToolClick(type) {
this.toolbarClicked = true;
console.log(`点击了${this.getToolName(type)}工具`);
// 可以根据不同类型执行不同操作
switch(type) {
case 'emoji':
// 显示表情选择器逻辑
break;
case 'image':
// 选择图片逻辑
break;
case 'file':
// 选择文件逻辑
break;
// 其他工具的处理逻辑...
}
// 点击后重新聚焦到输入框
this.$refs.messageInput.focus();
},
// 获取工具名称
getToolName(type) {
const toolNames = {
emoji: '表情',
image: '图片',
file: '文件',
mic: '语音',
location: '位置',
more: '更多'
};
return toolNames[type] || type;
},
// 发送消息
sendMessage() {
if (!this.message.trim()) return;
// 创建新消息元素
const newMessage = document.createElement('div');
newMessage.className = 'message sent';
newMessage.innerHTML = `
<div class="message-content">${this.message}</div>
<img src="https://picsum.photos/id/1012/40/40" alt="我的头像" class="avatar">
`;
// 添加到消息容器并滚动到底部
this.$refs.messagesContainer.appendChild(newMessage);
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
// 清空输入框
this.message = '';
}
},
mounted() {
// 监听窗口 resize 事件,处理键盘显示/隐藏
window.addEventListener('resize', () => {
const isInputFocused = document.activeElement === this.$refs.messageInput;
if (isInputFocused) {
this.showToolbar = true;
// 调整滚动位置,确保输入框可见
setTimeout(() => {
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
}, 300);
}
});
},
beforeDestroy() {
window.removeEventListener('resize', () => {});
}
};
</script>
<style scoped>
.keyboard-toolbar-container {
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
background-color: #f5f5f5;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.chat-container {
flex: 1;
display: flex;
flex-direction: column;
padding: 16px;
overflow: hidden;
}
.chat-title {
text-align: center;
margin: 0 0 16px 0;
color: #333;
font-weight: 600;
}
.messages {
flex: 1;
overflow-y: auto;
margin-bottom: 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.message {
display: flex;
max-width: 80%;
word-break: break-word;
}
.message.received {
align-self: flex-start;
}
.message.sent {
align-self: flex-end;
flex-direction: row-reverse;
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
margin: 0 8px;
}
.message-content {
padding: 10px 14px;
border-radius: 18px;
line-height: 1.4;
}
.message.received .message-content {
background-color: #ffffff;
border-top-left-radius: 4px;
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
}
.message.sent .message-content {
background-color: #007aff;
color: white;
border-top-right-radius: 4px;
}
.input-area {
display: flex;
gap: 8px;
align-items: flex-end;
}
.input-area textarea {
flex: 1;
border: 1px solid #ddd;
border-radius: 20px;
padding: 12px 16px;
resize: none;
outline: none;
font-size: 16px;
min-height: 42px;
max-height: 120px;
}
.send-btn {
background-color: #007aff;
color: white;
border: none;
border-radius: 50%;
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-weight: bold;
}
/* 工具栏样式 */
.toolbar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background-color: white;
display: flex;
justify-content: space-around;
padding: 8px 0;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
z-index: 100;
}
.toolbar-hidden {
transform: translateY(100%);
opacity: 0;
}
.toolbar-visible {
transform: translateY(0);
opacity: 1;
}
.toolbar-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: none;
border: none;
color: #666;
font-size: 12px;
padding: 6px;
width: 50px;
cursor: pointer;
}
.toolbar-btn i {
font-size: 20px;
margin-bottom: 4px;
}
.toolbar-btn:active {
background-color: #f0f0f0;
border-radius: 8px;
}
</style>