Svelte中的Reactivity(响应式)和组件中的Props(属性)

作者:renzp94
时间:2021-03-22 01:43:55

Reactivity(响应式)

Svelte中响应式很简单,只需要定义一个变量,它就是响应式的,如果导出的是constclassfunction,则在组件之外是只读的。如:记录点击按钮的次数

在线 REPL

<script>
    let count = 0;
    const onClick = () => count++;
</script>

<button on:click={onClick}>点击了{count}</button>

注意:如果变量是数组,通过下标改变后,需要将新数组重新赋值给变量,否则视图不会更新。如果是对象且将其赋值给一个不是响应式的变量,则在更改了新变量的值之后需要将新变量重新赋值给对象,否则视图不会更新。

在线 REPL

<script>
    let user = {
        github: 'https://github.com/sveltejs',
        auth: {
            qq: '123456'
        }
    };

    let tags = ['code', 'blog', 'book'];

    function onChangeGithub() {
        //             // 此处是值赋值,不是引用赋值,所以改变tmp需要再次赋值给user
        //             let tmp = user
        //             tmp.github = 'https://github.com/renzp94'
        //             user = tmp
        user.github = 'https://github.com/renzp94';
    }

    function onChangeQQ() {
        // 这个和改变github一样,需要将auth重新赋值给user.auth
        let auth = user.auth;
        auth.qq = '456789';
        user.auth = auth;
    }

    function onChangeTag() {
        //             tags.push('svelte')
        //             // 只push,是不会视图是不会更新的,需要重新赋值
        //             tags = tags
        //             这种更简洁
        tags = [...tags, 'svelte'];
    }
</script>

<div class="user">
    <div>
        <a href={user.github}>{user.github}</a>
    </div>
    <div>
        QQ:{user.auth.qq}
    </div>
    <ul>
        {#each tags as tag (tag)}
            <li>{tag}</li>
        {/each}
    </ul>
    <button on:click={onChangeGithub}>改变Github地址</button>
    <button on:click={onChangeQQ}>改变QQ</button>
    <button on:click={onChangeTag}>改变Tag</button>
</div>

{#each} ... {/each}这是循环渲染的语法,下篇文章会介绍,这里先不用管。

Svelte中如果需要根据某个值来动态计算得到某个结果,并且值每次改变后,都会重新计算,那就需要用到$:(reactive declarations(响应式声明)),如果语句是给未声明的变量赋值组成,则会自动用let声明那个未声明的变量,如:通过姓和名得到全名

在线 REPL

<script>
    let firstname = '';
    let lastname = '';
    // 未声明fullname,则自动声明
    $: fullname = `${firstname}${lastname}`;
</script>

<label>
    姓氏:
    <input type="text" placeholder="请输入姓氏" bind:value={firstname} />
</label>
<label>
    名称:
    <input type="text" placeholder="请输入名称" bind:value={lastname} />
</label>
<div>您的全名是:{fullname}</div>

上述例子只是一个简单的使用,如果需要一些判断或处理得到结果的话,可以使用$:{}。将上述例子完善一下,做一些校验。

<script>
    let firstname = '';
    let lastname = '';
    let fullname = '';
    let error = '';

    $: {
        if (!firstname) {
            error = '请输入姓氏';
        } else if (!lastname) {
            error = '请输入名称';
        } else {
            error = '';
            fullname = `${firstname}${lastname}`;
        }
    }
</script>

<div class="error">
    {error}
</div>
<label>
    姓氏:
    <input type="text" placeholder="请输入姓氏" bind:value={firstname} />
</label>
<label>
    名称:
    <input type="text" placeholder="请输入名称" bind:value={lastname} />
</label>
{#if fullname}
    <div>您的全名是:{fullname}</div>
{/if}

<style>
    .error {
        color: red;
    }
</style>

Props(组件属性)

一般封装组件,都需要对外提供一些属性来支持自定义组件,在Svelte中组件可通过export来对外暴露属性。

  • 若需要指定prop的默认值,直接在定义时设置默认值即可。
  • 如果有一个属性对象,可以通过对象解构的方式直接赋值给组件。
  • 在组件内可以通过$$props来访问所有属性(包括未通过export导出的),可通过$$restProps仅访问未使用export导出的属性。

在线 REPL

Hello.svelte

<script>
    export let msg = 'world';
    export let desc;

    console.log($$props);
    console.log($$restProps);
</script>

<div>Hello {msg}</div>
{#if desc}
    <div>{desc}</div>
{/if}

App.svelte

<script>
    import Hello from './Hello.svelte';
    const obj = {
        msg: 'CodeBook',
        desc: '有质感的编程'
    };
</script>

<Hello c="ccc" />
<Hello msg="svelte" />
<Hello {...obj} />

{#if} ... {/if}这是条件渲染的语法,下篇文章会介绍,这里先不用管。

最后提一句,如果想让组件外部设置组件的 class 属性,需要export,但是class是关键字,不能export,所以需要转换一下思路,通过一下方式实现。

<script>
    export let className;
    export { className as class };
</script>