TabsSelect 标签页选择器
多页签选择器,支持分组、列表、树形等结构
基础用法
使用v-model
来绑定选中的值。
tabs
是一个对象数组,对象含有title[tab名称]
、id[tab的id]
、type[列表展示类型]
、options[列表数据]
vue
<template>
<!-- {{ value }} -->
<el-tabs-select
v-model="value"
:tabs="tabs"
style="width: 320px"
@change="handleChange"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const value = ref('tag2')
const tabs = ref([
{
title: '分组展示',
id: '1',
type: 'group',
options: [
{
label: '插件',
children: [
{
label: 'Output1',
value: 'Output1',
children: [
{
label: 'Output1-1',
value: 'Output1-1',
},
],
},
{
label: 'Output2',
value: 'Output2',
},
],
},
{
label: '大模型',
children: [
{
label: 'model1',
value: 'model1',
children: [
{
label: 'model1-1',
value: 'model1-1',
children: [
{
label: 'model1-1-1',
value: 'model1-1-1',
},
],
},
],
},
{
label: 'model2',
value: 'model2',
},
],
},
],
},
{
title: '列表展示',
id: '2',
type: 'option',
options: [
{
label: '当前北京时间',
value: 'time',
},
{
label: 'SOP开始时间',
value: 'sop',
},
],
},
{
title: '树形展示',
id: '3',
type: 'option',
options: [
{
label: 'Vip客户',
value: 'vip',
children: [
{
label: '客户1',
value: 'vip-customer1',
},
{
label: '客户2',
value: 'vip-customer2',
},
],
},
{
label: '普通客户',
value: 'general',
children: [
{
label: '普通-客户1',
value: 'general-customer1',
},
{
label: '普通-客户2',
value: 'general-customer2',
},
],
},
],
},
{
title: '异步数据',
id: '4',
type: 'option',
options: [],
},
])
const handleChange = (value) => {
console.log(value)
}
// 模拟异步接口请求,更新数据源
setTimeout(() => {
tabs.value[3].options = [
{
label: '标签1',
value: 'tag1',
},
{
label: '标签2',
value: 'tag2',
},
]
}, 1000)
</script>
隐藏源代码
多选
使用multiple
属性来进行多选。其余属性参考ElSelect
组件属性
vue
<template>
<!-- {{ value }} -->
<el-tabs-select
v-model="value"
multiple
fit-input-width
collapse-tags
collapse-tags-tooltip
:max-collapse-tags="2"
:tabs="tabs"
style="width: 320px"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const value = ref(['Output1', 'time'])
const tabs = ref([
{
title: '分组展示',
id: '1',
type: 'group',
options: [
{
label: '插件',
children: [
{
label: 'Output1',
value: 'Output1',
children: [
{
label: 'Output1-1',
value: 'Output1-1',
},
],
},
{
label: 'Output2',
value: 'Output2',
},
],
},
{
label: '大模型',
children: [
{
label: 'model1',
value: 'model1',
children: [
{
label: 'model1-1',
value: 'model1-1',
children: [
{
label: 'model1-1-1',
value: 'model1-1-1',
},
],
},
],
},
{
label: 'model2',
value: 'model2',
},
],
},
],
},
{
title: '列表展示',
id: '2',
type: 'option',
options: [
{
label: '当前北京时间',
value: 'time',
},
{
label: 'SOP开始时间',
value: 'sop',
},
],
},
{
title: '树形展示',
id: '3',
type: 'option',
options: [
{
label: 'Vip客户',
value: 'vip',
children: [
{
label: '客户1',
value: 'vip-customer1',
},
{
label: '客户2',
value: 'vip-customer2',
},
],
},
{
label: '普通客户',
value: 'general',
children: [
{
label: '普通-客户1',
value: 'general-customer1',
},
{
label: '普通-客户2',
value: 'general-customer2',
},
],
},
],
},
{
title: '异步数据',
id: '4',
type: 'option',
options: [],
},
])
// 模拟异步接口请求,更新数据源
setTimeout(() => {
tabs.value[3].options = [
{
label: '标签1',
value: 'tag1',
},
{
label: '标签2',
value: 'tag2',
},
]
}, 1000)
</script>
隐藏源代码
支持绑定对象和对象数组
使用value-key
属性来绑定对象和对象数组,和 ElSelect`功能一致
{ "label": "Output1", "value": "Output1" }
vue
<template>
<pre>{{ value }}</pre>
<el-tabs-select
v-model="value"
:tabs="tabs"
style="width: 320px"
value-key="value"
:multiple="false"
@change="handleChange"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
// const value = ref([
// { label: 'Output1', value: 'Output1' },
// {
// label: '标签1',
// value: 'tag1',
// },
// ])
const value = ref({ label: 'Output1', value: 'Output1' })
const tabs = ref([
{
title: '分组展示',
id: '1',
type: 'group',
options: [
{
label: '插件',
children: [
{
label: 'Output1',
value: 'Output1',
children: [
{
label: 'Output1-1',
value: 'Output1-1',
},
],
},
{
label: 'Output2',
value: 'Output2',
},
],
},
{
label: '大模型',
children: [
{
label: 'model1',
value: 'model1',
children: [
{
label: 'model1-1',
value: 'model1-1',
children: [
{
label: 'model1-1-1',
value: 'model1-1-1',
},
],
},
],
},
{
label: 'model2',
value: 'model2',
},
],
},
],
},
{
title: '列表展示',
id: '2',
type: 'option',
options: [
{
label: '当前北京时间',
value: 'time',
},
{
label: 'SOP开始时间',
value: 'sop',
},
],
},
{
title: '树形展示',
id: '3',
type: 'option',
options: [
{
label: 'Vip客户',
value: 'vip',
children: [
{
label: '客户1',
value: 'vip-customer1',
},
{
label: '客户2',
value: 'vip-customer2',
},
],
},
{
label: '普通客户',
value: 'general',
children: [
{
label: '普通-客户1',
value: 'general-customer1',
},
{
label: '普通-客户2',
value: 'general-customer2',
},
],
},
],
},
{
title: '异步数据',
id: '4',
type: 'option',
options: [],
},
])
const handleChange = (value) => {
console.log(value)
}
// 模拟异步接口请求,更新数据源
setTimeout(() => {
tabs.value[3].options = [
{
label: '标签1',
value: 'tag1',
},
{
label: '标签2',
value: 'tag2',
},
]
}, 1000)
</script>
隐藏源代码
自定义 Option
使用option
插槽来自定义每一项内容,参数值同ElTree
默认插槽的node
和data
请选择
vue
<template>
<!-- {{ value }} -->
<el-tabs-select
v-model="select"
:tabs="tabs"
style="width: 300px"
:show-search="false"
>
<template #option="{ data }">
<span style="color: #f60">{{ data.label }}-{{ data.value }}</span>
</template>
</el-tabs-select>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const select = ref()
const tabs = ref([
{
title: '分组展示',
id: '1',
type: 'group',
options: [
{
label: '插件',
children: [
{
label: 'Output1',
value: 'Output1',
children: [
{
label: 'Output1-1',
value: 'Output1-1',
},
],
},
{
label: 'Output2',
value: 'Output2',
},
],
},
{
label: '大模型',
children: [
{
label: 'model1',
value: 'model1',
children: [
{
label: 'model1-1',
value: 'model1-1',
children: [
{
label: 'model1-1-1',
value: 'model1-1-1',
},
],
},
],
},
{
label: 'model2',
value: 'model2',
},
],
},
],
},
{
title: '列表展示',
id: '2',
type: 'option',
options: [
{
label: '当前北京时间',
value: 'time',
},
{
label: 'SOP开始时间',
value: 'sop',
},
],
},
{
title: '树形展示',
id: '3',
type: 'option',
options: [
{
label: 'Vip客户',
value: 'vip',
children: [
{
label: '客户1',
value: 'vip-customer1',
},
{
label: '客户2',
value: 'vip-customer2',
},
],
},
{
label: '普通客户',
value: 'general',
children: [
{
label: '普通-客户1',
value: 'general-customer1',
},
{
label: '普通-客户2',
value: 'general-customer2',
},
],
},
],
},
])
</script>
隐藏源代码
远程搜索
使用loading
来控制加载状态,使用remoteMethod
来加载远程数据
注意这个远程搜索和ElSelect
交互不一致,但是使用姿势类似
vue
<template>
<!-- {{ value }} -->
<el-tabs-select
v-model="value"
:tabs="tabs"
style="width: 320px"
:loading="loading"
:remote-method="remoteMethod"
@change="handleChange"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const value = ref('tag2')
const loading = ref(false)
const remoteMethod = (query: string, currentTabId: string) => {
if (loading.value) return
// 自定义业务逻辑,这里只是简单的赋值操作
if (query) {
loading.value = true
setTimeout(() => {
loading.value = false
tabs.value.find((item) => item.id === currentTabId)!.options = [
{
label: `${query}1`,
value: `${query}1`,
},
{
label: `${query}2`,
value: `${query}2`,
},
]
}, 200)
}
}
const tabs = ref([
{
title: '分组展示',
id: '1',
type: 'group',
options: [
{
label: '插件',
children: [
{
label: 'Output1',
value: 'Output1',
children: [
{
label: 'Output1-1',
value: 'Output1-1',
},
],
},
{
label: 'Output2',
value: 'Output2',
},
],
},
{
label: '大模型',
children: [
{
label: 'model1',
value: 'model1',
children: [
{
label: 'model1-1',
value: 'model1-1',
children: [
{
label: 'model1-1-1',
value: 'model1-1-1',
},
],
},
],
},
{
label: 'model2',
value: 'model2',
},
],
},
],
},
{
title: '列表展示',
id: '2',
type: 'option',
options: [
{
label: '当前北京时间',
value: 'time',
},
{
label: 'SOP开始时间',
value: 'sop',
},
],
},
{
title: '树形展示',
id: '3',
type: 'option',
options: [
{
label: 'Vip客户',
value: 'vip',
children: [
{
label: '客户1',
value: 'vip-customer1',
},
{
label: '客户2',
value: 'vip-customer2',
},
],
},
{
label: '普通客户',
value: 'general',
children: [
{
label: '普通-客户1',
value: 'general-customer1',
},
{
label: '普通-客户2',
value: 'general-customer2',
},
],
},
],
},
{
title: '异步数据',
id: '4',
type: 'option',
options: [],
},
])
const handleChange = (value) => {
console.log(value)
}
// 模拟异步接口请求,更新数据源
setTimeout(() => {
tabs.value[3].options = [
{
label: '标签1',
value: 'tag1',
},
{
label: '标签2',
value: 'tag2',
},
]
}, 1000)
</script>
隐藏源代码
面板
tabs-select
组件弹窗内容,已被剥离,使用tabs-select-panel
即可
使用姿势和tabs-select
一致
Output1
分组展示
列表展示
树形展示
异步数据
暂无数据
vue
<template>
<pre>{{ value }}</pre>
<el-tabs-select-panel
v-model="value"
v-model:tab="tab"
:multiple="false"
:tabs="tabs"
prefix-label=""
style="max-width: 380px"
:tabs-props="{ stretch: true }"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const tab = ref('4')
// const value = ref(['Output1', 'time'])
const value = ref('Output1')
const tabs = ref([
{
title: '分组展示',
id: '1',
type: 'group',
options: [
{
label: '插件',
children: [
{
label: 'Output1',
value: 'Output1',
children: [
{
label: 'Output1-1',
value: 'Output1-1',
},
],
},
{
label: 'Output2',
value: 'Output2',
},
],
},
{
label: '大模型',
children: [
{
label: 'model1',
value: 'model1',
children: [
{
label: 'model1-1',
value: 'model1-1',
children: [
{
label: 'model1-1-1',
value: 'model1-1-1',
},
],
},
],
},
{
label: 'model2',
value: 'model2',
},
],
},
],
},
{
title: '列表展示',
id: '2',
type: 'option',
options: [
{
label: '当前北京时间',
value: 'time',
},
{
label: 'SOP开始时间',
value: 'sop',
},
],
},
{
title: '树形展示',
id: '3',
type: 'option',
options: [
{
label: 'Vip客户',
value: 'vip',
children: [
{
label: '客户1',
value: 'vip-customer1',
},
{
label: '客户2',
value: 'vip-customer2',
},
],
},
{
label: '普通客户',
value: 'general',
children: [
{
label: '普通-客户1',
value: 'general-customer1',
},
{
label: '普通-客户2',
value: 'general-customer2',
},
],
},
],
},
{
title: '异步数据',
id: '4',
type: 'option',
options: [],
},
])
// 模拟异步接口请求,更新数据源
setTimeout(() => {
tabs.value[3].options = [
{
label: '标签1',
value: 'tag1',
},
{
label: '标签2',
value: 'tag2',
},
]
}, 1000)
</script>
隐藏源代码
面板-远程搜索
和tabs-select
组件使用一致
列表展示
树形展示
当前北京时间
SOP开始时间
vue
<template>
<pre>{{ value }}</pre>
<el-tabs-select-panel
v-model="value"
v-model:tab="tab"
:multiple="false"
:tabs="tabs"
prefix-label=""
style="max-width: 380px"
:loading="loading"
:remote-method="remoteMethod"
:tabs-props="{ stretch: true }"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const tab = ref('1')
const value = ref()
const loading = ref(false)
const remoteMethod = (query: string, currentTabId: string) => {
if (loading.value) return
// 自定义业务逻辑,这里只是简单的赋值操作
if (query) {
loading.value = true
setTimeout(() => {
loading.value = false
tabs.value.find((item) => item.id === currentTabId)!.options = [
{
label: `${query}1`,
value: `${query}1`,
},
{
label: `${query}2`,
value: `${query}2`,
},
]
}, 200)
}
}
const tabs = ref([
{
title: '列表展示',
id: '1',
type: 'option',
options: [
{
label: '当前北京时间',
value: 'time',
},
{
label: 'SOP开始时间',
value: 'sop',
},
],
},
{
title: '树形展示',
id: '2',
type: 'option',
options: [
{
label: 'Vip客户',
value: 'vip',
children: [
{
label: '客户1',
value: 'vip-customer1',
},
{
label: '客户2',
value: 'vip-customer2',
},
],
},
{
label: '普通客户',
value: 'general',
children: [
{
label: '普通-客户1',
value: 'general-customer1',
},
{
label: '普通-客户2',
value: 'general-customer2',
},
],
},
],
},
])
</script>
隐藏源代码
面板绑定也支持对象和对象数组
[ { "id": "tag1" } ]
分组展示
列表展示
树形展示
异步数据
暂无数据
vue
<template>
<pre>{{ value }}</pre>
<el-tabs-select-panel
v-model="value"
v-model:tab="tab"
:multiple="true"
:tabs="tabs"
prefix-label=""
style="max-width: 380px"
value-key="id"
:tabs-props="{ stretch: true }"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const tab = ref('4')
const value = ref([{ id: 'tag1' }])
// const value = ref({ id: 'tag1' })
const tabs = ref([
{
title: '分组展示',
id: '1',
type: 'group',
options: [
{
label: '插件',
children: [
{
label: 'Output1',
id: 'Output1',
children: [
{
label: 'Output1-1',
id: 'Output1-1',
},
],
},
{
label: 'Output2',
id: 'Output2',
},
],
},
{
label: '大模型',
children: [
{
label: 'model1',
id: 'model1',
children: [
{
label: 'model1-1',
id: 'model1-1',
children: [
{
label: 'model1-1-1',
id: 'model1-1-1',
},
],
},
],
},
{
label: 'model2',
id: 'model2',
},
],
},
],
},
{
title: '列表展示',
id: '2',
type: 'option',
options: [
{
label: '当前北京时间',
id: 'time',
},
{
label: 'SOP开始时间',
id: 'sop',
},
],
},
{
title: '树形展示',
id: '3',
type: 'option',
options: [
{
label: 'Vip客户',
id: 'vip',
children: [
{
label: '客户1',
id: 'vip-customer1',
},
{
label: '客户2',
id: 'vip-customer2',
},
],
},
{
label: '普通客户',
id: 'general',
children: [
{
label: '普通-客户1',
id: 'general-customer1',
},
{
label: '普通-客户2',
id: 'general-customer2',
},
],
},
],
},
{
title: '异步数据',
id: '4',
type: 'option',
options: [],
},
])
// 模拟异步接口请求,更新数据源
setTimeout(() => {
tabs.value[3].options = [
{
label: '标签1',
id: 'tag1',
},
{
label: '标签2',
id: 'tag2',
},
]
}, 1000)
</script>
隐藏源代码
基于面板
比如可以把面板内容插入到编辑器中
vue
<template>
<el-editor
ref="editor"
v-model="html"
class="editor"
resize
disable-enter-emit
placeholder="输入点什么"
style="margin-bottom: 12px"
/>
<el-popover
placement="right"
:visible="visible"
:width="320"
:popper-style="{ padding: '0px' }"
>
<template #reference>
<el-button style="margin-right: 16px" @click="visible = !visible">
插入内容
</el-button>
</template>
<el-tabs-select-panel
v-model="select"
v-model:tab="tab"
:tabs="tabs"
:border="false"
value-key="value"
@change="handleChange"
/>
</el-popover>
<el-button @click="getText"> 获取纯文本内容 </el-button>
<pre>{{ text }}</pre>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { getTextContent } from 'element-plus-x'
const html = ref()
const visible = ref(false)
const tab = ref('1')
const select = ref()
const editor = ref()
const text = ref()
const handleChange = (data) => {
visible.value = false
select.value = ''
editor.value.insertHtml(
` <tag disable-transitions id="${data.value}" class="tag" text="{{ ${data.label} }}"></tag> `
)
}
function getText() {
text.value = getTextContent(editor.value.getHtml(), [
{
tag: 'tag',
attr: 'id',
},
])
}
const tabs = ref([
{
title: '分组展示',
id: '1',
type: 'group',
options: [
{
label: '插件',
children: [
{
label: 'Output1',
value: 'Output1',
children: [
{
label: 'Output1-1',
value: 'Output1-1',
},
],
},
{
label: 'Output2',
value: 'Output2',
},
],
},
{
label: '大模型',
children: [
{
label: 'model1',
value: 'model1',
children: [
{
label: 'model1-1',
value: 'model1-1',
children: [
{
label: 'model1-1-1',
value: 'model1-1-1',
},
],
},
],
},
{
label: 'model2',
value: 'model2',
},
],
},
],
},
{
title: '列表展示',
id: '2',
type: 'option',
options: [
{
label: '当前北京时间',
value: 'time',
},
{
label: 'SOP开始时间',
value: 'sop',
},
],
},
{
title: '树形展示',
id: '3',
type: 'option',
options: [
{
label: 'Vip客户',
value: 'vip',
children: [
{
label: '客户1',
value: 'vip-customer1',
},
{
label: '客户2',
value: 'vip-customer2',
},
],
},
{
label: '普通客户',
value: 'general',
children: [
{
label: '普通-客户1',
value: 'general-customer1',
},
{
label: '普通-客户2',
value: 'general-customer2',
},
],
},
],
},
{
title: '异步数据',
id: '4',
type: 'option',
options: [],
},
])
// 模拟异步接口请求,更新数据源
setTimeout(() => {
tabs.value[3].options = [
{
label: '标签1',
value: 'tag1',
},
{
label: '标签2',
value: 'tag2',
},
]
}, 1000)
</script>
<style lang="scss" scoped>
.editor {
max-width: 450px;
min-height: 80px;
max-height: 250px;
line-height: 26px;
}
</style>
隐藏源代码
API
TabsSelect、TabsSelectPanel 属性
TabsSelect 其他相关的 API 属性,请参考 ElSelect 即可
属性名 | 说明 | 类型 | 默认值 |
---|---|---|---|
modelValue | 双向绑定值 | String|Number|Array|Object | - |
tabs | 分页配置 | Array | - |
tab | tab 绑定的值(只适用于 tabs-select-panel 组件) | String|Number | - |
prefixLabel | label 前缀 | String | {x} |
multiple | 是否多选 | Boolean | - |
tabsProps | el-tabs 组件属性 | Object | - |
treeProps | el-tree 组件属性 | Boolean | - |
border | 是否含有边框(只适用于 tabs-select-panel 组件) | Boolean | - |
maxHeight | 列表内容的高度 | String | 260px |
panelStyle | panelStyle 面板的样式 | Object | - |
showSearch | 是否显示搜索框 | Boolean | - |
valueKey | 作为 value 唯一标识的键名,绑定值为对象类型时必填 | Boolean | - |
Event
事件名 | 说明 | 参数 |
---|---|---|
change | 点击项时的事件 | (data: IPanelModelValue) => true |
selected-options-change | 当 v-model 时发生变化时所收集的 options | (val: ITreeOption[]) => isArray(val) |
TabsSelect、TabsSelectPanel Slots
事件名 | 说明 | 参数 |
---|---|---|
option | 自定义选项内容 | {node, data} |