Implement custom scrollbar for DataTable component. Refactor structure to include a scrollable wrapper and synchronize scroll positions between the table and the custom scrollbar. Update styles for improved visibility and functionality of the scrollbar.
This commit is contained in:
@ -1246,6 +1246,44 @@ section {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.list-wrapper-container {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.list-wrapper-scrollbar-top {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
height: 17px;
|
||||
margin-bottom: 0;
|
||||
display: none;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.list-wrapper-scrollbar-top .scrollbar-content {
|
||||
height: 1px;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.list-wrapper-scrollbar-top::-webkit-scrollbar {
|
||||
height: 17px;
|
||||
}
|
||||
|
||||
.list-wrapper-scrollbar-top::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.list-wrapper-scrollbar-top::-webkit-scrollbar-thumb {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.list-wrapper-scrollbar-top::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.list-wrapper {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
@ -2374,6 +2412,14 @@ section {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.list-wrapper-container {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.list-wrapper-scrollbar-top {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.list-wrapper {
|
||||
overflow: visible;
|
||||
overflow-x: visible;
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
<template>
|
||||
<div class="list-wrapper">
|
||||
<table class="table-border table-colored table-list">
|
||||
<div class="list-wrapper-container">
|
||||
<div class="list-wrapper-scrollbar-top" ref="scrollbarTopRef">
|
||||
<div class="scrollbar-content"></div>
|
||||
</div>
|
||||
<div class="list-wrapper" ref="listWrapperRef" @scroll="onScroll">
|
||||
<table class="table-border table-colored table-list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="table-head-row-number" v-if="rowNumber">
|
||||
@ -135,6 +139,7 @@
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<data-table-pagination
|
||||
v-if="pagination !== undefined && showPagination && !isPreview"
|
||||
@ -142,7 +147,7 @@
|
||||
:isUseRoute="isUseRoute" />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { ref, reactive, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import { useGlobalStore } from '@/stores/globalStore'
|
||||
import icourl from '@/assets/images/icons.svg'
|
||||
@ -172,7 +177,7 @@
|
||||
}
|
||||
export interface Props {
|
||||
tableHeader: ITableHead[]
|
||||
tableData: Record<string, any>
|
||||
tableData: Record<string, any>[]
|
||||
rowAction?: Function | string
|
||||
pagination?: IPagination
|
||||
sortData?: ISort
|
||||
@ -285,6 +290,95 @@
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.tableData,
|
||||
() => {
|
||||
// Tablo verisi değiştiğinde scrollbar'ı güncelle
|
||||
setTimeout(() => {
|
||||
syncScrollbars()
|
||||
}, 100)
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
const listWrapperRef = ref<HTMLElement | null>(null)
|
||||
const scrollbarTopRef = ref<HTMLElement | null>(null)
|
||||
|
||||
const onScroll = (e: Event) => {
|
||||
const target = e.target as HTMLElement
|
||||
if (scrollbarTopRef.value) {
|
||||
scrollbarTopRef.value.scrollLeft = target.scrollLeft
|
||||
}
|
||||
}
|
||||
|
||||
const syncScrollbars = () => {
|
||||
if (listWrapperRef.value && scrollbarTopRef.value) {
|
||||
const table = listWrapperRef.value.querySelector('table')
|
||||
if (table) {
|
||||
const tableWidth = table.scrollWidth
|
||||
const wrapperWidth = listWrapperRef.value.clientWidth
|
||||
|
||||
if (tableWidth > wrapperWidth) {
|
||||
scrollbarTopRef.value.style.display = 'block'
|
||||
scrollbarTopRef.value.scrollLeft = listWrapperRef.value.scrollLeft
|
||||
// Scrollbar wrapper'ın içeriğinin genişliğini tablo genişliğine eşitle
|
||||
const scrollbarContent = scrollbarTopRef.value.querySelector('.scrollbar-content') as HTMLElement | null
|
||||
if (scrollbarContent) {
|
||||
scrollbarContent.style.width = tableWidth + 'px'
|
||||
scrollbarContent.style.height = '1px'
|
||||
}
|
||||
} else {
|
||||
scrollbarTopRef.value.style.display = 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const onTopScroll = (e: Event) => {
|
||||
const target = e.target as HTMLElement
|
||||
if (listWrapperRef.value) {
|
||||
listWrapperRef.value.scrollLeft = target.scrollLeft
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await nextTick()
|
||||
|
||||
if (scrollbarTopRef.value) {
|
||||
scrollbarTopRef.value.addEventListener('scroll', onTopScroll)
|
||||
}
|
||||
|
||||
// İlk scrollbar senkronizasyonu
|
||||
setTimeout(() => {
|
||||
syncScrollbars()
|
||||
}, 100)
|
||||
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
syncScrollbars()
|
||||
})
|
||||
|
||||
if (listWrapperRef.value) {
|
||||
resizeObserver.observe(listWrapperRef.value)
|
||||
}
|
||||
|
||||
const tableObserver = new MutationObserver(() => {
|
||||
syncScrollbars()
|
||||
})
|
||||
|
||||
if (listWrapperRef.value) {
|
||||
const table = listWrapperRef.value.querySelector('table')
|
||||
if (table) {
|
||||
tableObserver.observe(table, { childList: true, subtree: true, attributes: true })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
if (scrollbarTopRef.value) {
|
||||
scrollbarTopRef.value.removeEventListener('scroll', onTopScroll)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style scoped>
|
||||
.action-fixed {
|
||||
|
||||
Reference in New Issue
Block a user