效果是将开启了换行的字段文本限制为仅显示前 3 行(这个数值可以改),如果文本超出 3 行,鼠标悬浮在单元格上时可以在悬浮提示中看到完整的文本
// 限制数据库换行文本最大行数 JS片段 - author: JeffreyChen
(function() {
var animationFrameRequestId = null; // 用于存储 requestAnimationFrame 的 ID
const rowsSelector = '.av__row:not(.av__row--header) ';
// 获取当前单元格的函数
function getCurrentCells() {
return Array.from(document.querySelectorAll(rowsSelector + '.av__cell[data-wrap="true"]'));
}
// 计算单元格内所有文本元素的总高度的函数
function calculateTotalHeight(cell) {
const textElements = Array.from(cell.querySelectorAll('.av__celltext'));
const tempSpan = document.createElement('span');
tempSpan.style.visibility = 'hidden';
tempSpan.style.display = 'block';
// 根据 data-dtype 属性设置 whiteSpace 样式
if (cell.dataset.dtype === 'relation' || cell.dataset.dtype === 'rollup') {
tempSpan.style.whiteSpace = 'normal'; // 对于 relation 和 rollup
} else {
tempSpan.style.whiteSpace = 'pre-wrap'; // 其他情况使用 pre-wrap
}
cell.appendChild(tempSpan); // 将其附加到单元格以便准确测量
// 将所有文本内容与分隔符 ", " 组合
const combinedText = textElements.map(textElement => textElement.textContent.trim()).join(', ');
tempSpan.textContent = combinedText; // 设置组合文本以进行高度计算
const totalHeight = tempSpan.scrollHeight; // 获取总高度
// 清理临时 span
cell.removeChild(tempSpan);
return totalHeight;
}
function updateAriaLabels(cells) {
if (animationFrameRequestId !== null) {
cancelAnimationFrame(animationFrameRequestId);
}
animationFrameRequestId = requestAnimationFrame(function() {
cells.forEach(cell => {
const currentLabel = cell.getAttribute('aria-label');
const totalHeight = calculateTotalHeight(cell);
const isTruncated = totalHeight > cell.clientHeight;
// 将所有文本组合成一个字符串以用于 aria-label
const textElements = cell.querySelectorAll('.av__celltext');
let combinedText;
// 特殊处理 .av__cell[data-dtype="relation"] 和 .av__cell[data-dtype="rollup"] 元素
if (cell.dataset.dtype === 'relation' || cell.dataset.dtype === 'rollup') {
combinedText = Array.from(textElements).map(textElement => {
// 获取文本并替换换行符
const cleanedText = textElement.textContent.replace(/\n+/g, ' ').trim();
return cleanedText;
}).join(',\n');
} else {
combinedText = Array.from(textElements).map(textElement => textElement.textContent.trim()).join(', ');
}
// 根据组合文本长度更新 aria-label
if (isTruncated && !currentLabel) {
cell.setAttribute('aria-label', combinedText);
} else if (!isTruncated && currentLabel) {
cell.removeAttribute('aria-label');
}
});
animationFrameRequestId = null;
});
}
function deferredUpdateAriaLabels() {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
const cells = getCurrentCells();
updateAriaLabels(cells);
}, 500); // 500 毫秒延时。
}
// 判断脚本是否开启 https://ld246.com/article/1726930314271
// 通过唯一标志符判断是否启用此脚本,注释中的uuid不要删除,也可以改成其他全局唯一字符串
// 也可以通过/api/snippet/getSnippet来判断脚本开启状态,这里采用判断脚本是否存在的方式
// 调用方式 isEnabled()
let scriptId = '';
function isEnabled(keyword = '限制数据库换行文本最大行数-b6fb408a-d400-4874-b357-06fcdce67ca6') {
if(!siyuan.config.snippet.enabledJS) return false;
const script = scriptId ? document.getElementById(scriptId) : null;
if(script) return true;
const scripts = document.head.querySelectorAll("script[id^=snippetJS]");
for (var i = 0; i < scripts.length; i++) {
// 限制数据库换行文本最大行数-b6fb408a-d400-4874-b357-06fcdce67ca6
if (scripts[i].textContent.indexOf('// ' + keyword) !== -1) {
scriptId = scripts[i].id;
return true;
}
}
return false;
}
var timeoutId = null;
// 定期检查 .layout__center 是否存在于 DOM 中
function checkForLayoutCenter() {
const targetNode = document.querySelector('.layout__center');
if (targetNode) {
startObserving(targetNode);
} else {
// 如果未找到,则每 200 毫秒重试
setTimeout(checkForLayoutCenter, 200);
}
}
function startObserving(targetNode) {
// 创建一个新的 MutationObserver 实例,观察 .layout__center 元素
const observer = new MutationObserver((mutations) => {
if(!isEnabled()) { // 判断脚本是否开启
if(observer) observer.disconnect();
if(timeoutId) clearTimeout(timeoutId);
if(animationFrameRequestId) cancelAnimationFrame(animationFrameRequestId);
return;
}
for (let mutation of mutations) {
if (mutation.type === 'attributes') {
const target = mutation.target;
// 数据库渲染检查
if (target.classList.contains('av') && target.getAttribute('data-render') === 'true') {
deferredUpdateAriaLabels();
// 列头调整或切换页签检查
} else if (target.classList.contains('av__cell--header') && target.getAttribute('data-wrap') === 'true' || target.classList.contains('item--focus')) {
deferredUpdateAriaLabels();
}
}
}
});
// 配置并开始观察
const config = { attributes: true, childList: false, subtree: true };
observer.observe(targetNode, config);
// 脚本启用后立即对当前 DOM 进行一次操作
const cells = getCurrentCells();
updateAriaLabels(cells);
}
checkForLayoutCenter(); // 开始检查 .layout__center 是否存在
// 创建并添加 CSS 代码
const style = document.createElement('style');
style.textContent = `
/* 限制数据库换行文本最大行数 CSS片段 */
.av__row:not(.av__row--header) .av__cell[data-wrap="true"]:not([data-dtype="relation"]):not([data-dtype="rollup"]):not([data-dtype="mAsset"]) {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* 最多3行 */
overflow: hidden;
}
.av__celltext--ref {
border-bottom: 0px;
text-decoration: underline; /* 下划线 */
text-decoration-color: rgb(0 202 255 / 85%); /* 浅蓝色 */
text-decoration-thickness: 2px;
}
/* 针对关联字段、汇总字段 */
.av__row:not(.av__row--header) .av__cell[data-wrap="true"][data-dtype="relation"],
.av__row:not(.av__row--header) .av__cell[data-wrap="true"][data-dtype="rollup"] {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* 最多3行 */
overflow: hidden;
white-space: normal;
}
/* 资源字段变为滚动容器 */
.av__row:not(.av__row--header) .av__cell[data-wrap="true"][data-dtype="mAsset"] {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* 最多3行 */
text-overflow: clip; /* 用于去掉多余的 "..." ,但不起效,要等 CSS4 再看有没有合适的 CSS 属性*/
overflow: auto;
overflow-x: hidden;
}
`;
document.head.appendChild(style);
})();
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于