自定义输入元素 [英] Custom input element in native form

查看:95
本文介绍了自定义输入元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于Web组件,人们想要创建并覆盖的元素之一是< input> 。输入元素是不好的,因为它们取决于它们的类型很多,并且通常很难定制,所以人们总是想要修改它们的外观和行为是正常的。

两年前或多或少,当我第一次听到网络组件时,我非常兴奋,并且想到了我想要创建的第一类元素是自定义输入元素。现在规范已经完成,它看起来像我对输入元素的需求没有解决。 Shadow DOM本来应该允许我改变他们的内部结构,但是看起来输入元素被列入黑名单,并且不能有影子根,因为他们已经有了一个隐藏的元素。如果我想添加额外的逻辑和行为,定制的内置元素(属性属性)应该可以实现;我不能做阴影DOM魔法,但至少我有这个,对吧?以及Safari不会执行它,聚合物不会因为这个原因而使用它们,这就像是即将被弃用的标准。

所以我只剩下普通的自定义元素;他们可以使用shadow DOM并拥有我想要的任何逻辑,但我希望它们成为输入!他们应该在< form> 内工作,但如果我是正确的,表单元素不喜欢它们。我是否还必须编写自己的自定义表单元素,以复制本地元素的所有内容?我必须告别 FormData ,验证API等吗?我是否失去了使用无javascript输入的表单的能力?解析方案

您可以使用外观创建自定义元素和你想要的行为。



在右边放置一个隐藏的< input> 元素 name (将传递给< form> )。



修改自定义元素visible value后更新它的属性。



我在<一个href =https://stackoverflow.com/a/38667839/4600982>这个答案类似的SO问题。



  class CI extends HTMLElement {constructor(){super()var sh = this.attachShadow({mode:'open'})sh。 appendChild(tpl.co ()}} connectedCallback(){var view = this var name = this.getAttribute('name')//代理输入elemnt var input = document.createElement('input')input.name =名称输入。 value = this.getAttribute('value')input.id ='realInput'input.style ='width:0; height:0; border:none; background:red'input.tabIndex = -1 this.appendChild(input) // content editable var content = this.shadowRoot.querySelector('#content')content.textContent = this.getAttribute('value')content.oninput = function(){//console.warn('content editable changed to' ,content.textContent)view.setAttribute('value',content.textContent)} //点击标签var label = document.querySelector('label [for =''+ name +'''')label.onclick = function (){content.focus()} //自动填充更新input.addEventListener('change',function(){//console.warn('real input changed')view.setAttribute('value',this.value)content.value = this.value})this.connected =如果(this.connected){this.querySelector('#realInput').value = true,则返回true(true,true,value) value.fontAttributes = [value] customElements.define('custom-input',CI)// Submitfunction submitF(){for(var()){this.shadowRoot.querySelector('#content').textContent = value}}} i = 0;我< this.length; (input.name)console.log('%s =%s',input.name,input.value)}} S1.onclick = function(){submitF.apply(i ++){var input = this [i] form1)}  

< form id = form1> <表> < tr>< td>< label for = name>名称< / label> < td>< input name = name id = name> < tr>< td>< label for = address>地址< / label> < td><输入名称=地址ID =地址> < tr>< td>< label for = city>城市< / label> < td>< custom-input id = city name = city>< / custom-input> < tr>< td>< label for = zip> Zip< / label> < td>< input name = zip id = zip> < tr>< td colspan = 2>< input id = S1 type = button value =Submit> < /表>< /形式>< HR>< DIV> < button onclick =document.querySelector('custom-input')。setAttribute('value','Paris')> city => Paris< / button>< / div>< template id = tpl> <风格> #content {background:dodgerblue;白颜色;最小宽度:50px; font-family:Courier New,Courier,等宽; font-size:1.3em; font-weight:600;显示:inline-block; padding:2px; }< / style> < div contenteditable id = content>< / div> < slot>< / slot>< / template>

With web components one of the elements that people want to create and override most is <input>. Input elements are bad because they are many things depending on their type and usually hard to customize, so it's normal that people always want to modify their looks and behavior.

Two years ago more or less, when I first heard of web components, I was pretty excited and the first kind of elements that came to my mind that I wanted to create were custom input elements. Now that the spec is finished it looks like the need I had for input elements is not solved. Shadow DOM was supposed to allow me to change their internal structure and looks but input elements are blacklisted and can not have a shadow root because they already have a hidden one. If I want add extra logic and behavior, custom, built-in elements with the is attribute should do the trick; I can't do the shadow DOM magic but at least I have this, right? well Safari is not going to implement it, polymer won't use them for that reason which smells like a standard that is going to be deprecated soon.

So I'm left with normal custom elements; they can use the shadow DOM and have whatever logic I want, but I want them to be inputs! they should work inside a <form>, but if I'm correct, form elements don't like them. Do I have to write my own custom form element as well that replicates all of what the native one does? Do I have to say goodbye to FormData, validation API, etc? Do I lose the ability to have a form with inputs that works without javascript?

解决方案

You can create a custom element with the look and behavior you want.

Put inside it a hidden <input> element with the right name (that will be passed to the <form>).

Update its value attribute whenever the custom element "visible value" is modified.

I posted an example in this answer to a similar SO question.

class CI extends HTMLElement 
{
    constructor ()
    {
        super()
        var sh = this.attachShadow( { mode: 'open' } )
        sh.appendChild( tpl.content.cloneNode( true ) )
    }

    connectedCallback ()
    {
        var view = this
        var name = this.getAttribute( 'name' )

        //proxy input elemnt
        var input = document.createElement( 'input' )
        input.name = name
        input.value = this.getAttribute( 'value' )
        input.id = 'realInput'
        input.style = 'width:0;height:0;border:none;background:red'
        input.tabIndex = -1
        this.appendChild( input )


        //content editable
        var content = this.shadowRoot.querySelector( '#content' )
        content.textContent = this.getAttribute( 'value' )
        content.oninput = function ()
        {
            //console.warn( 'content editable changed to', content.textContent )
            view.setAttribute( 'value', content.textContent)
        }

        //click on label
        var label = document.querySelector( 'label[for="' + name + '"]' )
        label.onclick = function () { content.focus() }

        //autofill update
        input.addEventListener( 'change', function ()
        {
            //console.warn( 'real input changed' )
            view.setAttribute( 'value', this.value )
            content.value = this.value 
        } )

        this.connected = true 
    }

    attributeChangedCallback ( name, old, value )
    {
        //console.info( 'attribute %s changed to %s', name, value )
        if ( this.connected )
        {
            this.querySelector( '#realInput' ).value = value 
            this.shadowRoot.querySelector( '#content' ).textContent = value 
        }                
    }

}
CI.observedAttributes = [ "value" ]
customElements.define( 'custom-input', CI )
//Submit
function submitF ()
{
    for( var i = 0 ; i < this.length ; i++ )
    {
        var input = this[i]
        if ( input.name ) console.log( '%s=%s', input.name, input.value )
    } 
}
S1.onclick = function () { submitF.apply(form1) }

<form id=form1>
    <table>
        <tr><td><label for=name>Name</label>        <td><input name=name id=name>
        <tr><td><label for=address>Address</label>  <td><input name=address id=address>
        <tr><td><label for=city>City</label>        <td><custom-input id=city name=city></custom-input>
        <tr><td><label for=zip>Zip</label>          <td><input name=zip id=zip>
        <tr><td colspan=2><input id=S1 type=button value="Submit">
    </table>
</form>
<hr>
<div>
  <button onclick="document.querySelector('custom-input').setAttribute('value','Paris')">city => Paris</button>
</div>

<template id=tpl>
  <style>
    #content {
      background: dodgerblue;
      color: white;
      min-width: 50px;
      font-family: Courier New, Courier, monospace;
      font-size: 1.3em;
      font-weight: 600;
      display: inline-block;
      padding: 2px;
    }
  </style>
  <div contenteditable id=content></div>
  <slot></slot>
</template>

这篇关于自定义输入元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆