Svelte中的一些其他用法

作者:renzp94
时间:2021-03-30 04:37:27

Action

Action可以针对元素级别的生命周期做一些自定义行为,主要提供三个生命周期:mountedupdatedestroyAction是一个函数,有两个参数,第一个参数为元素,第二个参数为传入参数。函数主体为mounted生命周期,其内部返回一个对象,对象可以包含两个属性分别为:updatedestroymounted会在元素渲染后执行,update会在Action参数发生变化后调用,destroy会在元素销毁后调用。

在线 REPL

countAction.js

export default (node, params) => {
    console.log('mounted:', node, params);

    return {
        update(val) {
            console.log('update:', val);
        },
        destroy() {
            console.log('destroy');
        }
    };
};

App.svelte

<script>
    import countAction from './countAction';
    let count = 0;

    const onAdd = () => count++;
</script>

<h1 use:countAction={count}>{count}</h1>
<button on:click={onAdd}> +1 </button>

Class

Svelte中对于绑定class提供了一些指令来简化。

  • class={条件?类名1:类名2}:条件满足用类名1,否则用类名2
  • class:类名={条件}:条件满足则使用类名
  • class:类名:变量名和类名一致,当类名为真时则采用类名。

在线 REPL

<script>
    let bold = true;
    let error = true;
</script>

<div class={error ? 'red' : 'green'}>hello</div>
<div class:bold>Hello</div>
<div class:bold>Hello</div>

<style>
    .bold {
        font-weight: bold;
    }
    .red {
        color: red;
    }
    .green {
        color: green;
    }
</style>

Context

当需要兄弟组件间共享数据时,可以通过Context来操作。Context API提供了三个方法:

  • setContext:设置context。接受两个参数:keyvalue
  • getContext:获取context。接受一个参数:key
  • hasContext:判断是否有某个context。接受一个参数:key

在线 REPL

Button.svelte

<script>
    import { getContext, hasContext } from 'svelte';

    let border = false;

    console.log(hasContext('BUTTON_BORDER'), getContext('BUTTON_BORDER'));

    if (hasContext('BUTTON_BORDER')) {
        border = getContext('BUTTON_BORDER');
    }
</script>

<button class:border>
    <slot />
</button>

<style>
    button {
        border: none;
    }
    .border {
        border: 1px solid #000;
    }
</style>

App.svelte

<script>
    import Button from './Button.svelte';
    import { setContext } from 'svelte';

    setContext('BUTTON_BORDER', true);
</script>

<Button>按钮</Button>

Component Slot

Svelte还为组件提供了插槽,实现更灵活的自定义组件。使用插槽用<slot></slot>,如果不指定name则为默认插槽,指定了name则为命名插槽。如果需要给某个插槽指定默认内容,则在<slot></slot>之前添加默认内容即可,当插槽没有指定内容时会采用默认内容。在组件外使用插槽时,对于默认插槽只需要放在组件区域内,如:<Button>默认插槽</Button>,对于命名插槽则需要使用slot="插槽名"属性在组件区域内指定,如:<Button><span slot="suffix">命名插槽</span></Button>。如果需要根据插槽是否存在来进行相应操作,还可以用$$slots检查是否有某个插槽是否存在。如果需要插槽内可以访问子组件中才有的数据,可以使用slot props,通过在组件内slot上设置属性,并在父组件中使用组件时用let指令使用。

在线 REPL

Button.svelte

<script>
    console.log('default: ', $$slots.defaults);
    console.log('prefix: ', $$slots.prefix);
    console.log('suffix: ', $$slots.suffix);

    let hoving = false;
    const onMouseenter = () => (hoving = true);
    const onMouseleave = () => (hoving = false);
</script>

<button on:mouseenter={onMouseenter} on:mouseleave={onMouseleave}>
    <slot name="prefix">默认的prefix</slot>
    <slot {hoving} />
    <slot name="suffix" />
</button>

App.svelte

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

<Button let:hoving>
    {#if hoving}
        鼠标悬停
    {:else}
        默认内容
    {/if}
    <span slot="suffix">后置内容</span>
</Button>

内置元素

Svelte提供了一些内置元素:

  • <svelte:self>:允许组件递归的调用自己。
  • <svelte:component>:设置动态组件。
  • <svelte:window>window对象。
  • <svelte:body>body元素。
  • <svelte:head>head元素。
  • <svelte:options>:指定编译选项。
    • immutable:是否禁止使用可变数据
    • accessors:是否为组件的 props 添加gettersetter
    • namespace:命名空间
    • tag:将组件编译成自定义元素的名称
  • <svelte:fragment>:在使用组件插槽配合使用可以不渲染元素。

在线 REPL

Menu.svelte

<script>
    export let menus;
</script>

<div>
    <slot name="test" />
    {#each menus as menu (menu.key)}
        {#if menu.children && menu.children.length > 0}
            <div>{menu.name}</div>
            <div style="margin-left: 8px">
                <svelte:self menus={menu.children} />
            </div>
        {:else}
            <div>{menu.name}</div>
        {/if}
    {/each}
</div>

App.svelte

<script>
    import Menu from './Menu.svelte';
    let menus = [
        {
            key: 'home',
            name: '首页'
        },
        {
            key: 'user',
            name: '用户管理',
            children: [
                {
                    key: 'admin',
                    name: '超级管理员'
                },
                {
                    key: 'normal',
                    name: '普通用户'
                }
            ]
        }
    ];
</script>

<Menu {menus}>
    <svelte:fragment slot="test">
        <div>test</div>
    </svelte:fragment>
</Menu>

module context

Svelte提供了<script context="module"></script>块来执行模块首次加载时的代码,不是在组件实例化时运行(组件实例化运行时在<script></script>块中)。

在线 REPL

Button.svelte

<script context="module">
    let buttonText = '';
</script>

<script>
    export let text;
    const onClick = () => {
        console.log('button text before:', buttonText);
        buttonText = text;
    };
</script>

<button on:click={onClick}>
    {text}
</button>

App.svelte

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

<Button text="按钮1" />
<Button text="按钮2" />
<Button text="按钮3" />
<Button text="按钮4" />