SvelteKit中如何在@html生成的HTML内实现动态字段替换?
问题描述
我想要创建一个Table组件,目前仅展示数据的功能正常,但还希望添加编辑/删除等动态标签。现有代码如下:
<script> const data = [ { username: "Test 1" }, { username: "Test 2" }, { username: "Test 3" }, { username: "Test 4" }, ] const headers = [ { key: 'username', text: 'Username' }, { key: null, text: 'Reset Link', field: '<p>/users/reset/{user.username}</p>' } ]; </script> <table> <tr> {#each headers as header} <th>{header.text}</th> {/each} </tr> {#each data as user} <tr> {#each headers as header} {#if user[header.key]} <td>{user[header.key]}</td> {:else} <td>{@html header.field}</td> {/if} {/each} </tr> {/each} </table>
当前输出:
Username Reset Link Test 1 /users/reset/{user.username} Test 2 /users/reset/{user.username} Test 3 /users/reset/{user.username} Test 4 /users/reset/{user.username}
预期输出:
Username Reset Link Test 1 /users/reset/Test 1 Test 2 /users/reset/Test 2 Test 3 /users/reset/Test 3 Test 4 /users/reset/Test 4
请问如何实现这类动态字段的替换?
解决方案
核心问题是header.field中的模板字符串只是普通文本,@html仅渲染HTML结构,不会处理变量替换。以下是几种可行的解决方法:
方法1:用模板函数替代静态字符串
把headers里的field改成接收user参数的函数,动态生成对应内容:
<script> const data = [ { username: "Test 1" }, { username: "Test 2" }, { username: "Test 3" }, { username: "Test 4" }, ] const headers = [ { key: 'username', text: 'Username' }, { key: null, text: 'Reset Link', field: (user) => `<p>/users/reset/${user.username}</p>` } ]; </script> <table> <tr> {#each headers as header} <th>{header.text}</th> {/each} </tr> {#each data as user} <tr> {#each headers as header} {#if header.key} <td>{user[header.key]}</td> {:else} <td>{@html header.field(user)}</td> {/if} {/each} </tr> {/each} </table>
方法2:正则替换字符串变量
如果坚持用字符串格式的field,可以写工具函数替换{user.xxx}格式的变量:
<script> const data = [ { username: "Test 1" }, { username: "Test 2" }, { username: "Test 3" }, { username: "Test 4" }, ] const replaceUserVars = (str, user) => { return str.replace(/\{user\.(\w+)\}/g, (match, key) => user[key] || match); } const headers = [ { key: 'username', text: 'Username' }, { key: null, text: 'Reset Link', field: '<p>/users/reset/{user.username}</p>' } ]; </script> <table> <tr> {#each headers as header} <th>{header.text}</th> {/each} </tr> {#each data as user} <tr> {#each headers as header} {#if header.key} <td>{user[header.key]}</td> {:else} <td>{@html replaceUserVars(header.field, user)}</td> {/if} {/each} </tr> {/each} </table>
方法3:用Svelte插槽实现(适合扩展编辑/删除功能)
如果后续要添加交互元素,插槽写法更符合Svelte特性,扩展性更强:
<!-- Table.svelte --> <script> export let data; export let headers; </script> <table> <tr> {#each headers as header} <th>{header.text}</th> {/each} </tr> {#each data as user, index} <tr> {#each headers as header} {#if header.key} <td>{user[header.key]}</td> {:else} <td> <slot name={header.slotName} {user} {index} /> </td> {/if} {/each} </tr> {/each} </table>
使用组件时:
<script> import Table from './Table.svelte'; const data = [ { username: "Test 1" }, { username: "Test 2" }, { username: "Test 3" }, { username: "Test 4" }, ] const headers = [ { key: 'username', text: 'Username' }, { text: 'Reset Link', slotName: 'reset-link' }, { text: 'Actions', slotName: 'actions' } ]; const handleEdit = (user) => { console.log('编辑用户:', user); } const handleDelete = (user) => { console.log('删除用户:', user); } </script> <Table {data} {headers}> <div slot="reset-link" let:user> <p>/users/reset/{user.username}</p> </div> <div slot="actions" let:user> <button on:click={() => handleEdit(user)}>编辑</button> <button on:click={() => handleDelete(user)}>删除</button> </div> </Table>
内容的提问来源于stack exchange,提问作者cunnus
相关产品推荐
相关产品推荐

