Tippy.js v6.3.7动态更新内容不替换旧内容,如何重新初始化实例?
问题
在Tippy.js v6.3.7版本中,动态更新提示内容时旧内容不会被替换。想知道重新初始化tippy的最佳方式是什么?能否仅为尚未拥有tippy实例的元素初始化,或者定位特定tippy实例进行替换?
尝试在事件监听器中销毁实例,但destroy方法似乎不起作用,新的提示框会与旧的重叠。相关代码如下:
const instance = tippy(document.querySelector('#statement-task-' + taskId + ' .status-change')); console.log(instance); instance.destroy(); console.log(instance);
控制台输出显示destroy方法未生效,页面中出现两个重叠的提示框。
初始化代码如下,不确定是否存在问题:
document.addEventListener('DOMContentLoaded', function() { initializeTippy(); }); function initializeTippy() { tippy.setDefaultProps({ allowHTML: true, placement: 'top', arrow: true, interactive: true, dynamicTitle: true }); const template = document.getElementById('status-menu'); const container = document.createElement('div'); container.appendChild(document.importNode(template.content, true)); tippy('.status-change', { content: container.innerHTML, theme: 'light', hideOnClick: 'toggle', trigger: 'click', onShown(instance) { attachStatusChangeListeners(instance); tippy('[data-tippy-content]'); }, }); const userTemplate = document.getElementById('user-options'); const userMenuContainer = document.createElement('div'); userMenuContainer.appendChild(document.importNode(userTemplate.content, true)); tippy('.user-change', { content: userMenuContainer.innerHTML, theme: 'light', hideOnClick: 'toggle', trigger: 'click', onShown(instance) { attachUserChangeListeners(instance); tippy('[data-tippy-content]'); }, }); const optionsMenuTemplate = document.getElementById('task-options'); const optionsMenuContainer = document.createElement('div'); optionsMenuContainer.appendChild(document.importNode(optionsMenuTemplate.content, true)); tippy('[class*=options-change]:not(.no-options)', { content: optionsMenuContainer.innerHTML, theme: 'light', hideOnClick: 'toggle', trigger: 'click', maxWidth: 'none', onShown(instance) { attachOptionMenuListeners(instance); tippy('[data-tippy-content]'); }, }); tippy('[data-tippy-content]'); }
解决方案
1. 正确销毁/替换特定Tippy实例
你当前代码的问题在于,调用tippy(element)会新建一个实例,但原有的实例并没有被正确销毁——因为你可能重复初始化了同一个元素,导致多个实例共存。正确的做法是:
- 先通过
tippy.getInstances(element)获取元素上已有的所有实例,逐个销毁 - 或者直接用
tippy.destroyAll(element)批量销毁该元素的所有实例
示例代码:
const targetEl = document.querySelector('#statement-task-' + taskId + ' .status-change'); // 销毁该元素上所有已存在的tippy实例 tippy.destroyAll(targetEl); // 重新初始化 const newInstance = tippy(targetEl, { // 你的配置项,比如content: 新的内容 });
2. 仅为无实例的元素初始化
Tippy提供了ignoreExisting配置项,设为true时,只会为没有Tippy实例的元素初始化,避免重复创建:
tippy('.status-change', { ignoreExisting: true, // 其他配置 });
这样在重复调用初始化方法时,不会给已有实例的元素新建实例,自然不会出现重叠问题。
3. 动态更新内容无需重新初始化
如果只是要更新提示内容,不需要销毁再重建实例,可以直接调用实例的setContent方法,这是更高效的方式:
// 获取目标元素的实例(假设只有一个实例) const instance = tippy.getInstances(document.querySelector('.status-change'))[0]; if (instance) { instance.setContent('新的提示内容'); }
4. 优化你的初始化代码
你的初始化代码存在几个可以改进的点:
- 避免在
onShown回调中重复调用tippy('[data-tippy-content]'),这会导致每次弹窗显示时都重新初始化这些元素,容易产生重复实例 - 可以把模板复用逻辑封装成函数,减少重复代码
- 对于动态添加的元素,建议在元素插入DOM后再单独初始化,而不是全局重复调用初始化方法
优化后的初始化示例:
function getTemplateContent(templateId) { const template = document.getElementById(templateId); const container = document.createElement('div'); container.appendChild(document.importNode(template.content, true)); return container.innerHTML; } function initializeTippy() { tippy.setDefaultProps({ allowHTML: true, placement: 'top', arrow: true, interactive: true, dynamicTitle: true }); // 初始化状态菜单 tippy('.status-change', { content: getTemplateContent('status-menu'), theme: 'light', hideOnClick: 'toggle', trigger: 'click', ignoreExisting: true, // 防止重复初始化 onShown(instance) { attachStatusChangeListeners(instance); }, }); // 初始化用户菜单 tippy('.user-change', { content: getTemplateContent('user-options'), theme: 'light', hideOnClick: 'toggle', trigger: 'click', ignoreExisting: true, onShown(instance) { attachUserChangeListeners(instance); }, }); // 初始化选项菜单 tippy('[class*=options-change]:not(.no-options)', { content: getTemplateContent('task-options'), theme: 'light', hideOnClick: 'toggle', trigger: 'click', maxWidth: 'none', ignoreExisting: true, onShown(instance) { attachOptionMenuListeners(instance); }, }); // 初始化data-tippy-content元素,同样加ignoreExisting tippy('[data-tippy-content]', { ignoreExisting: true }); } document.addEventListener('DOMContentLoaded', initializeTippy);
内容的提问来源于stack exchange,提问作者hyphen
相关产品推荐
相关产品推荐

