切换页面时 Svelte 组件出错
Error in Svelte component when switching pages
我有一个使用 Svelte + Laravel + Inertia 的项目,我正在处理一个具有记录分页功能的页面。
但是当我更改页码时,控制台中会显示错误并且应用程序停止工作。
app.js:108643
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'removeChild')
at detach (app.js:108643:19)
at Object.d (app.js:83321:77)
at Object.d (app.js:83428:16)
at destroy_component (app.js:110453:32)
at Object.d (app.js:81565:73)
at Object.d (app.js:80366:38)
at destroy_component (app.js:110453:32)
at Object.d (app.js:81393:73)
at Object.d (app.js:81640:43)
at destroy_component (app.js:110453:32)
经过一些测试,我发现了问题:
在我的组件中,我有 Inertia Link 组件,它导致了错误,因为如果我将组件更改为简单标记,错误就会停止。
组件代码
<script>
import { onMount } from "svelte";
import { Link } from "@inertiajs/inertia-svelte";
import { icon as make } from "@fortawesome/fontawesome-svg-core";
export let icon, title, click, attributes, href;
const svg_uid = Math.random().toString(16).substring(2);
onMount( () => {
const svg = make(icon).node[0];
document.querySelector(`svg[data-fa-svg="${svg_uid}"]`).replaceWith(svg);
const button = svg.parentElement;
for (const attribute in attributes) {
button.setAttribute(attribute, attributes[attribute])
}
})
</script>
<!--
---------------------------------------
HTML Template
---------------------------------------
-->
{#if click}
<button type="button" {title} class="svg-button-component" on:click={click}>
<svg data-fa-svg="{svg_uid}"></svg>
</button>
{:else if href}
<Link {href} {title}>
<svg data-fa-svg="{svg_uid}"></svg>
</Link>
{:else}
<svg data-fa-svg="{svg_uid}"></svg>
{/if}
工作代码(感谢@dummdidumm)
<script>
import { onMount } from "svelte";
import { icon as make } from "@fortawesome/fontawesome-svg-core";
import { Link } from "@inertiajs/inertia-svelte";
export let icon, button, href;
const uid = Math.random().toString(16).substring(2);
onMount( () => {
if (href) {
document.querySelector(`a[data-fa-svg="${uid}"]`)
.appendChild(
make(icon).node[0]
)
} else {
document.querySelector(`svg[data-fa-svg="${uid}"]`)
.replaceWith(
make(icon).node[0]
)
}
})
</script>
<!--
---------------------------------------
HTML Template
---------------------------------------
-->
{#if button}
<button type="button" {...$$restProps} class="svg-button-component" on:click>
<svg data-fa-svg="{uid}"></svg>
</button>
{:else if href}
<Link {href} {...$$restProps} data-fa-svg={uid}></Link>
{:else}
<svg data-fa-svg="{uid}" {...$$restProps}></svg>
{/if}
问题不在于 Link
组件,而是代码强制性地将 svg
元素替换为不同的元素。 Svelte 不知道这一点,并保留对作为 Link
子元素的旧(现已删除)svg
元素的引用。当组件被销毁时,它会尝试删除那个不存在的元素,因此会抛出错误。要么你调整你的代码而不是强制修改代码,要么你在你替换的元素周围添加一个包装元素,比如
<Link>
<span>
<svg ...>
</span>
</Link>
我有一个使用 Svelte + Laravel + Inertia 的项目,我正在处理一个具有记录分页功能的页面。 但是当我更改页码时,控制台中会显示错误并且应用程序停止工作。
app.js:108643
Uncaught (in promise) TypeError: Cannot read properties of null (reading 'removeChild')
at detach (app.js:108643:19)
at Object.d (app.js:83321:77)
at Object.d (app.js:83428:16)
at destroy_component (app.js:110453:32)
at Object.d (app.js:81565:73)
at Object.d (app.js:80366:38)
at destroy_component (app.js:110453:32)
at Object.d (app.js:81393:73)
at Object.d (app.js:81640:43)
at destroy_component (app.js:110453:32)
经过一些测试,我发现了问题: 在我的组件中,我有 Inertia Link 组件,它导致了错误,因为如果我将组件更改为简单标记,错误就会停止。
组件代码
<script>
import { onMount } from "svelte";
import { Link } from "@inertiajs/inertia-svelte";
import { icon as make } from "@fortawesome/fontawesome-svg-core";
export let icon, title, click, attributes, href;
const svg_uid = Math.random().toString(16).substring(2);
onMount( () => {
const svg = make(icon).node[0];
document.querySelector(`svg[data-fa-svg="${svg_uid}"]`).replaceWith(svg);
const button = svg.parentElement;
for (const attribute in attributes) {
button.setAttribute(attribute, attributes[attribute])
}
})
</script>
<!--
---------------------------------------
HTML Template
---------------------------------------
-->
{#if click}
<button type="button" {title} class="svg-button-component" on:click={click}>
<svg data-fa-svg="{svg_uid}"></svg>
</button>
{:else if href}
<Link {href} {title}>
<svg data-fa-svg="{svg_uid}"></svg>
</Link>
{:else}
<svg data-fa-svg="{svg_uid}"></svg>
{/if}
工作代码(感谢@dummdidumm)
<script>
import { onMount } from "svelte";
import { icon as make } from "@fortawesome/fontawesome-svg-core";
import { Link } from "@inertiajs/inertia-svelte";
export let icon, button, href;
const uid = Math.random().toString(16).substring(2);
onMount( () => {
if (href) {
document.querySelector(`a[data-fa-svg="${uid}"]`)
.appendChild(
make(icon).node[0]
)
} else {
document.querySelector(`svg[data-fa-svg="${uid}"]`)
.replaceWith(
make(icon).node[0]
)
}
})
</script>
<!--
---------------------------------------
HTML Template
---------------------------------------
-->
{#if button}
<button type="button" {...$$restProps} class="svg-button-component" on:click>
<svg data-fa-svg="{uid}"></svg>
</button>
{:else if href}
<Link {href} {...$$restProps} data-fa-svg={uid}></Link>
{:else}
<svg data-fa-svg="{uid}" {...$$restProps}></svg>
{/if}
问题不在于 Link
组件,而是代码强制性地将 svg
元素替换为不同的元素。 Svelte 不知道这一点,并保留对作为 Link
子元素的旧(现已删除)svg
元素的引用。当组件被销毁时,它会尝试删除那个不存在的元素,因此会抛出错误。要么你调整你的代码而不是强制修改代码,要么你在你替换的元素周围添加一个包装元素,比如
<Link>
<span>
<svg ...>
</span>
</Link>