特殊元素 #

一、特殊元素概述 #

Svelte 提供了一系列特殊元素,用于在组件中操作 document 的特定部分。

text
┌─────────────────────────────────────────────────────────────┐
│                    Svelte 特殊元素                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  <svelte:head>     向 <head> 插入内容                       │
│  <svelte:body>     向 <body> 添加事件监听                   │
│  <svelte:window>   向 window 添加事件监听和绑定             │
│  <svelte:fragment> 用于插槽内容包装                         │
│  <svelte:options>  组件选项配置                             │
│  <svelte:document> 向 document 添加事件监听                 │
│  <svelte:component> 动态组件渲染                            │
│  <svelte:element>  动态元素渲染                             │
│  <svelte:self>     组件递归渲染                             │
│                                                             │
└─────────────────────────────────────────────────────────────┘

二、svelte:head #

2.1 基本用法 #

svelte
<svelte:head>
  <title>My Page Title</title>
  <meta name="description" content="Page description" />
  <link rel="icon" href="/favicon.ico" />
</svelte:head>

<p>Page content</p>

2.2 动态标题 #

svelte
<script>
  let pageTitle = 'Home';
</script>

<svelte:head>
  <title>{pageTitle} | My App</title>
</svelte:head>

<button onclick={() => pageTitle = 'About'}>Go to About</button>

2.3 SEO 优化 #

svelte
<script>
  let { title, description, image } = $props();
</script>

<svelte:head>
  <title>{title}</title>
  <meta name="description" content={description} />
  <meta property="og:title" content={title} />
  <meta property="og:description" content={description} />
  <meta property="og:image" content={image} />
  <meta name="twitter:card" content="summary_large_image" />
</svelte:head>

2.4 加载外部资源 #

svelte
<svelte:head>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto" />
  <script src="https://cdn.example.com/library.js"></script>
</svelte:head>

三、svelte:body #

3.1 基本用法 #

svelte
<script>
  function handleMouseMove(event) {
    console.log('Mouse position:', event.clientX, event.clientY);
  }
</script>

<svelte:body on:mousemove={handleMouseMove} />

3.2 常用事件 #

svelte
<script>
  function handleMouseEnter() {
    console.log('Mouse entered body');
  }
  
  function handleMouseLeave() {
    console.log('Mouse left body');
  }
  
  function handleClick(event) {
    console.log('Body clicked', event.target);
  }
</script>

<svelte:body 
  on:mouseenter={handleMouseEnter}
  on:mouseleave={handleMouseLeave}
  on:click={handleClick}
/>

3.3 键盘事件 #

svelte
<script>
  let lastKey = '';
  
  function handleKeyDown(event) {
    lastKey = event.key;
    
    if (event.key === 'Escape') {
      console.log('Escape pressed');
    }
  }
</script>

<svelte:body on:keydown={handleKeyDown} />

<p>Last key: {lastKey}</p>

四、svelte:window #

4.1 事件绑定 #

svelte
<script>
  function handleResize() {
    console.log('Window resized:', window.innerWidth, window.innerHeight);
  }
  
  function handleScroll() {
    console.log('Scrolled:', window.scrollY);
  }
</script>

<svelte:window 
  on:resize={handleResize}
  on:scroll={handleScroll}
/>

4.2 属性绑定 #

svelte
<script>
  let innerWidth = 0;
  let innerHeight = 0;
  let scrollX = 0;
  let scrollY = 0;
</script>

<svelte:window 
  bind:innerWidth
  bind:innerHeight
  bind:scrollX
  bind:scrollY
/>

<p>Window: {innerWidth}x{innerHeight}</p>
<p>Scroll: ({scrollX}, {scrollY})</p>

4.3 响应式布局 #

svelte
<script>
  let innerWidth = 0;
  
  $: isMobile = innerWidth < 768;
  $: isTablet = innerWidth >= 768 && innerWidth < 1024;
  $: isDesktop = innerWidth >= 1024;
</script>

<svelte:window bind:innerWidth />

{#if isMobile}
  <MobileLayout />
{:else if isTablet}
  <TabletLayout />
{:else}
  <DesktopLayout />
{/if}

4.4 滚动到顶部按钮 #

svelte
<script>
  let scrollY = 0;
  
  function scrollToTop() {
    window.scrollTo({ top: 0, behavior: 'smooth' });
  }
</script>

<svelte:window bind:scrollY />

{#if scrollY > 300}
  <button 
    class="scroll-top"
    onclick={scrollToTop}
  >
    ↑ Top
  </button>
{/if}

<style>
  .scroll-top {
    position: fixed;
    bottom: 20px;
    right: 20px;
    padding: 10px 20px;
    background: #ff3e00;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }
</style>

五、svelte:fragment #

5.1 基本用法 #

svelte
<script>
  let { } = $props();
</script>

<svelte:fragment slot="content">
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</svelte:fragment>

5.2 多根节点插槽 #

svelte
<script>
  import Layout from './Layout.svelte';
</script>

<Layout>
  <svelte:fragment slot="header">
    <h1>Title</h1>
    <nav>Navigation</nav>
  </svelte:fragment>
  
  <p>Main content</p>
</Layout>

5.3 条件渲染多元素 #

svelte
<script>
  let showExtra = false;
</script>

{#if showExtra}
  <svelte:fragment>
    <p>Extra paragraph 1</p>
    <p>Extra paragraph 2</p>
  </svelte:fragment>
{/if}

六、svelte:component #

6.1 动态组件 #

svelte
<script>
  import Home from './Home.svelte';
  import About from './About.svelte';
  import Contact from './Contact.svelte';
  
  const components = { Home, About, Contact };
  
  let currentComponent = 'Home';
  let Component = components[currentComponent];
</script>

<nav>
  <button onclick={() => Component = Home}>Home</button>
  <button onclick={() => Component = About}>About</button>
  <button onclick={() => Component = Contact}>Contact</button>
</nav>

<svelte:component this={Component} />

6.2 传递 Props #

svelte
<script>
  import Card from './Card.svelte';
  import List from './List.svelte';
  
  let currentView = 'card';
  let data = { items: [], title: 'My Data' };
</script>

<svelte:component 
  this={currentView === 'card' ? Card : List}
  data={data}
  onUpdate={handleUpdate}
/>

6.3 条件组件 #

svelte
<script>
  import Loading from './Loading.svelte';
  import Error from './Error.svelte';
  import Content from './Content.svelte';
  
  let loading = true;
  let error = null;
  let data = null;
  
  $: Component = loading ? Loading : error ? Error : Content;
  $: props = loading ? {} : error ? { error } : { data };
</script>

<svelte:component this={Component} {...props} />

七、svelte:element #

7.1 动态元素 #

svelte
<script>
  let tag = 'div';
</script>

<svelte:element this={tag}>
  Dynamic element
</svelte:element>

<button onclick={() => tag = 'span'}>Span</button>
<button onclick={() => tag = 'div'}>Div</button>
<button onclick={() => tag = 'section'}>Section</button>

7.2 语义化组件 #

svelte
<script>
  let { as = 'div', href } = $props();
</script>

<svelte:element this={href ? 'a' : as} {href}>
  <slot />
</svelte:element>

使用:

svelte
<Button>Button</Button>
<Button as="a" href="/link">Link Button</Button>

7.3 标题组件 #

svelte
<script>
  let { level = 1 } = $props();
  
  const tag = `h${Math.min(Math.max(level, 1), 6)}`;
</script>

<svelte:element this={tag}>
  <slot />
</svelte:element>

使用:

svelte
<Heading level={1}>H1 Title</Heading>
<Heading level={2}>H2 Title</Heading>
<Heading level={3}>H3 Title</Heading>

八、svelte:self #

8.1 递归组件 #

svelte
<script>
  let { node } = $props();
</script>

<div class="tree-node">
  <span>{node.name}</span>
  
  {#if node.children}
    <div class="children">
      {#each node.children as child}
        <svelte:self node={child} />
      {/each}
    </div>
  {/if}
</div>

8.2 嵌套列表 #

svelte
<script>
  let { items, depth = 0 } = $props();
</script>

<ul style="padding-left: {depth * 20}px">
  {#each items as item}
    <li>
      {item.text}
      {#if item.children}
        <svelte:self items={item.children} depth={depth + 1} />
      {/if}
    </li>
  {/each}
</ul>

8.3 评论组件 #

svelte
<script>
  let { comment } = $props();
</script>

<div class="comment">
  <div class="header">
    <strong>{comment.author}</strong>
    <span>{comment.date}</span>
  </div>
  <p>{comment.text}</p>
  
  {#if comment.replies}
    <div class="replies">
      {#each comment.replies as reply}
        <svelte:self comment={reply} />
      {/each}
    </div>
  {/if}
</div>

九、svelte:options #

9.1 不可变 Props #

svelte
<script>
  export let data;
</script>

<svelte:options immutable={true} />

<p>{data.name}</p>

9.2 访问选项 #

svelte
<script>
  export let customOption = 'default';
</script>

<svelte:options 
  immutable={true}
  accessors={true}
/>

<p>{customOption}</p>

9.3 命名空间 #

svelte
<svelte:options namespace="svg" />

<circle cx="50" cy="50" r="40" />

十、完整示例 #

10.1 页面布局组件 #

svelte
<script>
  import { page } from '$app/stores';
  
  let { title = 'My App', description = '' } = $props();
  
  $: pageTitle = `${title} | My App`;
</script>

<svelte:head>
  <title>{pageTitle}</title>
  <meta name="description" content={description} />
  <link rel="canonical" href={$page.url.href} />
</svelte:head>

<svelte:window bind:scrollY />

<div class="page" class:scrolled={scrollY > 50}>
  <header>
    <nav>
      <a href="/">Home</a>
      <a href="/about">About</a>
      <a href="/contact">Contact</a>
    </nav>
  </header>
  
  <main>
    <slot />
  </main>
  
  <footer>
    <p>© 2024 My App</p>
  </footer>
</div>

<style>
  .page {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
  }
  
  header {
    position: sticky;
    top: 0;
    background: white;
    transition: box-shadow 0.3s;
  }
  
  .scrolled header {
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
  }
  
  main {
    flex: 1;
    padding: 2rem;
  }
</style>

10.2 响应式导航 #

svelte
<script>
  let innerWidth = 0;
  let menuOpen = false;
  
  $: isMobile = innerWidth < 768;
  
  function handleKeyDown(event) {
    if (event.key === 'Escape') {
      menuOpen = false;
    }
  }
</script>

<svelte:window bind:innerWidth on:keydown={handleKeyDown} />

<nav>
  {#if isMobile}
    <button onclick={() => menuOpen = !menuOpen}>
      Menu
    </button>
    
    {#if menuOpen}
      <div class="mobile-menu">
        <a href="/">Home</a>
        <a href="/about">About</a>
        <a href="/contact">Contact</a>
      </div>
    {/if}
  {:else}
    <div class="desktop-menu">
      <a href="/">Home</a>
      <a href="/about">About</a>
      <a href="/contact">Contact</a>
    </div>
  {/if}
</nav>

十一、总结 #

元素 说明
<svelte:head> <head> 插入内容
<svelte:body> <body> 添加事件
<svelte:window> 绑定 window 属性和事件
<svelte:fragment> 无包装元素的多节点
<svelte:component> 动态组件渲染
<svelte:element> 动态元素渲染
<svelte:self> 组件递归渲染
<svelte:options> 组件选项配置

特殊元素要点:

  • svelte:head 用于 SEO 和资源加载
  • svelte:window 用于响应式布局
  • svelte:component 用于动态组件
  • svelte:element 用于动态元素
  • svelte:self 用于递归渲染
最后更新:2026-03-28