处理 Svelte 组件道具的最佳方式

Best way to handle Svelte component props

我正在使用 SvelteKit 和 Tailwind 构建应用程序。我知道在使用 Tailwind 设计样式时,建议利用组件来减少必须使用 Tailwinds 实用程序编写的重复代码量 类。我的问题是,当基于 HTML 标签(例如 <input> 标签)制作组件时,处理该组件中通常只是该标签的属性的 props 变得难以应付。 MDN 显示 <input> 标签有 31 个可能的属性。我知道我不会全部使用它们,但是来回将它们作为 props 添加到组件中变得很烦人。

解决这个问题的最佳方法是什么,而不是将多达 31 行 export let attribute 添加到一个组件并将它们添加到 real HTML组件内部的标记?

示例:

<script>
    export let name;
    export let id;
    export let type;
    export let disabled;
    export let required;
    export let minLength;
    export let maxLength;
    export let min;
    export let max;
    export let pattern;

    let value;
    let borderColor = '#D1D5DB';

    const inputHandler = (e) => {
        if (e.target.value === '') {
            borderColor = '#D1D5DB';
        } else {
            borderColor = '';
        }
    };
</script>

<input
    {name}
    {id}
    {type}
    {disabled}
    {required}
    {minLength}
    {maxLength}
    {min}
    {max}
    {pattern}
    on:input={inputHandler}
    style={`border-color: ${borderColor}`}
    class="
    w-full px-1 py-px mb-4 bg-transparent border-2 border-gray-300 
    rounded-xl last:mb-0 valid:border-emerald-300 invalid:border-rose-400
  "
/>

如果你想可以做到

<MyInputField name="123" maxLength="5" type="text">

无需声明所有这些额外的属性,最好的方法是使用 $$restProps,此对象将包含所有已传递给组件但尚未显式定义的道具作为道具(导出)。

<script>
  export let name = "";
</script>

<input name={name} {..$$restProps}>

(这里定义了name,所以不会包含在$$restProps中,我不得不自己添加)

或者使用 $$restProps(并且基于@pilchard 上面的评论,谢谢)可以导出一个选项对象,它包含所有修改的属性值并在定义的默认属性之后传播在组件内的输入元素上
像这样元素的所有可能属性都可以是 used/set 而不必在任何地方都写出来 REPL

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

    const options ={
        type: 'number',
        placeholder:'input a number',
        required: true
    };
</script>

<Input {options} />
Input.svelte
<script>
    export let options = {}
    export let value = ''
</script>

<input type="text"
       placeholder="default placeholder"
       {...options}
       bind:value
       style:border-color="{options.required && value === '' ? 'tomato' : ''}"
       class="w-full px-1 py-px mb-4 bg-transparent border-2 ..."
       />