syncTarget 与目标容器实时同步。<template>
<div class="scrollbar-vertical-demo">
<div class="vertical-preview">
<div ref="viewportRef" class="vertical-viewport" :style="{ height: `${viewportSize}px` }">
<div v-for="item in rows" :key="item.id" class="vertical-row">
<div class="row-title">{{ item.title }}</div>
<div class="row-desc">{{ item.desc }}</div>
</div>
</div>
<TsScrollbar
v-model="offset"
class="vertical-scrollbar"
:syncTarget="viewportRef"
:viewportSize="viewportSize"
:contentSize="contentSize"
:width="8"
:minThumbSize="30"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { TsScrollbar } from 'tui';
import { computed, ref } from 'vue';
const offset = ref(0);
const viewportRef = ref<HTMLElement | null>(null);
const rowHeight = 58;
const viewportSize = 220;
const rows = Array.from({ length: 18 }).map((_, index) => ({
id: index + 1,
title: `日志条目 #${String(index + 1).padStart(2, '0')}`,
desc: `这是用于演示纵向滚动条的内容,当前序号 ${index + 1}`,
}));
const contentSize = computed(() => rows.length * rowHeight);
</script>
<style scoped>
.scrollbar-vertical-demo {
max-width: 360px;
}
.vertical-preview {
position: relative;
border-radius: 6px;
border: 1px solid var(--bussiness-doc-border, #e8e8e8);
background: var(--bussiness-doc-surface, #fff);
}
.vertical-viewport {
width: calc(100% - 14px);
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
}
.vertical-viewport::-webkit-scrollbar {
width: 0;
height: 0;
display: none;
}
.vertical-row {
height: 58px;
padding: 10px 12px;
border-bottom: 1px dashed var(--bussiness-doc-border, #e8e8e8);
}
.vertical-row:last-child {
border-bottom: none;
}
.row-title {
font-size: 13px;
color: var(--bussiness-doc-text-primary, #333);
font-weight: 600;
}
.row-desc {
margin-top: 6px;
font-size: 12px;
color: var(--bussiness-doc-text-secondary, #666);
}
.vertical-scrollbar {
top: 6px;
right: 6px;
bottom: 6px;
}
</style>
<template>
<div class="scrollbar-horizontal-demo">
<div class="horizontal-preview">
<div ref="viewportRef" class="horizontal-viewport" :style="{ width: `${viewportSize}px` }">
<div class="horizontal-content" :style="{ width: `${contentSize}px` }">
<div v-for="item in cards" :key="item.id" class="horizontal-card">
<div class="card-title">{{ item.title }}</div>
<div class="card-meta">{{ item.meta }}</div>
</div>
</div>
</div>
<TsScrollbar
v-model="offset"
axis="x"
class="horizontal-scrollbar"
:syncTarget="viewportRef"
:viewportSize="viewportSize"
:contentSize="contentSize"
:width="8"
:minThumbSize="40"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { TsScrollbar } from 'tui';
import { computed, ref } from 'vue';
const offset = ref(0);
const viewportRef = ref<HTMLElement | null>(null);
const viewportSize = 320;
const cardWidth = 160;
const cardGap = 12;
const cards = Array.from({ length: 12 }).map((_, index) => ({
id: index + 1,
title: `横向卡片 ${index + 1}`,
meta: `axis="x" 演示`,
}));
const contentSize = computed(() => cards.length * cardWidth + (cards.length - 1) * cardGap + 20);
</script>
<style scoped>
.scrollbar-horizontal-demo {
max-width: 100%;
}
.horizontal-preview {
position: relative;
height: 128px;
max-width: 100%;
border-radius: 6px;
border: 1px solid var(--bussiness-doc-border, #e8e8e8);
background: var(--bussiness-doc-surface, #fff);
}
.horizontal-viewport {
overflow-x: auto;
overflow-y: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
}
.horizontal-viewport::-webkit-scrollbar {
width: 0;
height: 0;
display: none;
}
.horizontal-content {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 10px 20px;
}
.horizontal-card {
width: 160px;
min-width: 160px;
height: 92px;
padding: 10px 12px;
border-radius: 6px;
border: 1px solid var(--bussiness-doc-border, #e8e8e8);
background: var(--bussiness-doc-panel-bg, #f8f9fa);
}
.card-title {
font-size: 13px;
color: var(--bussiness-doc-text-primary, #333);
font-weight: 600;
}
.card-meta {
margin-top: 10px;
font-size: 12px;
color: var(--bussiness-doc-text-secondary, #666);
}
.horizontal-scrollbar {
left: 10px;
right: 10px;
bottom: 6px;
}
</style>