Skip to main content

{@attach ...}

附件是元素挂载到 DOM 时运行的函数。它们可以选择返回一个函数,该函数稍后在元素从 DOM 中删除时调用。

¥Attachments are functions that run when an element is mounted to the DOM. Optionally, they can return a function that is called when the element is later removed from the DOM.

附件在 Svelte 5.29 及更高版本中可用。

¥[!NOTE] Attachments are available in Svelte 5.29 and newer.

App
<script>
	/** @type {import('svelte/attachments').Attachment} */
	function myAttachment(element) {
		console.log(element.nodeName); // 'DIV'

		return () => {
			console.log('cleaning up');
		};
	}
</script>

<div {@attach myAttachment}>...</div>
<script lang="ts">
	import type { Attachment } from 'svelte/attachments';

	const myAttachment: Attachment = (element) => {
		console.log(element.nodeName); // 'DIV'

		return () => {
			console.log('cleaning up');
		};
	};
</script>

<div {@attach myAttachment}>...</div>

一个元素可以包含任意数量的附件。

¥An element can have any number of attachments.

附件工厂(Attachment factories)

¥Attachment factories

一个有用的模式是让函数(例如本例中的 tooltip)返回一个附件 (demo):

¥A useful pattern is for a function, such as tooltip in this example, to return an attachment (demo):

App
<script>
	import tippy from 'tippy.js';

	let content = $state('Hello!');

	/**

	 * @param {string} content

	 * @returns {import('svelte/attachments').Attachment}
	 */
	function tooltip(content) {
		return (element) => {
			const tooltip = tippy(element, { content });
			return tooltip.destroy;
		};
	}
</script>

<input bind:value={content} />

<button {@attach tooltip(content)}>
	Hover me
</button>
<script lang="ts">
	import tippy from 'tippy.js';
	import type { Attachment } from 'svelte/attachments';

	let content = $state('Hello!');

	function tooltip(content: string): Attachment {
		return (element) => {
			const tooltip = tippy(element, { content });
			return tooltip.destroy;
		};
	}
</script>

<input bind:value={content} />

<button {@attach tooltip(content)}>
	Hover me
</button>

由于 tooltip(content) 表达式在 effect 中运行,因此每当 content 发生更改时,附件都会被销毁并重新创建。

¥Since the tooltip(content) expression runs inside an effect, the attachment will be destroyed and recreated whenever content changes.

内联附件(Inline attachments)

¥Inline attachments

附件也可以内联创建 (demo):

¥Attachments can also be created inline (demo):

App
<canvas
	width={32}
	height={32}
	{@attach (canvas) => {
		const context = canvas.getContext('2d');

		$effect(() => {
			context.fillStyle = color;
			context.fillRect(0, 0, canvas.width, canvas.height);
		});
	}}
></canvas>

嵌套 effect 会在 color 发生变化时运行,而外部 effect(调用 canvas.getContext(...) 的地方)仅运行一次,因为它不读取任何响应式状态。

¥[!NOTE] The nested effect runs whenever color changes, while the outer effect (where canvas.getContext(...) is called) only runs once, since it doesn’t read any reactive state.

将附件传递给组件(Passing attachments to components)

¥Passing attachments to components

当在组件上使用时,{@attach ...} 将创建一个键为 Symbol 的 prop。如果组件将 spreads 属性添加到元素上,则该元素将接收这些附件。

¥When used on a component, {@attach ...} will create a prop whose key is a Symbol. If the component then spreads props onto an element, the element will receive those attachments.

这允许你创建用于扩充元素(demo)的封装器组件:

¥This allows you to create wrapper components that augment elements (demo):

Button
<script>
	/** @type {import('svelte/elements').HTMLButtonAttributes} */
	let { children, ...props } = $props();
</script>

<!-- `props` includes attachments -->
<button {...props}>
	{@render children?.()}
</button>
<script lang="ts">
	import type { HTMLButtonAttributes } from 'svelte/elements';

	let { children, ...props }: HTMLButtonAttributes = $props();
</script>

<!-- `props` includes attachments -->
<button {...props}>
	{@render children?.()}
</button>
App
<script>
	import tippy from 'tippy.js';
	import Button from './Button.svelte';

	let content = $state('Hello!');

	/**

	 * @param {string} content

	 * @returns {import('svelte/attachments').Attachment}
	 */
	function tooltip(content) {
		return (element) => {
			const tooltip = tippy(element, { content });
			return tooltip.destroy;
		};
	}
</script>

<input bind:value={content} />

<Button {@attach tooltip(content)}>
	Hover me
</Button>
<script lang="ts">
	import tippy from 'tippy.js';
	import Button from './Button.svelte';
	import type { Attachment } from 'svelte/attachments';

	let content = $state('Hello!');

	function tooltip(content: string): Attachment {
		return (element) => {
			const tooltip = tippy(element, { content });
			return tooltip.destroy;
		};
	}
</script>

<input bind:value={content} />

<Button {@attach tooltip(content)}>
	Hover me
</Button>

以编程方式创建附件(Creating attachments programmatically)

¥Creating attachments programmatically

要将附件添加到将展开到组件或元素的对象,请使用 createAttachmentKey

¥To add attachments to an object that will be spread onto a component or element, use createAttachmentKey.

上一页 下一页