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 更新了该帖

相关帖子

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...
  • 我自己用的版本:

    // 限制数据库换行文本最大行数 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);
    
  • 其他回帖
  • 纯 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;
      }
    
  • 如果能改思源本身的话,只需要增加 3 行 JS 代码,用代码片段的话就得用几十行,性能还差 😭

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

推荐标签 标签

  • danl
    92 关注
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 22 关注
  • 友情链接

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

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

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 196 关注
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    54 引用 • 85 回帖
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    165 引用 • 407 回帖 • 509 关注
  • 反馈

    Communication channel for makers and users.

    124 引用 • 907 回帖 • 223 关注
  • 微信

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

    130 引用 • 793 回帖
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖
  • Gitea

    Gitea 是一个开源社区驱动的轻量级代码托管解决方案,后端采用 Go 编写,采用 MIT 许可证。

    4 引用 • 16 回帖 • 1 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    207 引用 • 2031 回帖
  • 京东

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

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

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    21 引用 • 140 回帖 • 12 关注
  • 工具

    子曰:“工欲善其事,必先利其器。”

    281 引用 • 716 回帖
  • Vditor

    Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。它使用 TypeScript 实现,支持原生 JavaScript、Vue、React 和 Angular。

    328 引用 • 1715 回帖 • 4 关注
  • 快应用

    快应用 是基于手机硬件平台的新型应用形态;标准是由主流手机厂商组成的快应用联盟联合制定;快应用标准的诞生将在研发接口、能力接入、开发者服务等层面建设标准平台;以平台化的生态模式对个人开发者和企业开发者全品类开放。

    15 引用 • 127 回帖 • 1 关注
  • CentOS

    CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux 依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。两者的不同在于 CentOS 并不包含封闭源代码软件。

    238 引用 • 224 回帖
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用
  • 安全

    安全永远都不是一个小问题。

    191 引用 • 813 回帖 • 1 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 363 关注
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    165 引用 • 1474 回帖
  • Facebook

    Facebook 是一个联系朋友的社交工具。大家可以通过它和朋友、同事、同学以及周围的人保持互动交流,分享无限上传的图片,发布链接和视频,更可以增进对朋友的了解。

    4 引用 • 15 回帖 • 458 关注
  • Flutter

    Flutter 是谷歌的移动 UI 框架,可以快速在 iOS 和 Android 上构建高质量的原生用户界面。 Flutter 可以与现有的代码一起工作,它正在被越来越多的开发者和组织使用,并且 Flutter 是完全免费、开源的。

    39 引用 • 92 回帖
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    41 引用 • 40 回帖
  • 音乐

    你听到信仰的声音了么?

    60 引用 • 510 回帖 • 1 关注
  • GitBook

    GitBook 使您的团队可以轻松编写和维护高质量的文档。 分享知识,提高团队的工作效率,让用户满意。

    3 引用 • 8 回帖 • 1 关注