JS 片段分享:限制数据库换行文本最大行数

效果是将开启了换行的列文本限制为显示前 3 行(这个数值可以改)→ 靠 CSS 实现

如果文本超出 3 行,鼠标悬浮在单元格上时可以在悬浮提示中看到完整的文本 → 靠 JS 实现

image.png

// 限制数据库换行文本最大行数(不包括主键换行) JS片段 - author: JeffreyChen

var animationFrameRequestId = null; // 用于存储 requestAnimationFrame 的 ID
function updateAriaLabels() { // 数据库渲染后所有 aria-label 属性都会丢失,所以直接全部添加即可
  // 如果已经有一个动画帧请求在等待,取消它
  if (animationFrameRequestId !== null) {
    cancelAnimationFrame(animationFrameRequestId);
  }
  animationFrameRequestId = requestAnimationFrame(function() {
    document.querySelectorAll('.av__row:not(.av__row--header) .av__cell[data-wrap="true"]:not([data-block-id])').forEach(cell => {
      const textElement = cell.querySelector('.av__celltext'); // 查找包含文本的子元素
      // 检查父元素是否已有 aria-label 属性、是否是有效的 DOM 元素、文本是否被截断
      if (!cell.getAttribute('aria-label') && textElement && textElement.scrollHeight > textElement.clientHeight) {
        const text = textElement.textContent.trim();  // 提取文本
        cell.setAttribute('aria-label', text); // 为单元格添加 aria-label 属性
      }
    });
    // 重置 animationFrameRequestId,以便下次调用 updateAriaLabels 时可以检查
    animationFrameRequestId = null;
  });
}
function updateAriaLabels2() { // 调整列(宽)后 aria-label 仍然保留,需要逐个判断移除或者添加
  // 如果已经有一个动画帧请求在等待,取消它
  if (animationFrameRequestId !== null) {
    cancelAnimationFrame(animationFrameRequestId);
  }
  animationFrameRequestId = requestAnimationFrame(function() {
    document.querySelectorAll('.av__row:not(.av__row--header) .av__cell[data-wrap="true"]:not([data-block-id])').forEach(cell => {
      const textElement = cell.querySelector('.av__celltext'); // 查找包含文本的子元素
      // 检查父元素是否已有 aria-label 属性、是否是有效的 DOM 元素、文本是否被截断
      if (cell.getAttribute('aria-label') && textElement && !(textElement.scrollHeight > textElement.clientHeight)) {
        cell.removeAttribute('aria-label'); // 为无截断文本的单元格移除 aria-label 属性
      } else if (!cell.getAttribute('aria-label') && textElement && textElement.scrollHeight > textElement.clientHeight) {
        const text = textElement.textContent.trim();  // 提取文本
        cell.setAttribute('aria-label', text); // 为有截断文本单元格添加 aria-label 属性
      }
    });
    // 重置 animationFrameRequestId,以便下次调用 updateAriaLabels 时可以检查
    animationFrameRequestId = null;
  });
}

var timeoutId = null;
// 创建一个新的 MutationObserver 实例,并提供一个回调函数
const observer = new MutationObserver((mutations) => {
  mutations.forEach((mutation) => {
    if (mutation.type === 'attributes') {
      // 数据库渲染:检查被修改的节点是否是数据库 av 类型并且已经渲染完成
      if (mutation.target.classList.contains('av') && mutation.target.getAttribute('data-render') === 'true') {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(function() {
          updateAriaLabels()
        }, 500); // 500 毫秒延时。用以避免短时间内重复执行
      // 调整列(宽):检查被修改的节点是否是数据库列头并且开启了换行
      } else if (mutation.target.classList.contains('av__cell--header') && mutation.target.getAttribute('data-wrap') === 'true') {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(function() {
          updateAriaLabels2()
        }, 500); // 500 毫秒延时。拖拽的过程中属性会高频变化,此时不继续运行
      }
    }
  });
});
// 配置MutationObserver以观察DOM树的变化
const config = { attributes: true, childList: false, subtree: true };
// 开始观察
observer.observe(document.body, config);

// 创建一个新的style元素
var style = document.createElement('style');
// 添加CSS代码
style.textContent = `
  .av__row:not(.av__row--header) .av__cell[data-wrap="true"]:not([data-block-id]) .av__celltext {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3; /* 最多3行 */
    overflow: hidden;
  }
`;
// 将style元素添加到文档的head中
document.head.appendChild(style);
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    20156 引用 • 77717 回帖
3 操作
JeffreyChen 在 2024-05-21 00:52:22 更新了该帖
JeffreyChen 在 2024-05-18 20:53:43 更新了该帖
JeffreyChen 在 2024-05-18 20:22:18 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • 纯 CSS:

      .av__row:not(.av__row--header) .av__cell[data-wrap="true"]:not([data-block-id]) .av__celltext {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 3; /* 最多3行 */
        overflow: hidden;
      }
    
  • 其他回帖
  • 我自己用的版本:

    // 限制数据库换行文本最大行数 JS片段 - author: JeffreyChen
    
    var animationFrameRequestId = null; // 用于存储 requestAnimationFrame 的 ID
    function updateAriaLabels() { // 数据库渲染后所有 aria-label 属性都会丢失,所以直接全部添加即可
      // 如果已经有一个动画帧请求在等待,取消它
      if (animationFrameRequestId !== null) {
        cancelAnimationFrame(animationFrameRequestId);
      }
      animationFrameRequestId = requestAnimationFrame(function() {
        document.querySelectorAll('.av__row:not(.av__row--header) .av__cell[data-wrap="true"]').forEach(cell => {
          const textElement = cell.querySelector('.av__celltext'); // 查找包含文本的子元素
          // 检查父元素是否已有 aria-label 属性、是否是有效的 DOM 元素、文本是否被截断
          if (!cell.getAttribute('aria-label') && textElement && textElement.scrollHeight > textElement.clientHeight) {
            const text = textElement.textContent.trim();  // 提取文本
            cell.setAttribute('aria-label', text); // 为单元格添加 aria-label 属性
          }
        });
        // 重置 animationFrameRequestId,以便下次调用 updateAriaLabels 时可以检查
        animationFrameRequestId = null;
      });
    }
    function updateAriaLabels2() { // 调整列(宽)后 aria-label 仍然保留,需要逐个判断移除或者添加;调整列(宽)后切换到镜像数据库时也需要逐个判断移除或者添加
      // 如果已经有一个动画帧请求在等待,取消它
      if (animationFrameRequestId !== null) {
        cancelAnimationFrame(animationFrameRequestId);
      }
      animationFrameRequestId = requestAnimationFrame(function() {
        document.querySelectorAll('.av__row:not(.av__row--header) .av__cell[data-wrap="true"]').forEach(cell => {
          const textElement = cell.querySelector('.av__celltext'); // 查找包含文本的子元素
          // 检查父元素是否已有 aria-label 属性、是否是有效的 DOM 元素、文本是否被截断
          if (cell.getAttribute('aria-label') && textElement && !(textElement.scrollHeight > textElement.clientHeight)) {
            cell.removeAttribute('aria-label'); // 为无截断文本的单元格移除 aria-label 属性
          } else if (!cell.getAttribute('aria-label') && textElement && textElement.scrollHeight > textElement.clientHeight) {
            const text = textElement.textContent.trim();  // 提取文本
            cell.setAttribute('aria-label', text); // 为有截断文本单元格添加 aria-label 属性
          }
        });
        // 重置 animationFrameRequestId,以便下次调用 updateAriaLabels 时可以检查
        animationFrameRequestId = null;
      });
    }
    
    var timeoutId = null;
    // 创建一个新的 MutationObserver 实例,并提供一个回调函数
    const observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.type === 'attributes') {
          // 数据库渲染:检查被修改的节点是否是数据库 av 类型并且已经渲染完成
          if (mutation.target.classList.contains('av') && mutation.target.getAttribute('data-render') === 'true') {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(function() {
              updateAriaLabels()
            }, 500); // 500 毫秒延时。用以避免短时间内重复执行
          // 调整列(宽):检查被修改的节点是否是数据库列头并且开启了换行;或者是否是切换页签
          } else if (mutation.target.classList.contains('av__cell--header') && mutation.target.getAttribute('data-wrap') === 'true' || mutation.target.classList.contains('item--focus')) {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(function() {
              updateAriaLabels2()
            }, 500); // 500 毫秒延时。拖拽的过程中属性会高频变化,此时不继续运行
          }
        }
      });
    });
    // 配置MutationObserver以观察DOM树的变化
    const config = { attributes: true, childList: false, subtree: true };
    // 开始观察
    observer.observe(document.body, config);
    
    // 创建一个新的style元素
    var style = document.createElement('style');
    // 添加CSS代码
    style.textContent = `
    /* 限制数据库换行文本最大行数 CSS片段 */
    .av__row:not(.av__row--header) .av__cell[data-wrap="true"] .av__celltext {
      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;
    }
    `;
    // 将style元素添加到文档的head中
    document.head.appendChild(style);
    
  • 如果能改思源本身的话,只需要增加 3 行 JS 代码,用代码片段的话就得用几十行,性能还差 😭

JeffreyChen
思源笔记同步教程:ld246.com/article/1692089679062

推荐标签 标签

  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    247 引用 • 1347 回帖 • 2 关注
  • 微信

    腾讯公司 2011 年 1 月 21 日推出的一款手机通讯软件。用户可以通过摇一摇、搜索号码、扫描二维码等添加好友和关注公众平台,同时可以将自己看到的精彩内容分享到微信朋友圈。

    130 引用 • 793 回帖
  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    262 引用 • 664 回帖
  • 智能合约

    智能合约(Smart contract)是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易,这些交易可追踪且不可逆转。智能合约概念于 1994 年由 Nick Szabo 首次提出。

    1 引用 • 11 回帖 • 7 关注
  • Mac

    Mac 是苹果公司自 1984 年起以“Macintosh”开始开发的个人消费型计算机,如:iMac、Mac mini、Macbook Air、Macbook Pro、Macbook、Mac Pro 等计算机。

    164 引用 • 594 回帖
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 606 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 609 关注
  • Sillot

    Insights(注意当前设置 master 为默认分支)

    汐洛彖夲肜矩阵(Sillot T☳Converbenk Matrix),致力于服务智慧新彖乄,具有彖乄驱动、极致优雅、开发者友好的特点。其中汐洛绞架(Sillot-Gibbet)基于自思源笔记(siyuan-note),前身是思源笔记汐洛版(更早是思源笔记汐洛分支),是智慧新录乄终端(多端融合,移动端优先)。

    主仓库地址:Hi-Windom/Sillot

    文档地址:sillot.db.sc.cn

    注意事项:

    1. ⚠️ 汐洛仍在早期开发阶段,尚不稳定
    2. ⚠️ 汐洛并非面向普通用户设计,使用前请了解风险
    3. ⚠️ 汐洛绞架基于思源笔记,开发者尽最大努力与思源笔记保持兼容,但无法实现 100% 兼容
    29 引用 • 25 回帖 • 53 关注
  • Logseq

    Logseq 是一个隐私优先、开源的知识库工具。

    Logseq is a joyful, open-source outliner that works on top of local plain-text Markdown and Org-mode files. Use it to write, organize and share your thoughts, keep your to-do list, and build your own digital garden.

    5 引用 • 62 回帖
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 430 关注
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖
  • 链滴

    链滴是一个记录生活的地方。

    记录生活,连接点滴

    143 引用 • 3752 回帖
  • 房星科技

    房星网,我们不和没有钱的程序员谈理想,我们要让程序员又有理想又有钱。我们有雄厚的房地产行业线下资源,遍布昆明全城的 100 家门店、四千地产经纪人是我们坚实的后盾。

    6 引用 • 141 回帖 • 566 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖 • 1 关注
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 61 关注
  • SSL

    SSL(Secure Sockets Layer 安全套接层),及其继任者传输层安全(Transport Layer Security,TLS)是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。

    69 引用 • 190 回帖 • 474 关注
  • 正则表达式

    正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列遵循某个句法规则的字符串。

    31 引用 • 94 回帖 • 1 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 403 关注
  • SMTP

    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。

    4 引用 • 18 回帖 • 609 关注
  • Mobi.css

    Mobi.css is a lightweight, flexible CSS framework that focus on mobile.

    1 引用 • 6 回帖 • 714 关注
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    14 引用 • 7 回帖 • 5 关注
  • RESTful

    一种软件架构设计风格而不是标准,提供了一组设计原则和约束条件,主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

    30 引用 • 114 回帖 • 2 关注
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    20156 引用 • 77717 回帖
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    75 引用 • 258 回帖 • 632 关注
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 441 关注
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    10 引用 • 88 回帖