【问题标题】:How to access element passed in a slot to a child component in Svelte?如何访问插槽中传递的元素到 Svelte 中的子组件?
【发布时间】:2022-01-07 21:05:26
【问题描述】:

我正在为我的应用程序开发一个表格组件。父组件会将数据传递给要渲染的表。除了数据,它还传递一个槽,其中包含为表中的每一行呈现的操作。动作必须作为插槽传递,因为它们可以变化。

在示例中,我想要实现的是,当更改类选择值时,隐藏的保存按钮变为可见(仅适用于该行),这需要从父方法“onClassChanged”中发生。

App.svelte

<script lang="ts">
    import Table from "/src/components/DataTable/DataTable.svelte";
    import {onMount} from "svelte";

    export let transaction = 0;
    let transactions: Array<Type.Transaction.Bank.Record> = [];
    let classes: Array<Type.Transaction.Bank.Class> = [];
    let transactionService = new Transaction();

    async function loadTransactions() {
        let result = await transactionService.get();
        if (result) {
            transactions = result['transactions'];
        }
    }

    onMount(async () => {
        await loadTransactions();
    });


    function onClassChanged() {
        console.log('class changed');
    }
</script>

<h1>Transactions</h1>
{#if transactions.length > 0}
    <Table rows={transactions}>
        <div slot="actions">
            <select on:change={onClassChanged}>
                {#each classes as tx_class}
                    <option value="1">Class A</option>
                    <option value="2">Class B</option>
                {/each}
            </select>
            <button style="display: none">Save</button>
        </div>
    </Table>
{/if}

DataTable.svelte

<script lang="ts">
    export let rows: Array<[]>;
</script>

<div class="datatable">
    {#each rows as row}
        <div class="table-row">
            <div class="table-cell">
                {row.id}
            </div>
            <div class="table-cell">
                {row.description}
            </div>
            <div class="table-cell">
                {row.date}
            </div>
            <div class="table-cell">
                <slot name="actions" id="{row.id}"></slot>
            </div>
        </div>
    {/each}
</div>

我不知道该怎么做,所以欢迎任何想法/解决方案。

【问题讨论】:

    标签: svelte svelte-3 svelte-component


    【解决方案1】:

    如果您希望行在控制来自父级的内容的同时单独跟踪状态,那么最好将您的 DataTable 组件分解为 DataRow 组件。

    完成此操作后,跟踪更改只需拥有一个与表中的行数相同大小的布尔数组,然后对onClassChange 处理程序进行柯里化以接受索引值:

    // DataRow.svelte
    <script>
        export let row;
    </script>
    
    <div class="table-row">
        <div class="table-cell">
            {row.id}
        </div>
        <div class="table-cell">
            {row.description}
        </div>
        <div class="table-cell">
            {row.date}
        </div>
        <div class="table-cell">
            <slot name="actions" id="{row.id}"></slot>
        </div>
    </div>
    
    // App.svelte
    <script lang="ts">
        // import Table from "/src/components/DataTable/DataTable.svelte";
        import Row from "/src/components/DataTable/DataRow.svelte";
    
        let isChanged;
    
        // ...
    
        onMount(async () => {
            await loadTransactions();
            isChanged = new Array(transactions.length).fill(false);
        });
    
    
        function onClassChanged(i) {
            return function() {
                isChanged[i] = true;
                console.log('class changed');
            }
        }
    </script>
    
    <h1>Transactions</h1>
    {#if transactions.length > 0}
    <div class="datatable">
        {#each transactions as row, i}
        <Row {row}>
            <div slot="actions">
                <select on:change={onClassChanged(i)}>
                    {#each classes as tx_class}
                        <option value="1">Class A</option>
                        <option value="2">Class B</option>
                    {/each}
                </select>
                {#if isChanged[i]}
                <button>Save</button>
                {/if}
            </div>
        </Row>
        {/each}
    </div>
    {/if}
    

    作为额外的好处,由于您现在定义了每行而不是整个表格的槽内容,如果需要,您也可以轻松处理不同的选择选项。

    Basic REPL Demo 带有虚拟数据。

    【讨论】:

    • 谢谢,将整个表格组件保留为可以放在任何地方的单个组件非常重要。我得到了一些工作,我已经发布了作为答案。我很惊讶 Svelte 这么容易做到这一点。
    【解决方案2】:

    经过反复试验,我得到了如下工作:

    <script lang="ts">
        import Table from "/src/components/DataTable/DataTable.svelte";
        import {onMount} from "svelte";
    
        export let transactions: Array<Type.Transaction.Bank.Record> = [];
        let classes: Array<Type.Transaction.Bank.Class> = [];
        let transactionService = new Transaction();
    
    
        async function loadTransactions() {
            let result = await transactionService.get();
            if (result) {
                transactions = result['transactions'];
            }
        }
    
        onMount(async () => {
            await loadTransactions();
        });
    
    
        function onClassChanged(row) {
            row.state = 1;
            rowsView = transactions;   
        }
    </script>
    
    <h1>Transactions</h1>
    {#if transactions.length > 0}
        <Table 
            bind:rows={transactions}
            let:row={row}
            >
            <div slot="actions">
                <select on:change={() => {onClassChanged(row)}}>
                    {#each classes as tx_class}
                        <option value="1">Class A</option>
                        <option value="2">Class B</option>
                    {/each}
                </select>
                {#if selectedRow}
                    {#if row.state === 1}
                        <button>Save</button>
                    {/if}
                {/if}            
            </div>
        </Table>
    {/if}
    

    DataTable.svelte

    <script lang="ts">
        export let rows: Array<[]>;
    </script>
    
    <div class="datatable">
        {#each rows as row}
            <div class="table-row">
                <div class="table-cell">
                    {row.id}
                </div>
                <div class="table-cell">
                    {row.description}
                </div>
                <div class="table-cell">
                    {row.date}
                </div>
                <div class="table-cell">
                    <slot name="actions" row="{row}"></slot>
                </div>
            </div>
        {/each}
    </div>
    

    这允许我将自定义操作传递给子 DataTable 组件并定位特定行(活动行)并隐藏或显示原始问题中描述的保存按钮。我将对每一行的引用传递回父插槽以执行操作,然后将该行作为参数传递给 onClassChanged 方法,在该方法中我可以切换该行的 state 属性 - 这将切换按钮的可见性。

    【讨论】:

      猜你喜欢
      • 2019-09-29
      • 2018-06-01
      • 2018-04-27
      • 2021-10-16
      • 2018-02-15
      • 1970-01-01
      • 1970-01-01
      • 2017-12-06
      • 2020-06-05
      相关资源
      最近更新 更多