返回

解决服务器端渲染表格Tippy工具提示失效问题

php

服务器端渲染表格中 Tippy 工具提示失效

在开发过程中,使用数据表格展示信息时常有在特定列添加工具提示的需求。Tippy 是一个常用的 JavaScript 工具提示库,它提供便捷的工具提示功能。在利用 DataTables 这类库实现服务器端渲染表格时,Tippy 的工具提示功能有时会失效。这里会探究失效原因以及给出解决办法。

问题分析

问题产生的主要原因是,DataTables 的服务器端渲染是在初始加载时获取表格数据,后续分页、排序或搜索等操作会通过 AJAX 异步请求获取数据并动态更新表格。Tippy 的初始化 tippy('[data-tippy-content]') 发生在表格渲染之前或者表格加载之后但还没有完成数据渲染的时候 ,这时带有 data-tippy-content 属性的元素还不存在或尚未完成添加到 DOM 中,Tippy 并未识别这些动态添加的元素,自然就无法激活工具提示。

解决方案

以下提供了两种解决此类问题的方法,帮助你让 Tippy 工具提示在动态渲染的数据表格中正常工作。

方法一:延迟初始化

此方案的基本思路是延迟 Tippy 的初始化,确保在 DataTables 完成数据渲染后执行 tippy 函数。DataTables 提供了 drawCallback 方法,可以在表格每次重绘完成后执行。

  1. 在 DataTables 初始化配置中,加入 drawCallback

     new DataTable('#example', {
            ajax: "{{ route('retrieveposts') }}",
            processing: true,
            serverSide: true,
             drawCallback: function () {
              tippy('[data-tippy-content]');
            },
            columns: [{
                    data: 'id',
                    name: 'id'
                },
                {
                    data: 'title',
                    name: 'title',
                    render: function(data, type, row) {
                        return `
                            <strong id="title_${row.id}" class="title"> ${data} </strong>                    
                        `;
                    }
                },
                {
                    data: 'body',
                    name: 'body',
                    render: function(data, type, row) {
                        return `
                        <div data-tippy-content="Tooltip">
                            <span id="value_description_${row.id}"> ${data}</span>
                         </div>
                         `;
                    }
                },
                {
                    data: 'is_publish',
                    name: 'is_publish',
                    render: function(data, type, row) {
                        return `
                        <span> ${data} </span>                         
                        `;
                    }
                },
            ]
        });
    

这会将 tippy 函数的调用放置到每一次表格数据重新渲染后,确保所有带有data-tippy-content 属性的元素都加载完成,从而让 Tippy 正确地初始化这些元素。

  1. 删除页面尾部,原有tippy函数初始化方法

      tippy('[data-tippy-content]') //remove it
    

方法二:手动实例

如果你不希望每次重绘表格都重新初始化Tippy实例,也可以采用手动创建Tippy实例的方式,它能精细地控制每一个工具提示元素的生成与销毁。

  1. 放弃使用 tippy('[data-tippy-content]') 这种初始化方式,并在服务器端渲染的数据中使用特定的选择器,例如为包裹着文本的 <span> 元素添加 tippy-target 类名,并且使用不同的内容作为工具提示文本,将原有的工具提示属性data-tippy-content="Tooltip"更改为 title=“Tooltip Content Here":
 render: function(data, type, row) {
          return `
         <div>
               <span  title="Tooltip Content Here" class="tippy-target" id="value_description_${row.id}"> ${data}</span>
          </div>
          `;
   }
  1. 在表格的drawCallback函数里,遍历符合选择器的元素,生成Tippy实例并存储。每次重绘前先销毁旧的实例,再生成新的。

    let tippyInstances = [];
    
       new DataTable('#example', {
                 ajax: "{{ route('retrieveposts') }}",
                 processing: true,
                 serverSide: true,
                  drawCallback: function () {
                       tippyInstances.forEach(instance => instance.destroy());
                         tippyInstances = [];
    
                      document.querySelectorAll('.tippy-target').forEach(el => {
                        const instance = tippy(el, {
                        content: el.getAttribute('title'),
                         });
                         tippyInstances.push(instance);
                     })
                   },
                columns: [ /* your code here */ ]
          });
    

这个方法在每次重新渲染后都会清除原有的 tippy 实例,并生成新的,确保工具提示的及时更新和资源清理。

安全建议

无论使用哪种方法,都有必要注意以下安全事项:

  • 内容过滤: 对于工具提示的内容,特别是由服务器返回的用户生成的内容,要进行严格的 HTML 转义处理。防止可能的 XSS 攻击,始终将数据视作不可信。
  • 防止选择器冲突: 你选择的选择器必须尽可能明确,确保不会无意中选中页面中其他非预期的元素,可以适当的使用前缀,降低命名冲突的可能性。

结语

工具提示增强了用户交互体验,但是,在处理动态内容时需要细心考虑初始化的时机和范围。这两种方法均有效处理 DataTables 和 Tippy 整合问题。通过了解背后原理并谨慎实施,你可以让工具提示在服务器端渲染的数据表格中正常运作。