FrontTools/InputArea/floatPanel.vue
Rain 3ab1f2db24 [入库]初次入库各种工具
- DBManager DB创建管理器
- FormatTimeTool
- ImageViewer工具
- InputArear工具
- OverlayPage工具
- 下拉刷新容器工具
- 视频查看器工具
2026-04-02 16:09:00 +08:00

182 lines
4.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view
class="floating-panel"
:class="{ 'panel-hide': !visible, 'panel-disabled': !visible }"
:style="panelStyle"
@tap.stop
>
<scroll-view class="button-scroll" scroll-x :show-scrollbar="false">
<view class="button-list">
<!-- 如果用户提供了自定义插槽内容 -->
<slot v-if="hasDefaultSlot"></slot>
<!-- 如果没有插槽而使用的是buttons则显示预制的渲染逻辑 -->
<template v-else>
<view
v-for="(button, index) in buttons"
:key="index"
class="button-item"
:class="{ 'active': activeIndex === index }"
@tap="handleButtonClick(button, index)"
hover-class="button-hover"
>
<!-- 这里也可以再套一层作用域插槽,允许只自定义单个按钮内部 -->
<slot name="button-content" :button="button" :index="index">
<image v-if="button.icon" class="button-icon" :src="button.icon" />
<text class="button-text">{{ button.label }}</text>
</slot>
</view>
</template>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, computed ,useSlots } from 'vue'
const props = defineProps({
visible: {
type: Boolean,
default: false
},
buttons: {
type: Array,
default: () => [
{ label: '', icon: '', value: 'text' },
{ label: '', icon: '', value: 'image' },
{ label: '', icon: '', value: 'video' },
{ label: '', icon: '', value: 'file' },
{ label: '', icon: '', value: 'location' },
{ label: '', icon: '', value: 'contact' }
]
},
height: {
type: String,
default: '100rpx'
},
horizontalPadding: {
type: String,
default: '20rpx'
},
bottomOffset: {
type: String,
default: '10rpx'
}
})
const emit = defineEmits(['handleTap'])
const slots = useSlots() // 获取插槽实例
const activeIndex = ref(-1)
const hasDefaultSlot = computed(() => !!slots.default)
const panelStyle = computed(() => ({
height: props.height,
left: props.horizontalPadding,
right: props.horizontalPadding,
bottom: `calc(100% + ${props.bottomOffset})`
}))
// 使用自带button的时候触发的点击事件
const handleButtonClick = (button, index) => {
activeIndex.value = index
emit('handleTap', { button, index })
}
</script>
<style lang="scss" scoped>
$elastic: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
.floating-panel {
position: absolute;
background: linear-gradient(135deg, #1a1a1a 0%, #262626 100%);
border-radius: 24rpx;
padding: 20rpx 0;
border: 1px solid rgba(255, 255, 255, 0.1);
z-index: 1000;
opacity: 1;
transform: translateY(0) scale(1);
backdrop-filter: blur(4px); // 增加背景模糊
/* 弹出 */
transition: opacity 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94),$elastic;
&.panel-hide {
/* 消失 */
opacity: 0;
transform: translateY(15rpx) scale(0.96);
transition: opacity 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94),$elastic;
}
&.panel-disabled {
pointer-events: none;
}
}
.button-scroll {
width: 100%;
height: 100%;
white-space: nowrap;
}
.button-list {
display: inline-flex;
align-items: center;
height: 100%;
gap: 20rpx;
padding: 0 20rpx;
}
.button-item {
display: inline-flex;
position: relative;
flex-direction: column;
align-items: center;
justify-content: center;
min-width: 90rpx;
height: 100%;
aspect-ratio: 1 ;
background-color: rgba(255, 255, 255, 0.05);
border-radius: 16rpx;
padding: 15rpx;
box-sizing: border-box;
flex-shrink: 0;
transition: $elastic;
border: 1px solid transparent; // 预留边框位置
&:active, &.button-hover {
transform: scale(0.94);
background-color: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.02); // 激活时边框显现
filter: brightness(0.9); // 点击变暗
.button-text {
color: #fff;
text-shadow: 0 0 8rpx rgba(255, 255, 255, 0.4); // 文字微发光
}
}
}
.button-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50rpx;
height: 50rpx;
flex-shrink: 0;
transition: $elastic;
}
.button-text {
position: absolute;
bottom: 5%;
left: 0;
right: 0;
text-align: center;
color: #ffffff;
font-size: 22rpx;
font-weight: 500;
text-align: center;
white-space: nowrap;
transition: $elastic;
}
</style>