From d5de65fdb1802cdf498d65d93397f290813c377c Mon Sep 17 00:00:00 2001 From: muqiuhan Date: Tue, 9 Sep 2025 06:17:00 +0000 Subject: deploy: 9665097f0fa0dae9f92123fac54d26c0818758a5 --- 2025/07/31/svelte-lazyquery/index.html | 35 ++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) (limited to '2025/07/31/svelte-lazyquery/index.html') diff --git a/2025/07/31/svelte-lazyquery/index.html b/2025/07/31/svelte-lazyquery/index.html index a90029c0..436b509b 100644 --- a/2025/07/31/svelte-lazyquery/index.html +++ b/2025/07/31/svelte-lazyquery/index.html @@ -195,41 +195,47 @@

在前端,一个常见的性能瓶颈是初始加载时请求了用户当前 viewpoint 之外的非必要数据。惰性加载(Lazy Loading)是一种关键策略,它将数据获取推迟到组件进入 viewpoint 时才执行。本文将阐述如何结合使用 Svelte 5、@tanstack/svelte-query 和 runed.dev 的 useIntersectionObserver,构建一个通用的、可复用的惰性加载组件。

核心依赖与环境

-

设计哲学:分离关注点

该方案的核心思想是将“何时加载”与“如何加载”这两个关注点进行解耦。

+

设计哲学:分离关注点

+

该方案的核心思想是将“何时加载”与“如何加载”这两个关注点进行解耦。

    -
  1. 何时加载 (When to Load): 组件的可见性决定了数据加载的时机。我们利用 Intersection Observer API 来精确、高效地监听一个元素是否进入 viewpoint。runed.dev 库为此提供了名为 useIntersectionObserver 的便捷封装。

    +
  2. +

    何时加载 (When to Load): 组件的可见性决定了数据加载的时机。我们利用 Intersection Observer API 来精确、高效地监听一个元素是否进入 viewpoint。runed.dev 库为此提供了名为 useIntersectionObserver 的便捷封装。

  3. -
  4. 如何加载 (How to Load): 数据获取、缓存、同步和状态管理的复杂性由 @tanstack/svelte-query (TanStack Query) 处理。它提供了一套强大的工具集来管理异步数据。

    +
  5. +

    如何加载 (How to Load): 数据获取、缓存、同步和状态管理的复杂性由 @tanstack/svelte-query (TanStack Query) 处理。它提供了一套强大的工具集来管理异步数据。

通过将这两者结合,可以创建一个名为 LazyQuery 的抽象组件。该组件内部处理可见性检测,并根据检测结果动态控制 TanStack Query 的执行,而将具体的查询逻辑(queryFn)和键(queryKey)完全交由使用者定义。

-

LazyQuery 组件的实现

+

LazyQuery 组件的实现

+

目标:封装惰性加载逻辑,并向外暴露一个标准的 TanStack Query 接口。

一、对组件的接口类型做如下定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import type { CreateQueryOptions, QueryKey } from '@tanstack/svelte-query';
import type { Snippet } from 'svelte';

type Props<
TQueryFnData = unknown,
TError = Error,
TData = TQueryFnData,
TQueryKey extends QueryKey = QueryKey
> = {
/// 一个标准的 TanStack Query 配置对象
queryOptions: CreateQueryOptions<TQueryFnData, TError, TData, TQueryKey>;

/// Svelte 5 的 `Snippet` 类型,它允许父组件向子组件传递一段可执行的 UI 模板。
/// 这个 `Snippet` 会接收到 `createQuery` 返回的完整查询对象 `query`,
/// 从而可以访问 `data`, `isLoading`, `error` 等所有状态。
children: Snippet<{
query: ReturnType<typeof createQuery<TQueryFnData, TError, TData, TQueryKey>>;
}>;
};
-

二、组件逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<script lang="ts">
import { createQuery, type CreateQueryOptions, type QueryKey } from '@tanstack/svelte-query';
import { useIntersectionObserver } from 'runed';
import type { Snippet } from 'svelte';

// [上述的类型定义]

let { queryOptions, children }: Props = $props();

let el: Element;
const { isIntersecting } = useIntersectionObserver(
() => el,
{
rootMargin: '200px',
}
);

const query = createQuery({
...queryOptions,
get enabled() {
return ($state.is(isIntersecting) && (queryOptions.enabled ?? true));
}
});
</script>

<div bind:this={el}>
{#snippet children({ query })}
{/snippet}
</div>
-