🌐 Nodejs.cn

一个多功能组件,可用于显示任何内容。

Item 组件是一个简单的弹性容器,可以容纳几乎任何类型的内容。使用它来显示标题、描述和操作。将其与 ItemGroup 组件组合使用,以创建一个项目列表。

🌐 The Item component is a straightforward flex container that can house nearly any type of content. Use it to display a title, description, and actions. Group it with the ItemGroup component to create a list of items.

你几乎可以使用 div 元素和一些类来实现相同的效果,但我已经构建过很多次,所以决定为它创建一个组件。现在我一直在使用它。

🌐 You can pretty much achieve the same result with the div element and some classes, but I've built this so many times that I decided to create a component for it. Now I use it all the time.

Basic Item

A simple item with title and description.

Your profile has been verified.
<script setup lang="ts">
import { BadgeCheckIcon, ChevronRightIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from '@/components/ui/item'
</script>

<template>
  <div class="flex w-full max-w-md flex-col gap-6">
    <Item variant="outline">
      <ItemContent>
        <ItemTitle>Basic Item</ItemTitle>
        <ItemDescription>
          A simple item with title and description.
        </ItemDescription>
      </ItemContent>
      <ItemActions>
        <Button variant="outline" size="sm">
          Action
        </Button>
      </ItemActions>
    </Item>
    <Item variant="outline" size="sm" as-child>
      <a href="#">
        <ItemMedia>
          <BadgeCheckIcon class="size-5" />
        </ItemMedia>
        <ItemContent>
          <ItemTitle>Your profile has been verified.</ItemTitle>
        </ItemContent>
        <ItemActions>
          <ChevronRightIcon class="size-4" />
        </ItemActions>
      </a>
    </Item>
  </div>
</template>

安装

🌐 Installation

pnpm dlx shadcn-vue@latest add item

大小

🌐 Size

Item 组件针对不同的使用场景有不同的尺寸。例如,你可以使用 sm 尺寸用于紧凑型的物品,或者使用 default 尺寸用于标准物品。

🌐 The Item component has different sizes for different use cases. For example, you can use the sm size for a compact item or the default size for a standard item.

Basic Item

A simple item with title and description.

Your profile has been verified.
<script setup lang="ts">
import { BadgeCheckIcon, ChevronRightIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from '@/components/ui/item'
</script>

<template>
  <div class="flex w-full max-w-md flex-col gap-6">
    <Item variant="outline">
      <ItemContent>
        <ItemTitle>Basic Item</ItemTitle>
        <ItemDescription>
          A simple item with title and description.
        </ItemDescription>
      </ItemContent>
      <ItemActions>
        <Button variant="outline" size="sm">
          Action
        </Button>
      </ItemActions>
    </Item>
    <Item variant="outline" size="sm" as-child>
      <a href="#">
        <ItemMedia>
          <BadgeCheckIcon class="size-5" />
        </ItemMedia>
        <ItemContent>
          <ItemTitle>Your profile has been verified.</ItemTitle>
        </ItemContent>
        <ItemActions>
          <ChevronRightIcon class="size-4" />
        </ItemActions>
      </a>
    </Item>
  </div>
</template>

图标

🌐 Icon

Security Alert

New login detected from unknown device.

<script setup lang="ts">
import { ShieldAlertIcon } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from '@/components/ui/item'
</script>

<template>
  <div class="flex w-full max-w-lg flex-col gap-6">
    <Item variant="outline">
      <ItemMedia variant="icon">
        <ShieldAlertIcon />
      </ItemMedia>
      <ItemContent>
        <ItemTitle>Security Alert</ItemTitle>
        <ItemDescription>
          New login detected from unknown device.
        </ItemDescription>
      </ItemContent>
      <ItemActions>
        <Button size="sm" variant="outline">
          Review
        </Button>
      </ItemActions>
    </Item>
  </div>
</template>

头像

🌐 Avatar

ER
Evil Rabbit

Last seen 5 months ago

ER
No Team Members

Invite your team to collaborate on this project.

<script setup lang="ts">
import { Plus } from 'lucide-vue-next'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from '@/components/ui/item'
</script>

<template>
  <div class="flex w-full max-w-lg flex-col gap-6">
    <Item variant="outline">
      <ItemMedia>
        <Avatar class="size-10">
          <AvatarImage src="https://github.com/evilrabbit.png" />
          <AvatarFallback>ER</AvatarFallback>
        </Avatar>
      </ItemMedia>
      <ItemContent>
        <ItemTitle>Evil Rabbit</ItemTitle>
        <ItemDescription>Last seen 5 months ago</ItemDescription>
      </ItemContent>
      <ItemActions>
        <Button
          size="icon-sm"
          variant="outline"
          class="rounded-full"
          aria-label="Invite"
        >
          <Plus />
        </Button>
      </ItemActions>
    </Item>
    <Item variant="outline">
      <ItemMedia>
        <div class="*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale">
          <Avatar class="hidden sm:flex">
            <AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
            <AvatarFallback>CN</AvatarFallback>
          </Avatar>
          <Avatar class="hidden sm:flex">
            <AvatarImage
              src="https://github.com/maxleiter.png"
              alt="@maxleiter"
            />
            <AvatarFallback>LR</AvatarFallback>
          </Avatar>
          <Avatar>
            <AvatarImage
              src="https://github.com/evilrabbit.png"
              alt="@evilrabbit"
            />
            <AvatarFallback>ER</AvatarFallback>
          </Avatar>
        </div>
      </ItemMedia>
      <ItemContent>
        <ItemTitle>No Team Members</ItemTitle>
        <ItemDescription>
          Invite your team to collaborate on this project.
        </ItemDescription>
      </ItemContent>
      <ItemActions>
        <Button size="sm" variant="outline">
          Invite
        </Button>
      </ItemActions>
    </Item>
  </div>
</template>

图片

🌐 Image

<script setup lang="ts">
import {
  Item,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemTitle,
} from '@/components/ui/item'

const music = [
  {
    title: 'Midnight City Lights',
    artist: 'Neon Dreams',
    album: 'Electric Nights',
    duration: '3:45',
  },
  {
    title: 'Coffee Shop Conversations',
    artist: 'The Morning Brew',
    album: 'Urban Stories',
    duration: '4:05',
  },
  {
    title: 'Digital Rain',
    artist: 'Cyber Symphony',
    album: 'Binary Beats',
    duration: '3:30',
  },
]
</script>

<template>
  <div class="flex w-full max-w-md flex-col gap-6">
    <ItemGroup class="gap-4">
      <Item
        v-for="song in music"
        :key="song.title"
        variant="outline"
        as-child
        role="listitem"
      >
        <a href="#">
          <ItemMedia variant="image">
            <img
              :src="`https://avatar.vercel.sh/${song.title}`"
              :alt="song.title"
              width="32"
              height="32"
              class="object-cover grayscale"
            >
          </ItemMedia>
          <ItemContent>
            <ItemTitle class="line-clamp-1">
              {{ song.title }} - <span class="text-muted-foreground">{{ song.album }}</span>
            </ItemTitle>
            <ItemDescription>{{ song.artist }}</ItemDescription>
          </ItemContent>
          <ItemContent class="flex-none text-center">
            <ItemDescription>{{ song.duration }}</ItemDescription>
          </ItemContent>
        </a>
      </Item>
    </ItemGroup>
  </div>
</template>

群组

🌐 Group

s
shadcn

shadcn@vercel.com

m
maxleiter

maxleiter@vercel.com

e
evilrabbit

evilrabbit@vercel.com

<script setup lang="ts">
import { Plus } from 'lucide-vue-next'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemMedia,
  ItemSeparator,
  ItemTitle,
} from '@/components/ui/item'

const people = [
  {
    username: 'shadcn',
    avatar: 'https://github.com/shadcn.png',
    email: 'shadcn@vercel.com',
  },
  {
    username: 'maxleiter',
    avatar: 'https://github.com/maxleiter.png',
    email: 'maxleiter@vercel.com',
  },
  {
    username: 'evilrabbit',
    avatar: 'https://github.com/evilrabbit.png',
    email: 'evilrabbit@vercel.com',
  },
]
</script>

<template>
  <div class="flex w-full max-w-md flex-col gap-6">
    <ItemGroup>
      <template v-for="(person, index) in people" :key="person.username">
        <Item>
          <ItemMedia>
            <Avatar>
              <AvatarImage :src="person.avatar" class="grayscale" />
              <AvatarFallback>{{ person.username.charAt(0) }}</AvatarFallback>
            </Avatar>
          </ItemMedia>
          <ItemContent class="gap-1">
            <ItemTitle>{{ person.username }}</ItemTitle>
            <ItemDescription>{{ person.email }}</ItemDescription>
          </ItemContent>
          <ItemActions>
            <Button variant="ghost" size="icon" class="rounded-full">
              <Plus />
            </Button>
          </ItemActions>
        </Item>
        <ItemSeparator v-if="index !== people.length - 1" />
      </template>
    </ItemGroup>
  </div>
</template>

标题

🌐 Header

<script setup lang="ts">
import {
  Item,
  ItemContent,
  ItemDescription,
  ItemGroup,
  ItemHeader,
  ItemTitle,
} from '@/components/ui/item'

const models = [
  {
    name: 'v0-1.5-sm',
    description: 'Everyday tasks and UI generation.',
    image:
      'https://images.unsplash.com/photo-1650804068570-7fb2e3dbf888?q=80&w=640&auto=format&fit=crop',
    credit: 'Valeria Reverdo on Unsplash',
  },
  {
    name: 'v0-1.5-lg',
    description: 'Advanced thinking or reasoning.',
    image:
      'https://images.unsplash.com/photo-1610280777472-54133d004c8c?q=80&w=640&auto=format&fit=crop',
    credit: 'Michael Oeser on Unsplash',
  },
  {
    name: 'v0-2.0-mini',
    description: 'Open Source model for everyone.',
    image:
      'https://images.unsplash.com/photo-1602146057681-08560aee8cde?q=80&w=640&auto=format&fit=crop',
    credit: 'Cherry Laithang on Unsplash',
  },
]
</script>

<template>
  <div class="flex w-full max-w-xl flex-col gap-6">
    <ItemGroup class="grid grid-cols-3 gap-4">
      <Item
        v-for="model in models"
        :key="model.name"
        variant="outline"
        as-child
        role="listitem"
      >
        <a href="#">
          <ItemHeader>
            <img
              :src="model.image"
              :alt="model.name"
              width="128"
              height="128"
              class="aspect-square w-full rounded-sm object-cover grayscale"
            >
          </ItemHeader>
          <ItemContent>
            <ItemTitle>{{ model.name }}</ItemTitle>
            <ItemDescription>{{ model.description }}</ItemDescription>
          </ItemContent>
        </a>
      </Item>
    </ItemGroup>
  </div>
</template>

链接

🌐 Link

要将一个项目呈现为链接,请使用 as-child 属性。悬停和聚焦状态将应用于锚元素。

🌐 To render an item as a link, use the as-child prop. The hover and focus states will be applied to the anchor element.

<script setup lang="ts">
import { ChevronRightIcon, ExternalLinkIcon } from 'lucide-vue-next'

import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemTitle,
} from '@/components/ui/item'
</script>

<template>
  <div class="flex w-full max-w-md flex-col gap-4">
    <Item as-child>
      <a href="#">
        <ItemContent>
          <ItemTitle>Visit our documentation</ItemTitle>
          <ItemDescription>
            Learn how to get started with our components.
          </ItemDescription>
        </ItemContent>
        <ItemActions>
          <ChevronRightIcon class="size-4" />
        </ItemActions>
      </a>
    </Item>
    <Item variant="outline" as-child>
      <a href="#" target="_blank" rel="noopener noreferrer">
        <ItemContent>
          <ItemTitle>External resource</ItemTitle>
          <ItemDescription>
            Opens in a new tab with security attributes.
          </ItemDescription>
        </ItemContent>
        <ItemActions>
          <ExternalLinkIcon class="size-4" />
        </ItemActions>
      </a>
    </Item>
  </div>
</template>

下拉菜单

🌐 Dropdown

<script setup lang="ts">
import { ChevronDownIcon } from 'lucide-vue-next'
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import {
  Item,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from '@/components/ui/item'

const people = [
  {
    username: 'shadcn',
    avatar: 'https://github.com/shadcn.png',
    email: 'shadcn@vercel.com',
  },
  {
    username: 'maxleiter',
    avatar: 'https://github.com/maxleiter.png',
    email: 'maxleiter@vercel.com',
  },
  {
    username: 'evilrabbit',
    avatar: 'https://github.com/evilrabbit.png',
    email: 'evilrabbit@vercel.com',
  },
]
</script>

<template>
  <div class="flex min-h-64 w-full max-w-md flex-col items-center gap-6">
    <DropdownMenu>
      <DropdownMenuTrigger as-child>
        <Button variant="outline" size="sm" class="w-fit">
          Select <ChevronDownIcon />
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent class="w-72 [--radius:0.65rem]" align="end">
        <DropdownMenuItem v-for="person in people" :key="person.username" class="p-0">
          <Item size="sm" class="w-full p-2">
            <ItemMedia>
              <Avatar class="size-8">
                <AvatarImage :src="person.avatar" class="grayscale" />
                <AvatarFallback>{{ person.username.charAt(0) }}</AvatarFallback>
              </Avatar>
            </ItemMedia>
            <ItemContent class="gap-0.5">
              <ItemTitle>{{ person.username }}</ItemTitle>
              <ItemDescription>{{ person.email }}</ItemDescription>
            </ItemContent>
          </Item>
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  </div>
</template>

API参考

🌐 API Reference

条目

🌐 Item

用于显示带有媒体、标题、描述和操作的内容的主要组件。

🌐 The main component for displaying content with media, title, description, and actions.

属性类型默认值
variant"default" | "outline" | "muted""default"
size"default" | "sm""default"
as-childbooleanfalse
<template>
  <Item size="" variant="">
    <ItemMedia />
    <ItemContent>
      <ItemTitle>Item</ItemTitle>
      <ItemDescription>Item</ItemDescription>
    </ItemContent>
    <ItemActions />
  </Item>
</template>

你可以使用 as-child 属性将自定义组件渲染为项目,例如一个链接。悬停和焦点状态将应用于自定义组件。

🌐 You can use the as-child prop to render a custom component as the item, for example a link. The hover and focus states will be applied to the custom component.

<script setup lang="ts">
import {
  Item,
  ItemContent,
  ItemDescription,
  ItemMedia,
  ItemTitle,
} from '@/components/ui/item'
</script>

<template>
  <Item as-child>
    <a href="/dashboard">
      <ItemMedia variant="icon">
        <Home />
      </ItemMedia>
      <ItemContent>
        <ItemTitle>Dashboard</ItemTitle>
        <ItemDescription>
          Overview of your account and activity.
        </ItemDescription>
      </ItemContent>
    </a>
  </Item>
</template>

ItemGroup

ItemGroup 组件是一个容器,用于将相关项目以一致的样式组合在一起。

🌐 The ItemGroup component is a container that groups related items together with consistent styling.

属性类型默认值
classstring
<template>
  <ItemGroup>
    <Item />
    <Item />
  </ItemGroup>
</template>

ItemSeparator

ItemSeparator 组件是一个分隔符,用于分隔项目组中的项目。

🌐 The ItemSeparator component is a separator that separates items in the item group.

属性类型默认值
classstring
<template>
  <ItemGroup>
    <Item />
    <ItemSeparator />
    <Item />
  </ItemGroup>
</template>

ItemMedia

使用 ItemMedia 组件来显示媒体内容,如图标、图片或头像。

🌐 Use the ItemMedia component to display media content such as icons, images, or avatars.

属性类型默认值
variant"default" | "icon" | "image""default"
classstring
<template>
  <ItemMedia variant="icon">
    <Icon />
  </ItemMedia>
</template>
<template>
  <ItemMedia variant="image">
    <img src="..." alt="...">
  </ItemMedia>
</template>

ItemContent

ItemContent 组件封装了项目的标题和描述。

🌐 The ItemContent component wraps the title and description of the item.

如果你只需要标题,你可以跳过 ItemContent

🌐 You can skip ItemContent if you only need a title.

属性类型默认值
classstring
<template>
  <ItemContent>
    <ItemTitle>Item</ItemTitle>
    <ItemDescription>Item</ItemDescription>
  </ItemContent>
</template>

ItemTitle

使用 ItemTitle 组件来显示项目的标题。

🌐 Use the ItemTitle component to display the title of the item.

属性类型默认值
classstring
<template>
  <ItemTitle>Item Title</ItemTitle>
</template>

ItemDescription

使用 ItemDescription 组件来显示项目的描述。

🌐 Use the ItemDescription component to display the description of the item.

属性类型默认值
classstring
<template>
  <ItemDescription>Item description</ItemDescription>
</template>

ItemActions

使用 ItemActions 组件来显示操作按钮或其他交互元素。

🌐 Use the ItemActions component to display action buttons or other interactive elements.

属性类型默认值
classstring
<template>
  <ItemActions>
    <Button>Action</Button>
    <Button>Action</Button>
  </ItemActions>
</template>

ItemHeader

使用 ItemHeader 组件在项目中显示标题。

🌐 Use the ItemHeader component to display a header in the item.

属性类型默认值
classstring
<template>
  <ItemHeader>Item Header</ItemHeader>
</template>

ItemFooter

使用 ItemFooter 组件在项目中显示页脚。

🌐 Use the ItemFooter component to display a footer in the item.

属性类型默认值
classstring
<template>
  <ItemFooter>Item Footer</ItemFooter>
</template>