<svelte:window>/<svelte:document>/<svelte:body>
本教程共 50 篇 · 第 30 篇 · 更新于 2026-08-05 · 约 6 分钟阅读
本节目标:学会用 svelte:window、svelte:document、svelte:body 三个特殊元素监听全局事件和绑定窗口属性。
三个特殊元素干什么用
有时候你需要监听 window、document 或 document.body 上的事件。如果直接用 window.addEventListener,你还得记得在组件卸载时移除监听器,还要处理 SSR 时 window 不存在的问题。
这三个特殊元素帮你处理了所有麻烦事:
| 元素 | 绑定目标 | 主要用途 |
|---|---|---|
<svelte:window> | window | 窗口事件、滚动位置、窗口尺寸 |
<svelte:document> | document | visibilitychange 等文档事件 |
<svelte:body> | document.body | mouseenter/mouseleave 等事件 |
Note这三个元素只能出现在组件的顶层,不能放在
{#if}或其他元素内部。
svelte:window 事件监听
最基础的用法:监听窗口事件。
<script>
function handleKeydown(event) {
console.log(`按下了 ${event.key} 键`);
}
</script>
<svelte:window onkeydown={handleKeydown} />
组件卸载时,Svelte 自动移除监听器,你不用写任何清理代码。SSR 时也不会报错。
svelte:window 属性绑定
<svelte:window> 支持绑定以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
innerWidth | 只读 | 窗口内部宽度 |
innerHeight | 只读 | 窗口内部高度 |
outerWidth | 只读 | 窗口外部宽度 |
outerHeight | 只读 | 窗口外部高度 |
scrollX | 可写 | 水平滚动位置 |
scrollY | 可写 | 垂直滚动位置 |
online | 只读 | 网络在线状态 |
devicePixelRatio | 只读 | 设备像素比 |
滚动位置绑定
<script>
let scrollY = $state(0);
</script>
<!-- 绑定垂直滚动位置 -->
<svelte:window bind:scrollY />
<p>当前滚动位置:{Math.round(scrollY)}px</p>
<div style="height: 2000px;">
往下滚动试试
</div>
Note初始渲染时页面不会自动滚动到绑定值的位置,这是为了避免可访问性问题。只有后续的变量变化才会触发滚动。如果你需要在组件挂载时滚动,在
$effect里调用scrollTo()。
窗口尺寸绑定
<script>
let innerWidth = $state(0);
let innerHeight = $state(0);
</script>
<svelte:window bind:innerWidth bind:innerHeight />
<p>窗口尺寸:{innerWidth} x {innerHeight}</p>
网络状态绑定
<script>
let online = $state(true);
</script>
<svelte:window bind:online />
<p>
{#if online}
网络已连接
{:else}
网络已断开
{/if}
</p>
svelte:document
<svelte:document> 用于监听 document 上的事件。有些事件(比如 visibilitychange)不会在 window 上触发,必须在 document 上监听。
<script>
function handleVisibilityChange() {
if (document.hidden) {
console.log('用户切换到了其他标签页');
} else {
console.log('用户回来了');
}
}
</script>
<svelte:document onvisibilitychange={handleVisibilityChange} />
<svelte:document> 也支持属性绑定:
| 属性 | 说明 |
|---|---|
activeElement | 当前获得焦点的元素 |
fullscreenElement | 全屏元素 |
pointerLockElement | 指针锁定元素 |
visibilityState | 页面可见性状态 |
<script>
let visibilityState = $state('');
</script>
<svelte:document bind:visibilityState />
<p>页面状态:{visibilityState}</p>
svelte:body
<svelte:body> 用于监听 document.body 上的事件。有些事件(比如 mouseenter 和 mouseleave)不在 window 上触发,但在 body 上触发。
<script>
let isHovering = $state(false);
function handleMouseenter() {
isHovering = true;
}
function handleMouseleave() {
isHovering = false;
}
</script>
<svelte:body
onmouseenter={handleMouseenter}
onmouseleave={handleMouseleave}
/>
{#if isHovering}
<p>鼠标在页面上</p>
{:else}
<p>鼠标离开了页面</p>
{/if}
实战:滚动返回顶部按钮
一个常见的实战场景:滚动超过一定距离后显示”返回顶部”按钮。
<script>
let scrollY = $state(0);
function scrollToTop() {
window.scrollTo({ top: 0, behavior: 'smooth' });
}
</script>
<svelte:window bind:scrollY />
<div style="height: 3000px; padding: 20px;">
往下滚动...
</div>
<!-- 滚动超过 200px 时显示按钮 -->
{#if scrollY > 200}
<button
onclick={scrollToTop}
style="position: fixed; bottom: 20px; right: 20px; padding: 10px 20px; background: #6c5ce7; color: white; border: none; border-radius: 4px; cursor: pointer;"
>
返回顶部
</button>
{/if}
实战:响应式布局
根据窗口宽度切换不同的布局类名。
<script>
let innerWidth = $state(0);
let layout = $derived(
innerWidth < 768 ? 'mobile' :
innerWidth < 1024 ? 'tablet' :
'desktop'
);
</script>
<svelte:window bind:innerWidth />
<div class="container" data-layout={layout}>
<p>当前布局:{layout}</p>
<p>窗口宽度:{innerWidth}px</p>
</div>
<style>
.container[data-layout="mobile"] {
flex-direction: column;
}
.container[data-layout="tablet"] {
flex-direction: row;
flex-wrap: wrap;
}
.container[data-layout="desktop"] {
flex-direction: row;
}
</style>
实战:键盘快捷键
利用 <svelte:window> 的键盘事件监听实现快捷键。
<script>
let showHelp = $state(false);
function handleKeydown(event) {
// Cmd+/ (Mac) 或 Ctrl+/ (Windows) 切换帮助面板
if ((event.metaKey || event.ctrlKey) && event.key === '/') {
event.preventDefault();
showHelp = !showHelp;
}
// ESC 关闭
if (event.key === 'Escape') {
showHelp = false;
}
}
</script>
<svelte:window onkeydown={handleKeydown} />
<h1>快捷键示例</h1>
<p>按 Ctrl+/ 或 Cmd+/ 打开帮助,ESC 关闭</p>
{#if showHelp}
<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 20px; background: white; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
<h3>快捷键帮助</h3>
<ul>
<li>Ctrl+/ - 打开/关闭帮助</li>
<li>ESC - 关闭帮助</li>
</ul>
<button onclick={() => showHelp = false}>关闭</button>
</div>
{/if}
本节回顾
<svelte:window>监听窗口事件和绑定窗口属性(scrollY、innerWidth 等)<svelte:document>监听 document 事件(visibilitychange 等)和绑定文档属性<svelte:body>监听 body 事件(mouseenter/mouseleave 等)- 这三个元素只能出现在组件顶层,组件卸载时自动清理监听器
scrollY和scrollX是可写的,其他窗口属性都是只读- 初始渲染不会自动滚动到
scrollY绑定值,需要手动调用scrollTo()