Building a Complex Synchronized Multi‑Table Layout with Vue and Element UI
This article explains how to create a highly customized table composed of three synchronized Element UI tables in Vue, covering coordinated scrolling, dynamic info‑bar positioning, floating operation columns, style overriding, and performance considerations with code examples.
The author describes a recent project that required a very complex table layout. Instead of using a single UI table component, three separate el-table components are placed side‑by‑side (left, middle, right) to achieve independent horizontal scrolling while maintaining a unified vertical scroll.
Technical challenges include coordinated vertical scrolling across all three tables, mirrored horizontal scrolling between the left and right tables, a floating information bar that must follow the data position, custom styling of the UI components, and a floating operation column that appears on hover.
Coordinated scrolling is implemented by listening to the scroll event on each table container and programmatically setting the scrollTop and scrollLeft of the other tables. The basic idea is shown in the following snippet:
<script>
const leftO = document.querySelector("#left")
const middleO = document.querySelector("#middle")
const rightO = document.querySelector("#right")
leftO.addEventListener("scroll", e => {
const top = e.target.scrollTop
const left = e.target.scrollLeft
middleO.scrollTop = top
rightO.scrollTop = top
rightO.scrollLeft = left
}, true)
middleO.addEventListener("scroll", e => {
const top = e.target.scrollTop
leftO.scrollTop = top
rightO.scrollTop = top
}, true)
rightO.addEventListener("scroll", e => {
const top = e.target.scrollTop
const left = e.target.scrollLeft
leftO.scrollTop = top
middleO.scrollTop = top
leftO.scrollLeft = left
}, true)
</script>Because each scroll handler triggers the others, a naive implementation leads to an infinite loop. The author solves this with a debounce flag (shown in the Vue 3 example) that ensures only one update occurs per user interaction.
// debounce flag
const flag = ref(null)
const scrollLeftFn = e => {
const scrollLeft = e.target.scrollLeft
const scrollTop = e.target.scrollTop
clearTimeout(flag.value)
flag.value = setTimeout(() => {
console.log("left table")
updateMassge(scrollTop)
middleTable.value.setScrollTop(scrollTop)
rightTable.value.setScrollTop(scrollTop)
setLeftFn(scrollLeft)
})
}
// similar functions for right and middle tables …The floating information bar is positioned using absolute positioning. Its vertical top value is calculated with the formula:
top = (index * rowHeight + headerHeight) - scrollTopWhen top is outside the table bounds, the bar is hidden; otherwise it is shown and updated on every scroll event.
A hover‑activated operation column is added by fixing a column on the left (or right) side of the table and using CSS selectors to toggle the visibility of a custom .operation-show element:
.operation-show { display: none; }
.el-table__body tr:hover > td .operation-show { display: block; }To customize the internal styles of Element UI components, the author wraps the table in a container with a custom class and uses the ::v-deep selector to penetrate the component’s scoped CSS, adjusting borders, padding, and header font weight.
In conclusion, the article provides a complete walkthrough of building a sophisticated, synchronized table layout, discusses performance bottlenecks when handling large data sets, and points to a follow‑up article on table optimization.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.