svelte特殊元素

Svelte 提供了各种内置的特殊元素。

1、

首个介绍的是,它表示当前组件,允许在某些情况递归自身,这对于展示文件夹树之类的视图很有用,其中文件夹可以包含 其他 文件夹。

下方以展示文件夹树 Folder 为例:

Folder.svelte





- {name}

    {#each folders as f}
  • {/each}

App.svelte



当前的结果只显示了根目录:

要显示所有子目录,这样是不可以的:

Folder.svelte

{#each folders as f}
  
  • {/each}

    也就是说,你不可以在 Folder.svelte 中直接使用  自身,因为模块不能导入自身。但是我们可以使用代表自身:

    Folder.svelte

    {#each folders as f}
      
  • {/each}

    最终的结果:

    svelte特殊元素_第1张图片

    基于  的作用是引用自身组件的构造函数,因此它十分容易导致堆栈溢出。

    试想一下,Folder 组件中又使用了 Folder 组件,如果不加以“限制”,默认将会无穷无尽地渲染下去,直到爆栈报错。

    所以, 必须包裹在 #if 块或者 #each 块中,或者由插槽传给组件,其余情况均是禁止的。

    2、

    组件可以通过进行 “变身”,这样可以省掉一系列的if块...

    例如我们有3个十分简单的组件(显示不同颜色的文本):

    Red.svelte

    red text

    Green.svelte

    green text

    Blue.svelte

    blue text

    如果我们的主程序中需要根据某个下拉框的选择的不同,展示不同的颜色文本:

    svelte特殊元素_第2张图片

    那么程序可能需要很多的 if 来做判断:

    App.svelte

    
    
    
    
    {#if selected == 'red'}
      
    {:else if selected == 'green'}
      
    {:else }
      
    {/if}

    通过使用 ,可以消除掉诸多 if,更为动态地使用这3个组件:

    App.svelte

    
    
    
    
    

    this的值可以是任何组件的构造函数,如果提供的是一个假值,则不会渲染这个组件。

    3、

    正如任何 DOM 元素都可以将监听事件一样,你可以通过来监听window对象的事件,例如鼠标移动的事件:

    App.svelte

    
    
     ({x, y} = e) } />
    
    

    鼠标位置:{x}, {y}

    你也可以添加像  preventDefault 这样的  事件修饰符,这与 DOM 元素的方法并无二致。

    绑定

    我们还可以绑定一些window的属性,某些业务我们可能需要监测浏览器窗口的大小,原生的写法是通过监听 window.onresize 来实现的。

    在 Svelte 中,它更为简单,并且支持绑定:

    App.svelte

    
    
    
    
    

    Window Size: width={width}, height={height}

    支持绑定的属性列表如下:

    • innerWidth - 获得浏览器窗口的内容区域的宽度,包含垂直滚动条(如果有的话)
    • innerHeight - 获得浏览器窗口的内容区域的高度,包含水平滚动条(如果有的话)
    • outerWidth - 获得浏览器窗口的宽度
    • outerHeight - 获得浏览器窗口的高度
    • scrollX - document 在水平方向已滚动的像素值
    • scrollY - document 在垂直方向已滚动的像素值
    • online - window.navigator.onLine 的别名,代表当浏览器能够访问网络。

    除了 scrollX 和 scrollY 两个属性之外,其余均是只读的。

    4、

    类似,元素允许你监听document.body上的事件。这对于mouseentermouseleave事件来说十分有用,它们无法在window上触发。

    App.svelte

    
    
     msg = 'Enter'}
      on:mouseleave={() => msg = 'Leave'}
    />
    
    
    {msg}

    5、

    元素允许你将其他元素插入到文档中的中:

    App.svelte

    
      
    
    
    

    Hello world!

     中可以插入例如 

  • 高筋面粉
  • 从展示的结果图来看,目前十分完美:

    svelte特殊元素_第3张图片

    <svelte:fragment> 示例

    菠萝包的制作用料中还有“低筋面粉”,如果你也想放到 bottom 位置,那么尴尬的事情就发生了:

    App.svelte

    
    
    
      
  • 高筋面粉
  • 低筋面粉
  • Svelte 不允许提供两个相同 slot 名称的内容(参考第13章《插槽》中的第3小节),你将收到一个错误信息:“Duplicate slot name "bottom" in ”。

    下一个立即被想到的方案是这样:

    App.svelte

    
    
    
      
  • 高筋面粉
  • 低筋面粉
  • 为赋新词强说愁。强加了一个 div 作为容器,看看结果似乎又是对的:

    svelte特殊元素_第4张图片

    但不要被表面蒙蔽,以下是实际的 HTML:

    svelte特殊元素_第5张图片

    如果将所有用料使用横向布局,这个问题原形毕露:

    Material.svelte

    ...
    
    你可能留意到,最后一个样式规则,使用的是  :global( ),这是因为通过   添加的 
  •  用料项目, 不会自动应用与 Material 组件中的 
  •  相同的样式。
    因为样式在组件中默认就是 局部作用域的。

    这种情况下,你必须将这个样式使用 全局样式(通过 :global 伪类),  内容里的 
  •  才可以应用得 Material 中 
  •  的样式。
  • 结果如下所示:

    svelte特殊元素_第6张图片

    这就是前面所述的“可能会影响到组件原有的布局”的问题, 正是为了解决这个问题而生,只需要将 

     改为 ,问题迎刃而解:

    App.svelte

    
    
    
      
        
  • 高筋面粉
  • 低筋面粉
  • 7、

    允许你配置编译器的选项。

    例如你希望为组件生成属性访问器(默认不生成):

    App.svelte

    
    
    
    
    

    {x}

    通过给 svelte:options 加入 accessors 后,最终生成的 App 类如下:

    class App extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance, create_fragment, safe_not_equal, { x: 0 });
      }
    
      get x() {
        return this.$$.ctx[0];
      }
    
      set x(x) {
        this.$set({ x });
        flush();
      }
    }
    
    export default App;
    

    你可以留意到,变量 x 已经生成为 App 类的一个属性,如果没有指定这个编译选项,生成的 App 类则是这样:

    class App extends SvelteComponent {
      constructor(options) {
        super();
        init(this, options, instance, create_fragment, safe_not_equal, { x: 0 });
      }
    }
    
    export default App;
    

    生成属性访问器的目的,是提供给使用端更容易去访问的,这通常是你编写了一个 Svelte 组件,想同时在 React 或者 Vue 等地方上用时才需要这个选项。

    下列是允许在此处设置可选用的值:

    • immutable={true}:你确信不会使用可变数据,因此编译器可以执行简单的引用相等性检查来确定值是否已更改。
    • immutable={false}:默认值,Svelte 将按默认的方式处理可变对象的更改
    • accessors={true}:为组件的 props 添加 getter 和 setter
    • accessors={false}:默认值
    • namespace="...":将使用此组件的命名空间,最常见的就是 "svg"
    • tag="...":将组件编译为自定义元素时,指定的标签名称

    有关这些选项的详细信息,请参考API文档。

    总结

    对于  来说,99.9% 的情况下,你无需手工干预编译器的默认选项,除非你有十分明确的理由。

     跟 Vue 的