【问题标题】:Get value of invalid html5 date input获取无效 html5 日期输入的值
【发布时间】:2017-11-22 11:44:27
【问题描述】:

我正在构建一个日历选择器来伴随(并替换某些浏览器提供的默认日历日期选择器)inputtype="date"

据记载,为了“简单”,Chrome(可能还有其他浏览器)的日期输入允许输入无效日期,但它们将无法验证(即 31/06/2017 可以输入,但会产生一个“值“的”)。

我的问题是:当输入的日期无效时,如何获取无效日期的值?

var date_input = document.getElementById('date_input');
var output_div = document.getElementById('output_div');

output_div.innerHTML = date_input.value;

date_input.addEventListener('input', function(e){
	output_div.innerHTML = e.target.value;
});
<p>To quickly input an invalid date, select the day field and press the down arrow (on Chrome OSX this displays an empty div below the input instead of the invalid date). This will select 31/06/2017</p>
<input type="date" value="2017-06-01" id="date_input" />
<br />
<br />
<div id="output_div" />

【问题讨论】:

  • 如果使用的是输入类型日期,那么日期值怎么会无效呢?
  • @sajalsuraj,如前所述,您可以输入(手动或通过按箭头键)日期,例如 31/06/2017(只有 30 天)六月)。输入允许这个值被输入和显示,但在使用Javascript查询时不返回它作为它的“值”)

标签: javascript html validation html5-input-date


【解决方案1】:

不是这样的

var date_input = document.getElementById( 'date_input' );
var output_div = document.getElementById( 'output_div' );

output_div.textContent = date_input.valueAsDate; // :-)

date_input.addEventListener( 'input', function( evt ){
    var val = date_input.value,
        sel = document.getSelection();
    if ( date_input.validity.badInput ) {
        // date_input.focus(); // with or without this,
        // date_input.select(); // this doesn't work but,
        // due to the added <span> wrapper:
        sel.selectAllChildren( date_input.parentElement );
        // this does. So:
        val = sel.toString() || function() {
            var copied = document.execCommand( 'copy' );
            sel.empty(); // clear the selection
            return "Invalid date" + ( copied ? " copied to clipboard." : "" );
        }();
    }
    output_div.textContent = val;
});
#output_div {
    margin-top: 1em;
}
<p>To quickly input an invalid date, select the day field and press the down arrow (on Chrome OSX this displays an empty div below the input instead of the invalid date). This will select 31/06/2017</p>
<span><input type="date" value="2017-06-01" id="date_input"></span>
<div id="output_div"></div>

显然,由于显示的value 实际上是&lt;input&gt;we can't access the user-agent's shadow DOMshadow DOM child输出,因此可见值实际上是JS 不知道。

对于accessibility reasons,可见值必须可供屏幕阅读器等访问,也可以手动复制到剪贴板。

尝试了多种以编程方式选择和复制文本的方法,但我的想法和耐心已经耗尽,只能设法将其复制到剪贴板。

  • 如果其他人能弄清楚如何用 JS 读取 #shadow-root (user-agent)aria-value* 属性,那么你就有了前进的方向。
  • 如果其他人能够弄清楚如何将 selection 字符串分配给 var,那么您还有其他方法。

然而

由于无效输入仅限于可预见的超出范围,您可以监控最后一个有效的value 在更改为无效之前是什么,然后计算它现在肯定是什么。

  • 如果使用日期选择器,所有输入都将有效。
  • 如果键入,请监控击键。
  • 如果使用箭头按钮,并且日期为 30/06/2017,在更改之前使其无效,并且 29/06/201730/05/201730/07/201730/06/201630/06/2018 都有效,则无效日期必须是 31/06/2017

没有尝试过(还)使这项工作有效,但我相信它可以。我会用这个答案发布那个解决方案,但是我的半天时间已经被这个问题吞噬了,我很饿。如果表达了真诚的兴趣,我会很乐意尝试并提供代码。

还是不行

如果它们是使用箭头按钮创建的,并且仅当最后一个日期有效时,这将显示无效日期。我可能会找到解决方法,但正式放弃!生命太短暂了。

According to MDN:

...显示的日期格式将根据用户操作系统的区域设置来选择。

这将使跟踪击键变得异常重要。

但是,我刚刚发现 &lt;input type="datetime-local"&gt; 可能会解决该问题,并且可能会解决其他问题。

所以这很有用:

但试图强迫它起作用开始感觉像是试图将西瓜插入通常不适合的地方。

这是一个没有魅力甚至没有魅力的笨拙的杂物,如果有人看得太用力,它很可能会破裂。最好的免责声明;)

var date = "",
    input = document.querySelector( "input" ),
    output = document.querySelector( "output" ),
    bits = function( d ) {
        return [ d.getFullYear(), d.getMonth() + 1, d.getDate() ];
    },
    adjustedDate = function( o ) {
        var d = new Date( date ),
            b = bits( d ),
            year = b[ 0 ],
            month = b[ 1 ],
            day = b[ 2 ];
        switch ( o.i ) {
            case "d": return [ year, month, ( day + o.v ) || 31 ];
            case "m": return [ year, month + o.v, day ];
            case "y": return [ year + o.v, month, day ];
        }
    },
    calcDate = function() {
        var ad, vd, rd;
        [ { i: "d", v: 1 },
          { i: "d", v: -1 },
          { i: "m", v: 1 },
          { i: "m", v: -1 },
          { i: "y", v: 1 },
          { i: "y", v: -1 }
        ].forEach( ( v ) => {
            ad = adjustedDate( v ).join( "-" );
            vd = bits( new Date( ad ) ).join( "-" );
            if ( ad !== vd ) {
                rd = ad;
            }
        } );
        return rd.split( "-" ).map( ( v ) => {
            v = v.toString();
            return v.length === 1 ? "0" + v : v;
        } ).join( "-" ); // tired so mental
    },
    showDate = function() {
        output.textContent = date = ( input.value || calcDate() );
    };
showDate();
input.addEventListener( "input", showDate, false );
output {
    margin-left: 1em;
}
<p>To quickly input an invalid date, select the day field and press the down arrow. This will select 31/06/2017 and output the desired invalid date string.</p>
<form><input type="date" value="2017-06-01"><output></output></form>

【讨论】:

  • 复制文本是一个有趣的解决方法。我喜欢它作为一个比“但是”部分更好的潜在解决方案。原因是像29/02/2012 这样的日期有两个地方,如果更改,会使值无效(当天的向上箭头,或年份的向上/向下箭头),我认为数字键选项只会使可能性非常难以管理的无效选项(尤其是考虑到minmax 属性选项)
  • @haxxxton - 实际的替代方案(如果没有其他方法)是构建自己的日期选择器。我在尝试使用 HTML5 颜色选择器时遇到了问题,我没有浪费时间试图强迫它运行,我只是构建了自己的 - 它比 HTML5 版本既令人满意又性感得多。无论如何,我可能会研究“然而”的解决方案——为了好玩。如果我有任何成功,我会发布它。
  • 是的,如果不是因为它在大多数情况下开箱即用的便利性以及我正在做的事情的时间限制,我肯定会走这条路。我构建的附加到它的日历选择器效果很好,它实际上只是与日期选择器本身的交互导致了问题。如果您确实找到了“但是”的解决方案,请随时通知我们,因为我很乐意尝试并打破它.. erm 测试我的意思是 ;)
  • @haxxxton - 可以玩的新玩具。真的很容易坏。享受! ;-)
  • 看起来很有趣,你说得对,它相对容易破解:P 即29/02/2012 然后年份上的向上箭头会导致负年份......就像你提到的那样,这只适用于第一个错误日期.. 真的很感谢你的努力!如果只有一种方法可以检测到按键发生的日期部分:\
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-13
  • 2021-01-06
  • 2020-04-21
  • 2017-07-17
  • 2011-03-30
  • 2013-02-19
相关资源
最近更新 更多