使用Svelte客户端组件API创建组件时如何获取其DOM元素引用
Svelte use:action中获取手动实例化组件DOM的方案
问题场景
在use:action函数内手动实例化Svelte组件时,没有找到类似bind:this的直接API获取组件渲染出的DOM元素,不想通过生成唯一类名/ID再调用querySelector的方式绕路获取。
问题复现代码
import ToolTip from '$lib/components/tooltips/Plain.svelte'; export default function (node: HTMLElement) { const title = node.getAttribute('title'); let tooltipComponent = new ToolTip({ props: { title, }, target: node, }); const tooltip = undefined; // 需要在此处获取Tooltip组件对应的根DOM let arrow = tooltip.querySelector('#tooltip-arrow'); let update = () => { compute(node, tooltip, arrow); }; node.addEventListener('mouseenter', update); node.addEventListener('focus', update); return { update() {}, destroy() { node.removeEventListener('mouseenter', update); node.removeEventListener('focus', update); tooltipComponent.$destroy(); }, } }
临时绕路方案
通过生成唯一ID给组件传入专属类名,再从父节点下查询对应元素:
const uniqueId = generateUniqueId(); let tooltipComponent = new ToolTip({ props: { title, class: `tooltip-${uniqueId}`, }, target: node, }); const tooltip = node.querySelector(`.tooltip-${uniqueId}`);
推荐实现方式
两种方案都不需要生成冗余的唯一标识,稳定性远高于选择器查询:
方案1:组件抛事件拿引用(最稳定,和
bind:this逻辑完全一致)
直接在Tooltip组件内部通过bind:this绑定根DOM,挂载完成后通过自定义事件把元素抛出来,外部实例化组件时监听事件即可拿到准确的DOM引用。
先修改Tooltip组件代码:<!-- $lib/components/tooltips/Plain.svelte --> <script> import { onMount, createEventDispatcher } from 'svelte'; const dispatch = createEventDispatcher(); let rootNode; onMount(() => { // 挂载完成后把根DOM抛出去 dispatch('domready', rootNode); }) </script> <!-- 绑定根节点 --> <div bind:this={rootNode} class="tooltip-wrap"> <!-- 组件原有内容 --> <div id="tooltip-arrow"></div> </div>再修改action里的实例化逻辑:
let tooltip: HTMLElement; let arrow: HTMLElement; const tooltipComponent = new ToolTip({ props: { title }, target: node, }); // 监听组件抛出的DOM就绪事件 tooltipComponent.$on('domready', (e) => { tooltip = e.detail; arrow = tooltip.querySelector('#tooltip-arrow'); // 所有依赖tooltip DOM的逻辑都可以在此处完成初始化 })如果组件是多根节点(Fragment)结构,没有单一外层元素,只能用这个方案获取需要的DOM节点。
方案2:通过DOM插入位置直接获取(无需修改组件源码)
Svelte实例化组件传入target时,默认会把组件内容作为target的最后一个子节点插入,直接取父节点的最后一个子元素即可,不需要查询选择器:const tooltipComponent = new ToolTip({ props: { title }, target: node, }); // 直接取target下最后一个元素,就是刚挂载的组件根节点 const tooltip = node.lastElementChild as HTMLElement; const arrow = tooltip.querySelector('#tooltip-arrow');如果实例化时传了
anchor参数指定插入位置,对应取anchor.previousElementSibling就是组件根节点。注意这个方案要确保实例化组件时,target节点下没有其他异步插入的元素,避免拿错节点。
内容的提问来源于stack exchange,提问作者Nick
相关产品推荐
相关产品推荐

