123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- /**
- * 表格高亮 Composable
- * 用于在 ContentRenderer 渲染的表格中高亮当前产品型号对应的列
- */
- export function useTableHighlight() {
- /**
- * 高亮包含指定文本的表格列
- * @param highlightText 要高亮的文本内容
- * @param containerSelector 容器选择器,默认为 '.prose'
- * @param highlightClass 高亮CSS类名,默认为 'highlighted-model-column'
- */
- function highlightTableColumns(
- highlightText: string,
- containerSelector: string = ".full-table-screen .prose",
- highlightClass: string = "highlighted-model-column"
- ) {
- if (!highlightText?.trim()) return;
-
- const containers = document.querySelectorAll(containerSelector);
-
- containers.forEach((container) => {
- const tables = container.querySelectorAll("table");
-
- tables.forEach((table) => {
- const rows = table.querySelectorAll("tbody tr, tr");
- const targetColumnIndexes: number[] = [];
-
- // 首先遍历所有行,找到包含目标文本的列索引
- rows.forEach((row) => {
- const cells = row.querySelectorAll("td, th");
- cells.forEach((cell, columnIndex) => {
- const textContent = cell.textContent?.trim() || "";
- if (textContent === highlightText.trim()) {
- if (!targetColumnIndexes.includes(columnIndex)) {
- targetColumnIndexes.push(columnIndex);
- }
- }
- });
- });
-
- // 清除所有列的高亮
- rows.forEach((row) => {
- const cells = row.querySelectorAll("td, th");
- cells.forEach((cell) => {
- cell.classList.remove(highlightClass);
- });
- });
-
- // 高亮目标列的所有单元格
- if (targetColumnIndexes.length > 0) {
- rows.forEach((row) => {
- const cells = row.querySelectorAll("td, th");
- targetColumnIndexes.forEach((columnIndex) => {
- if (cells[columnIndex]) {
- cells[columnIndex].classList.add(highlightClass);
- }
- });
- });
-
- // 在小屏幕上自动滚动到高亮列
- scrollToHighlightedColumn(table, targetColumnIndexes[0]);
- }
- });
- });
- }
-
- /**
- * 在小屏幕上滚动到高亮列
- * @param table 表格元素
- * @param columnIndex 列索引
- */
- function scrollToHighlightedColumn(table: Element, columnIndex: number) {
- if (typeof window === "undefined") return;
-
- // 只在小屏幕上执行滚动
- if (window.innerWidth > 768) return;
-
- const firstRow = table.querySelector("tr");
- if (!firstRow) return;
-
- const targetCell = firstRow.children[columnIndex] as HTMLElement;
- if (!targetCell) return;
-
- // 找到可滚动的父容器
- const scrollContainer = table.closest(".prose")?.parentElement;
- if (!scrollContainer) return;
-
- // 延迟执行滚动,确保样式已应用
- setTimeout(() => {
- const cellRect = targetCell.getBoundingClientRect();
- const containerRect = scrollContainer.getBoundingClientRect();
-
- // 计算需要滚动的距离
- const scrollLeft =
- targetCell.offsetLeft - containerRect.width / 2 + cellRect.width / 2;
-
- scrollContainer.scrollTo({
- left: Math.max(0, scrollLeft),
- behavior: "smooth",
- });
- }, 200);
- }
-
- /**
- * 添加表格响应式包装器
- * @param table 表格元素
- */
- function wrapTableForResponsive(table: Element) {
- if (table.parentElement?.classList.contains("table-responsive-wrapper")) {
- return; // 已经包装过了
- }
-
- const wrapper = document.createElement("div");
- wrapper.className =
- "table-responsive-wrapper overflow-x-auto bg-zinc-900 rounded-lg";
- wrapper.style.cssText = `
- overflow-x: auto;
- -webkit-overflow-scrolling: touch;
- border-radius: 8px;
- background: rgb(24 24 27);
- margin: 1rem 0;
- `;
-
- // 确保表格有足够的宽度
- (table as HTMLElement).style.cssText = `
- min-width: 1200px;
- width: 100%;
- margin: 0;
- border-radius: 0;
- table-layout: auto;
- `;
-
- // 为表格单元格设置合适的宽度
- const cells = table.querySelectorAll("th, td");
- cells.forEach((cell, index) => {
- const htmlCell = cell as HTMLElement;
- if (index === 0) {
- // 第一列给更多宽度
- htmlCell.style.minWidth = "200px";
- } else {
- htmlCell.style.minWidth = "150px";
- }
- htmlCell.style.maxWidth = "300px";
- htmlCell.style.whiteSpace = "nowrap";
- htmlCell.style.overflow = "hidden";
- htmlCell.style.textOverflow = "ellipsis";
- });
-
- // 添加滚动指示器
- const scrollIndicator = document.createElement("div");
- scrollIndicator.className =
- "scroll-indicator text-xs text-zinc-400 mb-2 block md:hidden";
- table.parentNode?.insertBefore(wrapper, table);
- wrapper.appendChild(scrollIndicator);
- wrapper.appendChild(table);
-
- // 监听滚动,隐藏指示器
- wrapper.addEventListener("scroll", () => {
- if (wrapper.scrollLeft > 10) {
- scrollIndicator.style.display = "none";
- }
- });
-
- // 添加自定义滚动条样式
- const style = document.createElement("style");
- style.textContent = `
- .table-responsive-wrapper::-webkit-scrollbar {
- height: 12px;
- }
- .table-responsive-wrapper::-webkit-scrollbar-track {
- background: rgb(39 39 42);
- border-radius: 6px;
- }
- .table-responsive-wrapper::-webkit-scrollbar-thumb {
- background: rgb(34 197 94);
- border-radius: 6px;
- border: 2px solid rgb(39 39 42);
- }
- .table-responsive-wrapper::-webkit-scrollbar-thumb:hover {
- background: rgb(34 197 94 / 0.8);
- }
- @keyframes fadeInOut {
- 0%, 100% { opacity: 0.6; }
- 50% { opacity: 1; }
- }
- `;
-
- if (!document.head.querySelector("#table-scroll-styles")) {
- style.id = "table-scroll-styles";
- document.head.appendChild(style);
- }
- }
-
- /**
- * 初始化表格列高亮功能
- * @param highlightText 要高亮的文本内容(响应式)
- * @param delay 延迟执行时间(毫秒),默认500ms
- */
- function initTableHighlight(
- highlightText: Ref<string> | ComputedRef<string>,
- delay: number = 500
- ) {
- // 页面挂载后执行高亮
- onMounted(() => {
- nextTick(() => {
- setTimeout(() => {
- // 为所有表格添加响应式包装器
- const tables = document.querySelectorAll(".full-table-screen .prose table");
- tables.forEach(wrapTableForResponsive);
-
- // 执行高亮
- highlightTableColumns(unref(highlightText));
- }, delay);
- });
- });
-
- // 监听文本变化,重新高亮
- watch(highlightText, (newText) => {
- nextTick(() => {
- setTimeout(() => {
- highlightTableColumns(newText);
- }, 100);
- });
- });
-
- // 监听窗口大小变化,重新调整表格
- if (typeof window !== "undefined") {
- const handleResize = debounce(() => {
- const tables = document.querySelectorAll(".full-table-screen .prose table");
- tables.forEach(wrapTableForResponsive);
- highlightTableColumns(unref(highlightText));
- }, 300);
-
- window.addEventListener("resize", handleResize);
-
- onUnmounted(() => {
- window.removeEventListener("resize", handleResize);
- });
- }
- }
-
- /**
- * 防抖函数
- * @param func 要防抖的函数
- * @param delay 延迟时间
- */
- function debounce(func: Function, delay: number) {
- let timeoutId: ReturnType<typeof setTimeout>;
- return (...args: any[]) => {
- clearTimeout(timeoutId);
- timeoutId = setTimeout(() => func.apply(null, args), delay);
- };
- }
-
- return {
- highlightTableColumns,
- initTableHighlight,
- scrollToHighlightedColumn,
- wrapTableForResponsive,
- };
- }
|