155 lines
6.8 KiB
Markdown
155 lines
6.8 KiB
Markdown
|
|
Make By. RainyTears
|
|||
|
|
基于 Vue移动端打造的「悬浮面板 + 输入框」
|
|||
|
|
```sh
|
|||
|
|
├── floatPanel.vue # 横向滚动按钮组 / 插槽面板
|
|||
|
|
└── InputArea.vue # 语音/文字双模式输入容器
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 特性总览
|
|||
|
|
|
|||
|
|
| 层级 | 可插拔 | |
|
|||
|
|
| ------ | -------------------------------------- | --- |
|
|||
|
|
| **外层** | `InputArea.vue` 负责长录音、键盘切换、主题色、v-model | |
|
|||
|
|
| **面板** | `floatPanel.vue` 提供按钮渲染 + 两种插槽,零逻辑依赖 | |
|
|||
|
|
|
|||
|
|
> ✅ 支持 uni-app、hbuilder、vue3+setup
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 安装与最简调用
|
|||
|
|
|
|||
|
|
```vue
|
|||
|
|
<!-- 页面 -->
|
|||
|
|
<!-- 关于showPanel - 即便你不想要主动操控 内部也内置了一部分的showPanel管理 -->
|
|||
|
|
<template>
|
|||
|
|
<inputArea
|
|||
|
|
v-model="msg"
|
|||
|
|
v-model:showPanel="show"
|
|||
|
|
:buttons="btns"
|
|||
|
|
themeColor="#a846e6"
|
|||
|
|
@Send="onSend"
|
|||
|
|
@LongPressStart="recordStart"
|
|||
|
|
@LongPressEnd="recordEnd"
|
|||
|
|
@LongPressCancel="recordCancel"
|
|||
|
|
@PanelClick="panelSelect"
|
|||
|
|
>
|
|||
|
|
|
|||
|
|
<!-- 如果你想自定义悬浮面板里的内容,可以使用 slot -->
|
|||
|
|
<template #panel-content>
|
|||
|
|
<view>自定义表情面板</view>
|
|||
|
|
</template>
|
|||
|
|
<!-- 如果自定义了悬浮面板 那将默认不会显示buttons -->
|
|||
|
|
</inputArea>
|
|||
|
|
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import InputKit from '@/components/FloatingInputKit/index.vue'
|
|||
|
|
|
|||
|
|
const msg = ref('')
|
|||
|
|
const show = ref(false)
|
|||
|
|
const btns = [
|
|||
|
|
{ label:'相册', icon:'/static/pic.png', value:'image' },
|
|||
|
|
{ label:'拍摄', icon:'/static/cam.png', value:'video' },
|
|||
|
|
{ label:'文件', icon:'/static/file.png', value:'file' }
|
|||
|
|
] // 如果不定义btns直接移除的话可以使用Slot
|
|||
|
|
|
|||
|
|
function onSend(e) { console.log('文字',e.content) }
|
|||
|
|
function panelSelect(e) {
|
|||
|
|
switch(e.value){
|
|||
|
|
case image:
|
|||
|
|
ChooseImage(); break;
|
|||
|
|
case vide:
|
|||
|
|
ChooseVideo(); break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. Props(index.Vue)
|
|||
|
|
|
|||
|
|
| 属性 | 类型 | 默认 | 说明 |
|
|||
|
|
| ----------------- | ------- | ---------------------- | --------------------------- |
|
|||
|
|
| modelValue | String | '' | 输入框内容,支持 v-model |
|
|||
|
|
| showPanel | Boolean | false | 浮层面板显隐,支持 v-model:showPanel |
|
|||
|
|
| placeholder | String | 点击输入或按住说话... | 输入框占位 |
|
|||
|
|
| longPressTip | String | 正在录音,上滑取消 | 长按时提示 |
|
|||
|
|
| cancelTip | String | 松开手指,取消发送 | 上滑取消时提示 |
|
|||
|
|
| LeftIcon | String | /static/button.Png | 左侧图标 |
|
|||
|
|
| sendIcon | String | /static/send.Png | 发送态图标 |
|
|||
|
|
| attachmentIcon | String | /static/Attachment.Png | 附件图标 |
|
|||
|
|
| showLeftBtn | Boolean | true | 是否显示左侧按钮 |
|
|||
|
|
| buttons | Array | 见代码 | 面板的按钮数据 |
|
|||
|
|
| panelHeight | String | 100rpx | 面板高度 |
|
|||
|
|
| panelBottomOffset | String | 10rpx | 面板与输入框距离 |
|
|||
|
|
| panelPadding | String | 15rpx | 面板左右留空 |
|
|||
|
|
| longPressDelay | Number | 200 | 长按触发阈值 ms |
|
|||
|
|
| cancelThreshold | Number | 100 | 上滑取消的 px 阈值 |
|
|||
|
|
| adjustPosition | Boolean | false | input adjust-position |
|
|||
|
|
| holdKeyboard | Boolean | true | input hold-keyboard |
|
|||
|
|
| confirmType | String | send | input confirm-type |
|
|||
|
|
| themeColor<br> | String | #a846e6 | 主色,同--main-color |
|
|||
|
|
| BarHeight | String | 100rpx | 整个聊天条高度 |
|
|||
|
|
| PadBottom | String | 36rpx | 距离底部距离 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. Events(index.Vue)
|
|||
|
|
|
|||
|
|
| 事件 | 参数 | 说明 |
|
|||
|
|
| ----------------- | ---------------------------- | -------------- |
|
|||
|
|
| update:modelValue | text:String | 文本变化 |
|
|||
|
|
| update:showPanel | show:Boolean | 面板显隐变化 |
|
|||
|
|
| LongPressStart | - | 开始长按输入框(可用于录音) |
|
|||
|
|
| LongPressEnd | - | 正常松手结束 |
|
|||
|
|
| LongPressCancel | - | 上滑取消 |
|
|||
|
|
| Send | {type:'text',content:String} | 点击发送触发 |
|
|||
|
|
| PanelClick | {button,index} | 面板按钮/插槽点击 |
|
|||
|
|
| LeftButtonClick | - | 左侧按钮触发 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. Slots — 高自由度
|
|||
|
|
|
|||
|
|
| 插槽 | 作用域 | 用法 |
|
|||
|
|
| ------------------------------ | -------------- | ------------------------ |
|
|||
|
|
| panel-content(index.Vue) | - | **外层整体替换面板**,常用于自定义复杂 ui |
|
|||
|
|
| -(floatPanel.Vue 默认插槽) | - | **完全覆盖按钮区**,保留滚动和动效骨架 |
|
|||
|
|
| button-content(floatPanel.Vue) | {button,index} | **仅定制按钮内部结构**,不破坏外层 item |
|
|||
|
|
| | | |
|
|||
|
|
|
|||
|
|
> 注意:一旦使用 floatPanel 默认插槽 (`<slot v-if="hasDefaultSlot">`),预设按钮循环即不再渲染,仅展示你提供的内容,仍享有 hide/disabled 动效。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 内部状态(index.Vue)
|
|||
|
|
|
|||
|
|
- `focusLock:boolean` —— 防止长按后立即抖动聚焦
|
|||
|
|
- `isLongPressing / isCancelling` —— 手势长按聊天条状态
|
|||
|
|
- `innerShowPanel` —— 本地面板显隐,外部通过 v-model:showPanel 同步
|
|||
|
|
|
|||
|
|
> 面板显隐会自动受 focus/blur 影响,可在回调里 `setPanelVisible` 覆盖
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 样式变量(index.Scss)
|
|||
|
|
|
|||
|
|
| CSS 变量 | 默认 | 用途 |
|
|||
|
|
| ------------ | -------------------------------- | ------ |
|
|||
|
|
| --main-color | #a846e6 | 主色 |
|
|||
|
|
| $elastic | transform 0.35s cubic-bezier(... | 全局弹性曲线 |
|
|||
|
|
| $btn-height | 100rpx | 输入条高度 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 常见修补/扩展
|
|||
|
|
1. 底部安全区 & 全面屏定位已内置:`env(safe-area-inset-bottom) + 60rpx`
|
|||
|
|
2. 举例:想替换「长按录音」为「长按拍照」:
|
|||
|
|
- 监听 `LongPressStart` 调起相机,返回值自己构造
|
|||
|
|
3. 面板支持无限长按钮,内部 `scroll-view` 已 `white-space:nowrap`
|
|||
|
|
---
|