Skip to content

Instantly share code, notes, and snippets.

@IlCallo
Created June 10, 2021 16:03
Show Gist options
  • Save IlCallo/795ddd07dfc6bb48519f3d81f670e77c to your computer and use it in GitHub Desktop.
Save IlCallo/795ddd07dfc6bb48519f3d81f670e77c to your computer and use it in GitHub Desktop.
Composable to manage sticky columns for QTable
.sticky-table .q-table {
th.sticky-cell,
td.sticky-cell {
position: sticky;
z-index: 1;
}
th.last-sticky-cell,
td.last-sticky-cell {
border-right: 2px solid rgba($color: black, $alpha: 0.12);
}
}
.sticky-table.alternate-row-color {
tr:nth-child(odd) {
// Sticky columns feature needs flat colors
background-color: #ffffff;
}
tr:nth-child(even) {
// Equal to: rgba($color: $primary, $alpha: 0.12)
// Calculated with http://marcodiiga.github.io/rgba-to-rgb-conversion
// Sticky columns feature needs flat colors
background-color: #eaebeb !important;
}
}
import {
onMounted,
onUnmounted,
onUpdated,
Ref,
watch
} from '@vue/composition-api';
import { throttle } from 'lodash-es';
import { QTable } from 'quasar';
const STICKY_TABLE_CLASS = 'sticky-table';
const STICKY_CELL_CLASS = 'sticky-cell';
const LAST_STICKY_CELL_CLASS = `last-${STICKY_CELL_CLASS}`;
/**
* Make left-most columns sticky
*
* @param table Reactive reference to the table
* @param count Reactive reference to the number of columns to make sticky
* @returns The method which manually trigger the sticky columns update
*/
export function useStickyColumns(table: Ref<QTable>, count: Ref<number>) {
let $el: Element;
function updateStickyColumns() {
// Must add back the class every time due to
// Vue "class" attribute reactive management which overwrites
// the value at every cycle
$el.classList.add(STICKY_TABLE_CLASS);
const stickyLeftValues: number[] = [];
$el
.querySelectorAll<HTMLElement>(
`.q-table th:nth-child(-n + ${count.value})`
)
.forEach((element, index) => {
const isLastStickyPerRow = index % count.value === count.value - 1;
const leftShift = index === 0 ? 0 : stickyLeftValues[index - 1];
element.style.left = `${leftShift}px`;
element.classList.add(STICKY_CELL_CLASS);
isLastStickyPerRow && element.classList.add(LAST_STICKY_CELL_CLASS);
stickyLeftValues.push(leftShift + element.offsetWidth);
});
$el
.querySelectorAll<HTMLElement>(
`.q-table td:nth-child(-n + ${count.value})`
)
.forEach((element, index) => {
const isLastStickyPerRow = index % count.value === count.value - 1;
const relativeIndex = index % count.value;
element.style.left = `${
relativeIndex === 0 ? 0 : stickyLeftValues[relativeIndex - 1]
}px`;
element.classList.add(STICKY_CELL_CLASS);
isLastStickyPerRow && element.classList.add(LAST_STICKY_CELL_CLASS);
});
}
const throttledUpdate = throttle(updateStickyColumns, 100);
onMounted(() => {
$el = table.value.$el as HTMLElement;
window.addEventListener('resize', throttledUpdate);
});
onUnmounted(() => {
window.removeEventListener('resize', throttledUpdate);
});
onUpdated(updateStickyColumns);
watch(count, () => {
// Cleanup classes related to previous count value
$el
.querySelectorAll<HTMLElement>(`.q-table .${STICKY_CELL_CLASS}`)
.forEach(element =>
element.classList.remove(STICKY_CELL_CLASS, LAST_STICKY_CELL_CLASS)
);
updateStickyColumns();
});
return { updateStickyColumns };
}
const tableRef = ref() as Ref<QTable>;
const stickyColumnCount = ref(4);
useStickyColumns(tableRef, stickyColumnCount);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment