Mention 提及

用于在文本输入时触发提及(@)候选列表的组件,支持自定义触发字符、匹配模式和渲染模板。

组件特性

  • 🛠️ 多匹配模式:支持前缀匹配(prefix)、完全匹配(exact)和模糊匹配(fuzzy)。
  • ⌨️ 多触发字符:支持自定义单一或多个触发字符(如 @#)。
  • 🖱️ 高适应性:兼容普通输入框(Input)、文本域(Textarea)以及类富文本编辑器(ContentEditable)。
  • 🎨 自定义渲染:支持通过插槽自定义提及候选列表项的展现形式。

基础用法

最基础的提及展示,使用前缀匹配模式。

<script setup lang="ts">
import { ref } from 'vue'

const text = ref('')
const users = [
  { label: '张三', value: 'zhangsan' },
  { label: '李四', value: 'lisi' },
  { label: '王五', value: 'wangwu' },
  { label: '赵六', value: 'zhaoliu' }
]

const handleSelect = (opt: any) => {
  // console.log('Selected:', opt.label)
}
</script>

<template>
  <BrMention :options="users" @select="handleSelect">
    <BrMentionTrigger>
      <BrInput v-model="text" placeholder="输入 @ 提及用户" class="w-full" />
    </BrMentionTrigger>
    <BrMentionContent />
  </BrMention>
</template>

模糊匹配与文本域

在文本域中使用模糊匹配,并设置最大高度。

<script setup lang="ts">
import { ref } from 'vue'

const text = ref('')
const projects = Array.from({ length: 30 }).map((_, i) => ({
  label: `BreezeUI 项目 ${i + 1}`,
  value: `project-${i + 1}`
}))

const handleSelect = (opt: any) => {
  // console.log('Selected:', opt.label)
}
</script>

<template>
  <BrMention 
    :options="projects" 
    match-mode="fuzzy" 
    max-height="200px" 
    @select="handleSelect"
  >
    <BrMentionTrigger>
      <BrTextarea 
        v-model="text" 
        placeholder="输入 @ 提及项目 (支持模糊搜索,如输入 '1')" 
        :rows="4" 
        class="w-full" 
      />
    </BrMentionTrigger>
    <BrMentionContent />
  </BrMention>
</template>

自定义触发字符与列表项

支持多触发字符(@# 等)以及自定义列表项的内容展示。

<script setup lang="ts">
import { ref } from 'vue'

const text = ref('')
const options = [
  { label: '前端开发部', value: 'fe', description: '负责BreezeUI组件库开发', avatar: 'https://avatars.githubusercontent.com/u/137638062?s=200&v=4' },
  { label: '设计部', value: 'design', description: '负责UI/UX设计规范', avatar: 'https://avatars.githubusercontent.com/u/137638062?s=200&v=4' },
  { label: '产品部', value: 'pm', description: '需求规划', disabled: true }
]

const handleSelect = (opt: any, trigger: string) => {
  // console.log('Selected:', opt.label, 'Trigger:', trigger)
}
</script>

<template>
  <BrMention :options="options" :trigger="['@', '#']" @select="handleSelect">
    <BrMentionTrigger>
      <BrInput v-model="text" placeholder="输入 @ 或 # 触发提及" class="w-full" />
    </BrMentionTrigger>
    <BrMentionContent>
      <template #item="{ option, active }">
        <div class="flex items-center gap-3 w-full p-2">
          <div class="w-6 h-6 rounded-full overflow-hidden shrink-0">
            <img v-if="option.avatar" :src="option.avatar" :alt="option.label" class="w-full h-full object-cover" />
          </div>
          <div class="flex flex-col flex-1">
            <span :class="active ? 'text-primary font-medium' : ''">{{ option.label }}</span>
            <span class="text-xs text-muted-foreground">{{ option.description }}</span>
          </div>
          <span v-if="option.disabled" class="text-xs text-destructive ml-auto">已禁用</span>
        </div>
      </template>
    </BrMentionContent>
  </BrMention>
</template>

ContentEditable 集成

contenteditable 元素中使用提及组件,这在富文本场景中非常常见。

<script setup lang="ts">
import { ref } from 'vue'

const users = [
  { label: '张三', value: 'zhangsan' },
  { label: '李四', value: 'lisi' },
  { label: '王五', value: 'wangwu' }
]
</script>

<template>
  <BrMention :options="users">
    <BrMentionTrigger>
      <div 
        contenteditable="true" 
        class="min-h-[100px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
        placeholder="在此处输入 @ 提及用户..."
      ></div>
    </BrMentionTrigger>
    <BrMentionContent />
  </BrMention>
</template>

主题定制

结合 BrConfigProvider,可以全局覆盖组件默认样式,例如修改主题色和圆角,并配合 highlightClass 属性深度定制选中项的高亮样式。

<script setup lang="ts">
import { ref } from 'vue'

const text = ref('')
const users = [
  { label: '张三', value: 'zhangsan' },
  { label: '李四', value: 'lisi' },
  { label: '王五', value: 'wangwu' },
  { label: '赵六', value: 'zhaoliu' }
]

const handleSelect = (opt: any) => {
  // console.log('Selected:', opt.label)
}
</script>

<template>
  <BrConfigProvider :theme="{ primary: '280 84% 67%', radius: '1rem' }">
    <div class="p-6 border rounded-2xl bg-card shadow-sm">
      <BrMention 
        :options="users" 
        highlight-class="!bg-primary/20 !text-primary"
        @select="handleSelect"
      >
        <BrMentionTrigger>
          <BrInput v-model="text" placeholder="自定义主题色与高亮样式" class="w-full" />
        </BrMentionTrigger>
        <BrMentionContent class="shadow-xl border-primary" />
      </BrMention>
    </div>
  </BrConfigProvider>
</template>

API 说明

BrMention

属性类型默认值说明
triggerstring | string[]'@'触发字符
optionsMentionOption[]-候选列表数据
matchMode'prefix' | 'exact' | 'fuzzy''prefix'匹配模式
position'auto' | 'top' | 'bottom' | 'left' | 'right''auto'候选列表弹出的方向
delaynumber0触发延迟时间(ms)
disabledbooleanfalse是否禁用
loadingbooleanfalse是否为加载中状态
maxHeightstring | number-候选列表最大高度
isolatedbooleanfalse是否开启样式隔离
showEmptybooleantrue是否展示空状态
highlightClassstring-选中的高亮样式定制类名

MentionOption 数据结构

属性类型默认值说明
labelstring-选项显示的文本内容
valuestring-选项的值
disabledbooleanfalse是否禁用该选项
descriptionstring-额外描述文本
avatarstring-选项的头像地址
[key: string]any-支持扩展自定义属性

事件 (Emits)

事件名参数说明
search(query: string, trigger: string)搜索文本变化时触发
select(option: MentionOption, trigger: string)选中候选列表项时触发
open-change(open: boolean)候选列表展开/收起时触发

插槽 (Slots)

BrMentionContent

插槽名参数说明
item{ option: MentionOption, active: boolean }自定义候选列表项渲染