svelte/reactivity
Svelte 提供了各种内置函数(例如 Map
、Set
和 URL
)的响应式版本,这些版本可以像原生版本一样使用,此外还提供了一些用于处理响应式的附加实用程序。
¥Svelte provides reactive versions of various built-ins like Map
, Set
and URL
that can be used just like their native counterparts, as well as a handful of additional utilities for handling reactivity.
import {
class MediaQuery
Creates a media query and provides a current
property that reflects whether or not it matches.
Use it carefully — during server-side rendering, there is no way to know what the correct value should be, potentially causing content to change upon hydration.
If you can use the media query in CSS to achieve the same effect, do that.
<script>
import { MediaQuery } from 'svelte/reactivity';
const large = new MediaQuery('min-width: 800px');
</script>
<h1>{large.current ? 'large screen' : 'small screen'}</h1>
MediaQuery,
class SvelteDate
SvelteDate,
class SvelteMap<K, V>
SvelteMap,
class SvelteSet<T>
SvelteSet,
class SvelteURL
SvelteURL,
class SvelteURLSearchParams
SvelteURLSearchParams,
function createSubscriber(start: (update: () => void) => (() => void) | void): () => void
Returns a subscribe
function that, if called in an effect (including expressions in the template),
calls its start
callback with an update
function. Whenever update
is called, the effect re-runs.
If start
returns a function, it will be called when the effect is destroyed.
If subscribe
is called in multiple effects, start
will only be called once as long as the effects
are active, and the returned teardown function will only be called when all effects are destroyed.
It’s best understood with an example. Here’s an implementation of MediaQuery
:
import { createSubscriber } from 'svelte/reactivity';
import { on } from 'svelte/events';
export class MediaQuery {
#query;
#subscribe;
constructor(query) {
this.#query = window.matchMedia(`(${query})`);
this.#subscribe = createSubscriber((update) => {
// when the `change` event occurs, re-run any effects that read `this.current`
const off = on(this.#query, 'change', update);
// stop listening when all the effects are destroyed
return () => off();
});
}
get current() {
this.#subscribe();
// Return the current state of the query, whether or not we're in an effect
return this.#query.matches;
}
}
createSubscriber
} from 'svelte/reactivity';
MediaQuery
自 5.7.0 起可用
¥Available since 5.7.0
创建媒体查询并提供反映其是否匹配的 current
属性。
¥Creates a media query and provides a current
property that reflects whether or not it matches.
请谨慎使用 - 在服务器端渲染期间,无法知道正确的值应该是什么,可能会导致内容在水合时发生变化。如果你可以在 CSS 中使用媒体查询来实现相同的效果,请这样做。
¥Use it carefully — during server-side rendering, there is no way to know what the correct value should be, potentially causing content to change upon hydration. If you can use the media query in CSS to achieve the same effect, do that.
<script>
import { MediaQuery } from 'svelte/reactivity';
const large = new MediaQuery('min-width: 800px');
</script>
<h1>{large.current ? 'large screen' : 'small screen'}</h1>
class MediaQuery extends ReactiveValue<boolean> {…}
constructor(query: string, fallback?: boolean | undefined);
query
媒体查询字符串¥
query
A media query stringfallback
服务器的后备值¥
fallback
Fallback value for the server
SvelteDate
内置 Date
对象的响应式版本。在 effect 或 derived 中读取日期(无论是使用 date.getTime()
或 date.toString()
之类的方法,还是通过 Intl.DateTimeFormat
之类的方法)会导致日期值发生变化时重新评估。
¥A reactive version of the built-in Date
object.
Reading the date (whether with methods like date.getTime()
or date.toString()
, or via things like Intl.DateTimeFormat
)
in an effect or derived
will cause it to be re-evaluated when the value of the date changes.
<script>
import { SvelteDate } from 'svelte/reactivity';
const date = new SvelteDate();
const formatter = new Intl.DateTimeFormat(undefined, {
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
$effect(() => {
const interval = setInterval(() => {
date.setTime(Date.now());
}, 1000);
return () => {
clearInterval(interval);
};
});
</script>
<p>The time is {formatter.format(date)}</p>
class SvelteDate extends Date {…}
constructor(...params: any[]);
SvelteMap
内置 Map
对象的响应式版本。在 effect 或 derived 中读取映射的内容(通过迭代,或者通过读取 map.size
或调用 map.get(...)
或 map.has(...)
,如下面的 井字游戏示例 所示)将导致映射在更新时根据需要重新评估。
¥A reactive version of the built-in Map
object.
Reading contents of the map (by iterating, or by reading map.size
or calling map.get(...)
or map.has(...)
as in the tic-tac-toe example below) in an effect or derived
will cause it to be re-evaluated as necessary when the map is updated.
请注意,响应式映射中的值不会被设为 深度响应。
¥Note that values in a reactive map are not made deeply reactive.
<script>
import { SvelteMap } from 'svelte/reactivity';
import { result } from './game.js';
let board = new SvelteMap();
let player = $state('x');
let winner = $derived(result(board));
function reset() {
player = 'x';
board.clear();
}
</script>
<div class="board">
{#each Array(9), i}
<button
disabled={board.has(i) || winner}
onclick={() => {
board.set(i, player);
player = player === 'x' ? 'o' : 'x';
}}
>{board.get(i)}</button>
{/each}
</div>
{#if winner}
<p>{winner} wins!</p>
<button onclick={reset}>reset</button>
{:else}
<p>{player} is next</p>
{/if}
class SvelteMap<K, V> extends Map<K, V> {…}
constructor(value?: Iterable<readonly [K, V]> | null | undefined);
set(key: K, value: V): this;
SvelteSet
内置 Set
对象的响应式版本。在 effect 或 derived 中读取集合的内容(通过迭代,或者通过读取 set.size
或调用 set.has(...)
,如下面的 example 所示)将导致集合在更新时根据需要重新评估。
¥A reactive version of the built-in Set
object.
Reading contents of the set (by iterating, or by reading set.size
or calling set.has(...)
as in the example below) in an effect or derived
will cause it to be re-evaluated as necessary when the set is updated.
请注意,响应式集合中的值不会被设为 深度响应。
¥Note that values in a reactive set are not made deeply reactive.
<script>
import { SvelteSet } from 'svelte/reactivity';
let monkeys = new SvelteSet();
function toggle(monkey) {
if (monkeys.has(monkey)) {
monkeys.delete(monkey);
} else {
monkeys.add(monkey);
}
}
</script>
{#each ['🙈', '🙉', '🙊'] as monkey}
<button onclick={() => toggle(monkey)}>{monkey}</button>
{/each}
<button onclick={() => monkeys.clear()}>clear</button>
{#if monkeys.has('🙈')}<p>see no evil</p>{/if}
{#if monkeys.has('🙉')}<p>hear no evil</p>{/if}
{#if monkeys.has('🙊')}<p>speak no evil</p>{/if}
class SvelteSet<T> extends Set<T> {…}
constructor(value?: Iterable<T> | null | undefined);
add(value: T): this;
SvelteURL
内置 URL
对象的响应式版本。在 effect 或 derived 中读取 URL 的属性(例如 url.href
或 url.pathname
)会导致 URL 发生变化时根据需要重新评估。
¥A reactive version of the built-in URL
object.
Reading properties of the URL (such as url.href
or url.pathname
) in an effect or derived
will cause it to be re-evaluated as necessary when the URL changes.
searchParams
属性是 SvelteURLSearchParams 的一个实例。
¥The searchParams
property is an instance of SvelteURLSearchParams.
示例:
¥Example:
<script>
import { SvelteURL } from 'svelte/reactivity';
const url = new SvelteURL('https://example.com/path');
</script>
<!-- changes to these... -->
<input bind:value={url.protocol} />
<input bind:value={url.hostname} />
<input bind:value={url.pathname} />
<hr />
<!-- will update `href` and vice versa -->
<input bind:value={url.href} size="65" />
class SvelteURL extends URL {…}
get searchParams(): SvelteURLSearchParams;
SvelteURLSearchParams
内置 URLSearchParams
对象的响应式版本。在 effect 或 derived 中读取其内容(通过迭代,或者通过调用 params.get(...)
或 params.getAll(...)
,如下面的 example 所示)将导致参数更新时根据需要重新评估。
¥A reactive version of the built-in URLSearchParams
object.
Reading its contents (by iterating, or by calling params.get(...)
or params.getAll(...)
as in the example below) in an effect or derived
will cause it to be re-evaluated as necessary when the params are updated.
<script>
import { SvelteURLSearchParams } from 'svelte/reactivity';
const params = new SvelteURLSearchParams('message=hello');
let key = $state('key');
let value = $state('value');
</script>
<input bind:value={key} />
<input bind:value={value} />
<button onclick={() => params.append(key, value)}>append</button>
<p>?{params.toString()}</p>
{#each params as [key, value]}
<p>{key}: {value}</p>
{/each}
class SvelteURLSearchParams extends URLSearchParams {…}
[REPLACE](params: URLSearchParams): void;
createSubscriber
自 5.7.0 起可用
¥Available since 5.7.0
返回一个 subscribe
函数,如果在效果(包括模板中的表达式)中调用该函数,则使用 update
函数调用其 start
回调。每当调用 update
时,效果都会重新运行。
¥Returns a subscribe
function that, if called in an effect (including expressions in the template),
calls its start
callback with an update
function. Whenever update
is called, the effect re-runs.
如果 start
返回一个函数,则当效果被销毁时将调用该函数。
¥If start
returns a function, it will be called when the effect is destroyed.
如果在多个效果中调用 subscribe
,则只要效果处于活动状态,start
将仅被调用一次,并且只有在所有效果都被销毁时才会调用返回的拆卸函数。
¥If subscribe
is called in multiple effects, start
will only be called once as long as the effects
are active, and the returned teardown function will only be called when all effects are destroyed.
最好通过一个例子来理解。以下是 MediaQuery
的实现:
¥It’s best understood with an example. Here’s an implementation of MediaQuery
:
import { function createSubscriber(start: (update: () => void) => (() => void) | void): () => void
Returns a subscribe
function that, if called in an effect (including expressions in the template),
calls its start
callback with an update
function. Whenever update
is called, the effect re-runs.
If start
returns a function, it will be called when the effect is destroyed.
If subscribe
is called in multiple effects, start
will only be called once as long as the effects
are active, and the returned teardown function will only be called when all effects are destroyed.
It’s best understood with an example. Here’s an implementation of MediaQuery
:
import { createSubscriber } from 'svelte/reactivity';
import { on } from 'svelte/events';
export class MediaQuery {
#query;
#subscribe;
constructor(query) {
this.#query = window.matchMedia(`(${query})`);
this.#subscribe = createSubscriber((update) => {
// when the `change` event occurs, re-run any effects that read `this.current`
const off = on(this.#query, 'change', update);
// stop listening when all the effects are destroyed
return () => off();
});
}
get current() {
this.#subscribe();
// Return the current state of the query, whether or not we're in an effect
return this.#query.matches;
}
}
createSubscriber } from 'svelte/reactivity';
import { function on<Type extends keyof WindowEventMap>(window: Window, type: Type, handler: (this: Window, event: WindowEventMap[Type]) => any, options?: AddEventListenerOptions | undefined): () => void (+4 overloads)
Attaches an event handler to the window and returns a function that removes the handler. Using this
rather than addEventListener
will preserve the correct order relative to handlers added declaratively
(with attributes like onclick
), which use event delegation for performance reasons
on } from 'svelte/events';
export class class MediaQuery
MediaQuery {
#query;
#subscribe;
constructor(query: any
query) {
this.#query = var window: Window & typeof globalThis
window.function matchMedia(query: string): MediaQueryList
matchMedia(`(${query: any
query})`);
this.#subscribe = function createSubscriber(start: (update: () => void) => (() => void) | void): () => void
Returns a subscribe
function that, if called in an effect (including expressions in the template),
calls its start
callback with an update
function. Whenever update
is called, the effect re-runs.
If start
returns a function, it will be called when the effect is destroyed.
If subscribe
is called in multiple effects, start
will only be called once as long as the effects
are active, and the returned teardown function will only be called when all effects are destroyed.
It’s best understood with an example. Here’s an implementation of MediaQuery
:
import { createSubscriber } from 'svelte/reactivity';
import { on } from 'svelte/events';
export class MediaQuery {
#query;
#subscribe;
constructor(query) {
this.#query = window.matchMedia(`(${query})`);
this.#subscribe = createSubscriber((update) => {
// when the `change` event occurs, re-run any effects that read `this.current`
const off = on(this.#query, 'change', update);
// stop listening when all the effects are destroyed
return () => off();
});
}
get current() {
this.#subscribe();
// Return the current state of the query, whether or not we're in an effect
return this.#query.matches;
}
}
createSubscriber((update: () => void
update) => {
// when the `change` event occurs, re-run any effects that read `this.current`
const const off: () => void
off = on<MediaQueryList, "change">(element: MediaQueryList, type: "change", handler: (this: MediaQueryList, event: MediaQueryListEvent) => any, options?: AddEventListenerOptions | undefined): () => void (+4 overloads)
Attaches an event handler to an element and returns a function that removes the handler. Using this
rather than addEventListener
will preserve the correct order relative to handlers added declaratively
(with attributes like onclick
), which use event delegation for performance reasons
on(this.#query, 'change', update: () => void
update);
// stop listening when all the effects are destroyed
return () => const off: () => void
off();
});
}
get MediaQuery.current: boolean
current() {
this.#subscribe();
// Return the current state of the query, whether or not we're in an effect
return this.#query.MediaQueryList.matches: boolean
matches;
}
}
function createSubscriber(
start: (update: () => void) => (() => void) | void
): () => void;