Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export default defineConfig({
{ text: '时间长度限制', link: '/examples/max-time-length' },
{ text: '合并多选标签', link: '/examples/merge-tag' },
{ text: '面板最大高度', link: '/examples/panel-max-height' },
{ text: '虚拟滚动', link: '/examples/virtual-scroll' },
{ text: '潜在匹配项', link: '/examples/potential-match' },
{ text: '自定义默认搜索项', link: '/examples/default-field' },
{ text: '切分输入值', link: '/examples/split-input-value' },
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/apis/props.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
| items | [ISearchBoxItem[]](types.md#isearchboxitem) | [] | 数据项 |
| maxlength | number | -- | input 元素的原生属性,限制输入框的长度,可配合 exceed 监听输入超出限定长度的事件 |
| model-value/v-model | [ISearchBoxTag[]](types.md#isearchboxtag) | [] | 选中的标签列表 |
| panel-max-height | string | 999px | 设置下拉面板最大高度 |
| panel-max-height | string | 999px | 设置下拉面板最大高度。当数据量较大时,组件内置虚拟滚动会以该高度作为可视区域,只渲染可见选项节点,保证流畅滚动 |
| append-to-body | boolean | true | 是否将下拉面板/弹窗挂载到 `body`,用于父容器有 `overflow` 时避免被裁剪 |
| potential-options | getMatchList: (arg1: string) => [ISearchBoxMatchItem[]](types.md#isearchboxmatchitem) | {} | 潜在项匹配,接口返回潜在匹配项的数据列表,异步或同步皆可 |
| show-help | boolean | true | 是否显示帮助图标。3.14.0 及以上版本默认显示;低于此版本默认隐藏 |
Expand Down
18 changes: 18 additions & 0 deletions packages/docs/examples/virtual-scroll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## 虚拟滚动

当数据选项数量较多时(如上千条),二级面板内置虚拟滚动机制,只渲染视口内可见的选项节点,保证滚动流畅不卡顿。

虚拟滚动对 `radio`(单选)、`checkbox`(多选)、`map`(标签)三种类型的二级面板均生效,无需额外配置。配合 `panel-max-height` 可控制下拉面板的滚动区域高度。

<preview path="../search-box/virtual-scroll.vue"></preview>

### 工作原理

- 固定行高(32px),通过滚动监听计算当前可视区域
- 只渲染视口内 + 上下各 5 行缓冲项,DOM 节点数恒定(约 20~30 个)
- 使用占位元素撑开总高度,内容容器通过 `translateY` 定位到正确位置
- 搜索输入变化时自动重置滚动位置到顶部

### Data Source

<<< ../search-box/virtual-scroll-data.ts
51 changes: 51 additions & 0 deletions packages/docs/search-box/virtual-scroll-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 生成大数据量数据源,用于演示二级面板数据选项的虚拟滚动效果

// 生成 1000 个单选选项
function generateRadioOptions(count: number) {
return Array.from({ length: count }, (_, i) => ({
label: `选项-${String(i + 1).padStart(4, '0')}`,
id: `radio-${i + 1}`
}))
}

// 生成 500 个多选选项
function generateCheckboxOptions(count: number) {
return Array.from({ length: count }, (_, i) => ({
label: `区域-${String(i + 1).padStart(4, '0')}`,
id: `region-${i + 1}`
}))
}

// 生成 200 个标签(map)选项,每个含 20 个子值
function generateMapOptions(groupCount: number, childCount: number) {
return Array.from({ length: groupCount }, (_, i) => ({
label: `标签组-${String(i + 1).padStart(3, '0')}`,
id: `tag-group-${i + 1}`,
options: Array.from({ length: childCount }, (_, j) => ({
label: `值-${i + 1}-${j + 1}`,
id: `tag-value-${i + 1}-${j + 1}`
}))
}))
}

export const virtualScrollDataSource = [
{
label: '单选项(1000条)',
field: 'radioLarge',
replace: true,
options: generateRadioOptions(1000)
},
{
label: '多选项(500条)',
field: 'checkboxLarge',
type: 'checkbox',
options: generateCheckboxOptions(500)
},
{
label: '标签(200组x20值)',
field: 'mapLarge',
type: 'map',
searchKeys: ['label', 'id'],
options: generateMapOptions(200, 20)
}
]
26 changes: 26 additions & 0 deletions packages/docs/search-box/virtual-scroll-options-api.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<template>
<div class="demo">
<tiny-search-box
v-model="tags"
:items="items"
panel-max-height="300px"
/>
</div>
</template>

<script>
import TinySearchBox from '@opentiny/vue-search-box'
import { virtualScrollDataSource } from './virtual-scroll-data'

export default {
components: {
TinySearchBox
},
data() {
return {
items: virtualScrollDataSource,
tags: []
}
}
}
</script>
17 changes: 17 additions & 0 deletions packages/docs/search-box/virtual-scroll.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<template>
<ClientOnly>
<tiny-search-box
v-model="tags"
:items="items"
panel-max-height="300px"
/>
</ClientOnly>
</template>

<script setup lang="ts">
import { ref } from "vue";
import { virtualScrollDataSource } from "./virtual-scroll-data";

const items = virtualScrollDataSource;
const tags = ref([]);
</script>
12 changes: 12 additions & 0 deletions packages/docs/search-box/webdoc/search-box.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ export default {
},
codeFiles: ['panel-max-height.vue', 'data-source.ts']
},
{
demoId: 'virtual-scroll',
name: {
'zh-CN': '虚拟滚动',
'en-US': 'Virtual Scroll'
},
desc: {
'zh-CN': ' 当数据选项数量较多时,二级面板内置虚拟滚动机制,只渲染视口内可见的选项节点,保证滚动流畅不卡顿。 ',
'en-US': ' When the number of data options is large, the level-2 panel has a built-in virtual scroll mechanism that renders only the option nodes visible in the viewport, ensuring smooth scrolling without lag. '
},
codeFiles: ['virtual-scroll.vue', 'virtual-scroll-data.ts']
},
{
demoId: 'split-input-value',
name: {
Expand Down
2 changes: 1 addition & 1 deletion packages/search-box/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@opentiny/vue-search-box",
"version": "3.29.0-alpha.0",
"version": "3.29.0",
"description": "",
"homepage": "https://github.com/opentiny/tiny-search-box#readme",
"bugs": {
Expand Down
Loading
Loading