组件
<script setup lang="ts">
import { Minus, Plus } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from '@/components/ui/drawer'
const data = [
{ goal: 400 },
{ goal: 300 },
{ goal: 200 },
{ goal: 300 },
{ goal: 200 },
{ goal: 278 },
{ goal: 189 },
{ goal: 239 },
{ goal: 300 },
{ goal: 200 },
{ goal: 278 },
{ goal: 189 },
{ goal: 349 },
]
const goal = ref(350)
</script>
<template>
<Drawer>
<DrawerTrigger as-child>
<Button variant="outline">
Open Drawer
</Button>
</DrawerTrigger>
<DrawerContent>
<div class="mx-auto w-full max-w-sm">
<DrawerHeader>
<DrawerTitle>Move Goal</DrawerTitle>
<DrawerDescription>Set your daily activity goal.</DrawerDescription>
</DrawerHeader>
<div class="p-4 pb-0">
<div class="flex items-center justify-center space-x-2">
<Button
variant="outline"
size="icon"
class="h-8 w-8 shrink-0 rounded-full"
:disabled="goal <= 200"
@click="goal -= 10"
>
<Minus />
<span class="sr-only">Decrease</span>
</Button>
<div class="flex-1 text-center">
<div class="text-7xl font-bold tracking-tighter">
{{ goal }}
</div>
<div class="text-muted-foreground text-[0.70rem] uppercase">
Calories/day
</div>
</div>
<Button
variant="outline"
size="icon"
class="h-8 w-8 shrink-0 rounded-full"
:disabled="goal >= 400"
@click="goal += 10"
>
<Plus />
<span class="sr-only">Increase</span>
</Button>
</div>
<div class="mt-3 h-[120px]">
<!-- <ResponsiveContainer width="100%" height="100%">
<BarChart data={data}>
<Bar
dataKey="goal"
style={
{
fill: "hsl(var(--foreground))",
opacity: 0.9,
} as React.CSSProperties
}
/>
</BarChart>
</ResponsiveContainer> -->
</div>
</div>
<DrawerFooter>
<Button>Submit</Button>
<DrawerClose as-child>
<Button variant="outline">
Cancel
</Button>
</DrawerClose>
</DrawerFooter>
</div>
</DrawerContent>
</Drawer>
</template>安装
🌐 Installation
pnpm dlx shadcn-vue@latest add drawer
用法
🌐 Usage
<script setup lang="ts">
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from '@/components/ui/drawer'
</script>
<template>
<Drawer>
<DrawerTrigger>Open</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Are you absolutely sure?</DrawerTitle>
<DrawerDescription>
This action cannot be undone.
</DrawerDescription>
</DrawerHeader>
<DrawerFooter>
<Button>Submit</Button>
<DrawerClose>
<Button variant="outline">
Cancel
</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
</template>示例
🌐 Example
响应式模态(对话框与抽屉)
🌐 Responsive Modal (Dialog & Drawer)
对于较小的视口尺寸使用 Drawer 组件,否则使用 Dialog 组件。通过为模态框的各个部分使用插槽,可以进一步实现可复用性。
🌐 Use a Drawer component for smaller viewport sizes and a Dialog component otherwise. This can be further made reusable by using slots for various parts of the modal.
<script setup lang="ts">
import { useMediaQuery } from '@vueuse/core'
import { Button } from '@/components/ui/button'
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from '@/components/ui/drawer'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
const isDesktop = useMediaQuery('(min-width: 640px)')
const Modal = computed(() => ({
Root: isDesktop.value ? Dialog : Drawer,
Trigger: isDesktop.value ? DialogTrigger : DrawerTrigger,
Content: isDesktop.value ? DialogContent : DrawerContent,
Header: isDesktop.value ? DialogHeader : DrawerHeader,
Title: isDesktop.value ? DialogTitle : DrawerTitle,
Description: isDesktop.value ? DialogDescription : DrawerDescription,
Footer: isDesktop.value ? DialogFooter : DrawerFooter,
Close: isDesktop.value ? DialogClose : DrawerClose,
}))
const open = ref(false)
</script>
<template>
<component :is="Modal.Root" v-model:open="open">
<component :is="Modal.Trigger" as-child>
<Button variant="outline">
Open Dialog
</Button>
</component>
<component
:is="Modal.Content"
class="sm:max-w-md" :class="[
{ 'px-2 pb-8 *:px-4': !isDesktop },
]"
>
<component :is="Modal.Header">
<component :is="Modal.Title">
Share Link
</component>
<component :is="Modal.Description">
Anyone who has this link will be able to view this.
</component>
</component>
<div class="flex items-center gap-2">
<div class="grid flex-1 gap-2">
<Label for="link" class="sr-only">
Link
</Label>
<Input
id="link"
default-value="https://www.shadcn-vue.com/docs/installation"
read-only
/>
</div>
</div>
<component :is="Modal.Footer" class="pt-4">
<component :is="Modal.Close" as-child>
<Button variant="outline">
Close
</Button>
</component>
</component>
</component>
</component>
</template>