工作笔记
本周设计回顾
下一版组件清单
<script setup lang="ts">
import { ref } from 'vue'
import { Plus } from '@lucide/vue'
import {
Button,
Card,
Dialog,
FloatButton,
FormField,
Heading,
Input,
Stack,
Text,
} from '@hina-ui/vue'
const open = ref(false)
const title = ref('')
const notes = ref(['本周设计回顾', '下一版组件清单'])
function create() {
if (!title.value.trim()) return
notes.value.push(title.value.trim())
title.value = ''
open.value = false
}
</script>
<template>
<Card class="relative min-h-72 w-full max-w-md pb-24">
<Stack gap="lg">
<Heading :level="3" size="base">工作笔记</Heading>
<Stack gap="sm">
<Text v-for="(note, index) in notes" :key="index" class="border-line border-b pb-3">
{{ note }}
</Text>
</Stack>
</Stack>
<FloatButton position="absolute" label="新建笔记" @click="open = true"><Plus /></FloatButton>
<Dialog v-model:open="open" title="新建笔记" description="为新的笔记填写标题。">
<template #content>
<FormField label="笔记标题">
<Input v-model="title" placeholder="例如:交互细节" @keydown.enter.prevent="create" />
</FormField>
</template>
<template #footer>
<Button variant="soft" tone="neutral" @click="open = false">取消</Button>
<Button :disabled="!title.trim()" @click="create">创建</Button>
</template>
</Dialog>
</Card>
</template>
用法
import { FloatButton } from '@hina-ui/vue'
默认固定在视口的逻辑右下角。通过 label 提供操作名称,默认插槽放图标。浮动按钮适合新建、帮助这类跨内容区域的常用操作;行内操作继续使用 Button 或 IconButton。
<FloatButton label="新建笔记" @click="createNote"><Plus /></FloatButton>
整页使用时放在应用壳外层,避免祖先的 transform 改变固定定位的参照。组件不传送到 body,保留当前位置的主题、方向和组件上下文。上面的演示使用 position="absolute",将按钮限制在预览面板内。
示例
外观
支持实底、浅底和描边,shape="square" 使用圆角方形。图标按钮沿用现有 Tooltip;应用需提供 TooltipProvider,AppShell 已包含它。label 始终作为无障碍名称,不依赖 Tooltip。
悬停或键盘聚焦可以查看操作名称
<script setup lang="ts">
import { ref } from 'vue'
import { HelpCircle, Pencil, Plus } from '@lucide/vue'
import { FloatButton, Flex, Stack, Text } from '@hina-ui/vue'
const result = ref('悬停或键盘聚焦可以查看操作名称')
</script>
<template>
<Stack align="center" gap="lg">
<Flex wrap justify="center" gap="lg">
<FloatButton position="static" label="新建项目" @click="result = '已选择:新建项目'">
<Plus />
</FloatButton>
<FloatButton
position="static"
label="编辑项目"
variant="soft"
shape="square"
@click="result = '已选择:编辑项目'"
>
<Pencil />
</FloatButton>
<FloatButton
position="static"
label="帮助中心"
variant="outline"
tone="neutral"
@click="result = '已选择:帮助中心'"
>
<HelpCircle />
</FloatButton>
</Flex>
<Text role="status" size="sm" tone="muted">{{ result }}</Text>
</Stack>
</template>
尺寸与文字
sm、md、lg 分别对应 40、48、56px 的默认高度。extended 将 label 显示在图标旁,此时不会重复显示 Tooltip。长文案在可用宽度内截断。
文字按钮使用同一高度,宽度随名称展开
<script setup lang="ts">
import { ref } from 'vue'
import { Plus } from '@lucide/vue'
import { FloatButton, Flex, Stack, Text } from '@hina-ui/vue'
const result = ref('文字按钮使用同一高度,宽度随名称展开')
</script>
<template>
<Stack align="center" gap="lg">
<Flex wrap align="center" justify="center" gap="lg">
<FloatButton
v-for="size in ['sm', 'md', 'lg'] as const"
:key="size"
position="static"
:size="size"
:label="`新建项目(${size})`"
@click="result = `已选择:${size}`"
>
<Plus />
</FloatButton>
<FloatButton position="static" extended label="新建项目" @click="result = '已选择:新建项目'">
<Plus />
</FloatButton>
</Flex>
<Text role="status" size="sm" tone="muted">{{ result }}</Text>
</Stack>
</template>
定位与方向
placement 使用逻辑方向,start / end 随 RTL 切换。absolute 相对最近的定位祖先,static 参与正常布局,适合与 Stack 组合成一组操作。offset 控制边距,传 { x, y } 分别设置水平与垂直边距;固定定位时还会避开设备安全区。
start / end 随书写方向切换
<script setup lang="ts">
import { ref } from 'vue'
import { Plus } from '@lucide/vue'
import { Card, Center, FloatButton, FormField, Stack, Switch, Text } from '@hina-ui/vue'
const rtl = ref(false)
const result = ref('start / end 随书写方向切换')
const placements = ['top-start', 'top-end', 'bottom-start', 'bottom-end'] as const
</script>
<template>
<Stack class="w-full max-w-md">
<FormField label="从右向左" orientation="horizontal"><Switch v-model="rtl" /></FormField>
<Card :dir="rtl ? 'rtl' : 'ltr'" class="relative h-64" :padded="false">
<Center class="h-full px-16">
<Text role="status" size="sm" tone="muted" class="text-center">{{ result }}</Text>
</Center>
<FloatButton
v-for="placement in placements"
:key="placement"
position="absolute"
:placement="placement"
:label="placement"
:offset="16"
variant="soft"
size="sm"
@click="result = placement"
>
<Plus />
</FloatButton>
</Card>
</Stack>
</template>
状态与显隐
visible 控制出现和退场,退场期间按钮不能交互。loading 保留按钮尺寸并阻止重复操作,disabled 禁用按钮。
显示和隐藏带有过渡
<script setup lang="ts">
import { ref } from 'vue'
import { RefreshCw } from '@lucide/vue'
import { Center, FloatButton, FormField, Stack, Switch, Text } from '@hina-ui/vue'
const visible = ref(true)
const loading = ref(false)
const disabled = ref(false)
const result = ref('显示和隐藏带有过渡')
</script>
<template>
<Stack class="w-full max-w-xs">
<FormField label="显示按钮" orientation="horizontal"><Switch v-model="visible" /></FormField>
<FormField label="加载中" orientation="horizontal"><Switch v-model="loading" /></FormField>
<FormField label="禁用" orientation="horizontal"><Switch v-model="disabled" /></FormField>
<Center class="h-24">
<FloatButton
position="static"
label="同步资料"
:visible="visible"
:loading="loading"
:disabled="disabled"
@click="result = '已执行:同步资料'"
>
<RefreshCw />
</FloatButton>
</Center>
<Text role="status" size="sm" tone="muted" class="text-center">{{ result }}</Text>
</Stack>
</template>
应用内导航
将 as 设置为路由组件,to 等属性透传到实际操作节点。这样可以保留 SPA 导航。
<FloatButton :as="NuxtLink" :to="localePath('/components')" label="组件文档">
<BookOpen />
</FloatButton>
API
Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
label | string | 必填 | 操作名称,同时用于无障碍和 Tooltip |
visible | boolean | true | 显示按钮,变化时播放过渡 |
position | 'fixed' | 'absolute' | 'static' | 'fixed' | 定位方式 |
placement | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'bottom-end' | 定位角落,静态布局时无效 |
offset | number | string | { x?: number | string; y?: number | string } | 6 × spacing | 边距,数字单位为 px;对象形式分别设置水平 x 与垂直 y,未给出的方向使用默认值;固定定位取边距与安全区中的较大值 |
size | 'sm' | 'md' | 'lg' | 'md' | 按钮尺寸 |
shape | 'circle' | 'square' | 'circle' | 圆形或圆角方形 |
extended | boolean | false | 显示文字标签 |
variant | 'solid' | 'soft' | 'outline' | 'solid' | 按钮外观 |
tone | 'accent' | 'neutral' | 'danger' | 'accent' | 按钮色调 |
tooltip | boolean | true | 图标形态下显示 Tooltip |
tooltipSide | 'top' | 'right' | 'bottom' | 'left' | 'top' | Tooltip 首选方向 |
loading | boolean | false | 加载中并禁止操作 |
disabled | boolean | false | 禁用操作 |
ripple | boolean | true | 涟漪反馈 |
as | string | Component | 'button' | 实际操作元素或组件 |
type | 'button' | 'submit' | 'reset' | 'button' | 按钮类型 |
class | string | — | 按钮类名 |
style | StyleValue | — | 按钮样式 |
原生属性和事件透传到按钮,例如 id、form 和 @click。
Slots
| 插槽 | 说明 |
|---|---|
default | 操作图标; extended 时放在文字前面 |
Expose
| 名称 | 类型 | 说明 |
|---|---|---|
element | HTMLElement | undefined | 当前操作节点 |
focus | () => void | 聚焦可用的按钮 |