错误:如果输入使用双向绑定,则“类型”属性不能是动态的

Posted

技术标签:

【中文标题】错误:如果输入使用双向绑定,则“类型”属性不能是动态的【英文标题】:error: 'type' attribute cannot be dynamic if input uses two-way binding 【发布时间】:2019-12-14 23:52:30 【问题描述】:

我试图为我的项目创建一个Input 组件。我想在input 元素上动态设置类型属性

但是当我在input 上动态设置类型属性时,我收到错误消息 'type' attribute cannot be dynamic if input uses two-way binding

那么有什么解决方法可以让我可以动态设置类型属性而不会丢失双向绑定

Input.svelte

<script>
  export let placeholder = "";
  export let label = "";
  export let description = "";
  export let value = "";
  export let type = "text";
</script>

<div class="container">
    <label>label</label>
    <input type bind:value placeholder />
    <p>description</p>
</div>

【问题讨论】:

【参考方案1】:

type 在双向绑定中必须是静态的原因是 Svelte 生成的代码对于不同类型的输入是不同的。例如,numberrange 输入必须将其值强制转换为数字,某些输入需要 change 事件侦听器而不是 input 事件,反之亦然,等等。

但是您可以手动执行生成的代码会执行的相同操作 - 添加反映状态的事件侦听器:

<script>
  export let placeholder = "";
  export let label = "";
  export let description = "";
  export let value = "";
  export let type = "text";

  const handleInput = e => 
    // in here, you can switch on type and implement
    // whatever behaviour you need
    value = type.match(/^(number|range)$/)
      ? +e.target.value
      : e.target.value;
  ;
</script>

<div class="container">
    <label>label</label>
    <input type value placeholder on:input=handleInput />
    <p>description</p>
</div>

【讨论】:

嗨 Rich,值强制不起作用 - 对于 [type=number] 输入,我仍然得到字符串类型而不是数字。我在&lt;form on:submit&gt; 事件中使用了console.log value: new FormData(form).get('inputname') 。顺便说一句,感谢这个美妙的 Svelte 框架! 更新:Rich,实际上您的解决方案似乎有效。看起来是表单的行为在提交时将所有表单数据转换为字符串类型。【参考方案2】:

另一种可能的解决方案不是很优雅或 DRY,但不需要自己模拟核心 Svelte 功能是简单地在 type 上分支并相应地呈现不同的输入:

<script>
  export let name;
  export let value;
  export let type = 'text';
</script>


#if type === 'password'
  <input
    type="password"
    id=name
    name
    on:change
    on:blur
    bind:value
  />
:else if type === 'email'
  <input
    type="email"
    id=name
    name
    on:change
    on:blur
    bind:value
  />
:else if type === 'number'
  <input
    type="number"
    id=name
    name
    on:change
    on:blur
    bind:value
  />
:else if type === 'date'
  <input
    type="date"
    id=name
    name
    on:change
    on:blur
    bind:value
  />
:else
  <input
    type="text"
    id=name
    name
    on:change
    on:blur
    bind:value
  />
/if

【讨论】:

【参考方案3】:
<!-- InputField.svelte -->
<script>
  export let placeholder = "";
  export let label = "";
  export let description = "";
  export let value = "";
  export let type = "text";

  const handleInputType = (e) => 
    e.target.type = type;
  ;
</script>

<div class="container">
    <label>label</label>
    <input value placeholder on:input=handleInputType />
    <p>description</p>
</div>

我遇到了这个,为了简化,我所做的就像上面一样,基本上我删除了输入中的type,在输入时我只是修改了目标类型,因为这是一个组件,所以你的父母/路由苗条的文件。

<InputField type="email" bind:value=emailValue />

【讨论】:

使用这种方法,值将始终是字符串类型,当我们在 svelte 中指定 type=numbertype=range 时,我们希望绑定的值应该是数字类型。在这种方法中,我们还需要处理从字符串到数字的类型变化【参考方案4】:

一个简单的解决方法:通过 id 获取元素并使用element.setAttribute(attributename, attributevalue) 设置类型

<script>
  export let id = "";
  export let placeholder = "";
  export let label = "";
  export let description = "";
  export let value = "";
  export let type = "text";
</script>

<div class="container">
    <label>label</label>
    <input type bind:value placeholder
    on:focus="() => 
       console.log(type)
       let inpt =    document.getElementById(id)
       inpt.setAttribute("type", type)
       console.log(inpt)
    "/>
    <p>description</p>
</div>

希望对你有帮助:-)

【讨论】:

【参考方案5】:

这样的事情呢?

export let type: 'email' | 'text' | 'password' | 'number' = 'text'

let ref: htmlInputElement

onMount(() => 
  if (ref) 
    ref.type = type
  
)

然后

<input bind:this=ref />

export let type: 'email' | 'text' | 'password' | 'number' = 'text'

const ref = (node: HTMLInputElement) => 
  node.type = type

然后

<input use:ref />

【讨论】:

我建议不要在答案中使用修辞问题。他们冒着被误解为根本不是答案的风险。您正在尝试回答此页面顶部的问题,不是吗?否则请删除此帖。

以上是关于错误:如果输入使用双向绑定,则“类型”属性不能是动态的的主要内容,如果未能解决你的问题,请参考以下文章

用纯JS实现双向数据绑定

实现双向绑定

VUE的数据双向绑定

Angular2双向绑定选择选项不更新

Angular 2双向绑定从html输入标签中删除名称属性

vuejs