HTML5 类型检测和插件初始化

发布于 2024-10-01 16:33:05 字数 3364 浏览 2 评论 0原文

A 部分:

我知道有很多东西可以告诉您浏览器是否支持特定的 HTML5 属性,例如 http://diveintohtml5.info/detect.html,但它们不会告诉您如何从各个元素获取类型并使用该信息初始化你的插件。

所以我尝试了:

alert($("input:date"));
//returns "[object Object]" 

alert($("input[type='date']")); 
//returns "[object Object]"

alert($("input").attr("type"));
//returns "text" ... which is a lie. it should have been "date"

这些都不起作用。

我最终想出了这个(确实有效):

var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();
alert(inputAttr);
// returns "<input min="-365" max="365" type="date">"

谢谢:http://jquery-howto.blogspot.com/2009/02/how-to-get-full-html-string-include.html

所以我的第一个问题是: 1. 为什么在不支持html5的浏览器中无法读取“type”属性?您可以编造任何其他属性和虚假值并读取它。 2. 为什么我的解决方案有效?为什么它是否在 DOM 中很重要?

B 部分:

下面是我使用检测器的基本示例:

  <script type="text/javascript" >
    $(function () {
    var tM = document.createElement("input");
    tM.setAttribute("type", "date");
        if (tM.type == "text") {
            alert("No date type support on a browser level. Start adding date, week, month, and time fallbacks");
        //   Thanks: http://diveintohtml5.ep.io/detect.html

            $("input").each(function () {
                // If we read the type attribute directly from the DOM (some browsers) will return unknown attributes as text (like the first detection).  Making a clone allows me to read the input as a clone in a variable.  I don't know why.
                var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();

                    alert(inputAttr);

                    if ( inputAttr.indexOf( "month" ) !== -1 )

                    {
                        //get HTML5 attributes from element
                        var tMmindate =  $(this).attr('min');
                        var tMmaxdate =  $(this).attr('max');
                        //add datepicker with attributes support and no animation (so we can use -ms-filter gradients for ie)
                         $(this).datepick({ 
                            renderer: $.datepick.weekOfYearRenderer,
                            onShow: $.datepick.monthOnly,
                            minDate: tMmindate, 
                            maxDate: tMmaxdate, 
                            dateFormat: 'yyyy-mm', 
                            showAnim: ''}); 
                    }
                    else
                    {

                        $(this).css('border', '5px solid red');
                        // test for more input types and apply init to them 
                    }

                });         
            }
        });

        </script>

实例:http://joelcrawfordsmith.com/sandbox/html5-type-detection.html

还有一个恩惠/问题: 谁能帮我减少 HTML5 输入类型修复程序中的一些内容?

我已经关闭了该功能(添加了 IE6-IE8 和 FF 的后备,而不添加要初始化的类)

是否有更有效的方法来迭代神秘输入类型的 DOM? 在我的示例中,我应该使用 If Else、函数还是案例?

谢谢大家,

乔尔

PART A:

I know there are a lot of things out there that tell you if a browser supports a certain HTML5 attribute, for example http://diveintohtml5.info/detect.html, but they don't tell you how to acquire the type from individual elements and use that info to init your plugins.

So I tried:

alert($("input:date"));
//returns "[object Object]" 

alert($("input[type='date']")); 
//returns "[object Object]"

alert($("input").attr("type"));
//returns "text" ... which is a lie. it should have been "date"

None those worked.

I eventually came up with this (that does work):

var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();
alert(inputAttr);
// returns "<input min="-365" max="365" type="date">"

Thanks: http://jquery-howto.blogspot.com/2009/02/how-to-get-full-html-string-including.html

So my first question:
1. Why can I not read the "type" attribute in browsers that don't support html5? You can make up any other attribute and bogus value and read it.
2. Why does my solution work? Why does it matter if its in the DOM or not?

PART B:

Below is a basic example of what I am using the detector for:

  <script type="text/javascript" >
    $(function () {
    var tM = document.createElement("input");
    tM.setAttribute("type", "date");
        if (tM.type == "text") {
            alert("No date type support on a browser level. Start adding date, week, month, and time fallbacks");
        //   Thanks: http://diveintohtml5.ep.io/detect.html

            $("input").each(function () {
                // If we read the type attribute directly from the DOM (some browsers) will return unknown attributes as text (like the first detection).  Making a clone allows me to read the input as a clone in a variable.  I don't know why.
                var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();

                    alert(inputAttr);

                    if ( inputAttr.indexOf( "month" ) !== -1 )

                    {
                        //get HTML5 attributes from element
                        var tMmindate =  $(this).attr('min');
                        var tMmaxdate =  $(this).attr('max');
                        //add datepicker with attributes support and no animation (so we can use -ms-filter gradients for ie)
                         $(this).datepick({ 
                            renderer: $.datepick.weekOfYearRenderer,
                            onShow: $.datepick.monthOnly,
                            minDate: tMmindate, 
                            maxDate: tMmaxdate, 
                            dateFormat: 'yyyy-mm', 
                            showAnim: ''}); 
                    }
                    else
                    {

                        $(this).css('border', '5px solid red');
                        // test for more input types and apply init to them 
                    }

                });         
            }
        });

        </script>

Live example: http://joelcrawfordsmith.com/sandbox/html5-type-detection.html

And a favor/question:
Can anyone help me cut some fat in my HTML5 input type fixer?

I have the functionality down (adds fallbacks to IE6-IE8, and FF with out adding classes to init off of)

Are there are more efficient methods for iterating over the DOM for mystery input types?
And should I be using an If Else, or a function, or a case in my example?

Thanks All,

Joel

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

烟凡古楼 2024-10-08 16:33:06

好吧,我认为这里描述的检测浏览器是否支持日期输入类型的方法太复杂了,如果您想要一种更简单的方法,您可以这样做:

/*
 * Instead of body, you could use the closest parent where you know your input is going to be 
 */
$("body").on("focus", "input[type='date']", function(){
    let attribute, property;
    attribute= $(this).attr("type").toUpperCase();
    property= $(this).prop("type").toUpperCase();
    if(attribute!== property){
        console.log("This browser doe not support type='date'");
        //Pop up your own calendar or use a plugin 
    }
});

一旦您将输入集中到类型上,就会执行此函数="date",如果页面上尚不存在也没关系,听众将一直观看,直到正文上有新的输入[type="date"],但正如评论中所建议的,如果您有您知道的更接近的容器将始终包含输入,那么您可以更改它而不是“主体”。

JS Listener 无论如何都很快

Ok I think that the methods described here to detect if a browser supports the date inpu type are to complicated, if you'd like an easier approach you could just do something like this:

/*
 * Instead of body, you could use the closest parent where you know your input is going to be 
 */
$("body").on("focus", "input[type='date']", function(){
    let attribute, property;
    attribute= $(this).attr("type").toUpperCase();
    property= $(this).prop("type").toUpperCase();
    if(attribute!== property){
        console.log("This browser doe not support type='date'");
        //Pop up your own calendar or use a plugin 
    }
});

This function will be executed once you focus an input with type="date", it doesnt matter if it doesn't exist on the page yet, the listener will be watching until there's a new input[type="date"] on body, but as suggested on the comments, if you have a closer container that you know will always contain the inputs, well you could change it instead of having "body".

JS Listeners are fast anyway

两个我 2024-10-08 16:33:05

检测支持的输入类型的一种更优越的方法是简单地创建一个输入元素并循环所有可用的不同输入类型并检查 type 更改是否持续:

var supported = { date: false, number: false, time: false, month: false, week: false },
    tester = document.createElement('input');

for (var i in supported){
    try {
        tester.type = i;
        if (tester.type === i){
            supported[i] = true;
        }
    } catch (e) {
        // IE raises an exception if you try to set the type to 
        // an invalid value, so we just swallow the error
    }
}

这实际上利用了浏览器的事实不支持该特定输入类型的将回退到使用文本,从而允许您测试它们是否受支持。

例如,您可以使用 supported['week'] 来检查 week 输入类型的可用性,并通过此进行回退。在这里查看一个简单的演示: http://www.jsfiddle.net/yijian/r5Wsa /2/。您还可以考虑使用 Modernizr 进行更强大的 HTML5 功能检测。


最后,无论您相信与否,获取 outerHTML 的更好方法是使用 outerHTML。而不是为什么

var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();

不直接使用:(

var inputAttr = this.outerHTML || new XMLSerializer().serializeToString(this);

是的,如您所见,有一个警告 - Firefox 不支持 outerHTML,因此我们需要一个简单的解决方法,来自 这个堆栈溢出问题)。


编辑:从以下页面找到了一种测试本机表单 UI 支持的方法:http://miketaylr.com/code/html5-forms-ui-support.html。以某种方式支持这些类型的 UI 的浏览器应该还可以防止在这些字段中输入无效值,因此我们上面所做的测试的逻辑扩展如下:

var supported = {date: false, number: false, time: false, month: false, week: false},
    tester = document.createElement('input');

for(var i in supported){
    tester.type = i;
    tester.value = ':(';

    if(tester.type === i && tester.value === ''){
        supported[i] = true;
    }
}

同样,不是 100 %可靠 - 这仅适用于对其值有​​一定限制的类型,并且绝对不是很好,但这是朝着正确方向迈出的一步,并且现在肯定会解决您的问题。

在此处查看更新的演示:http://www.jsfiddle.net/yijian/ r5Wsa/3/

A far superior method for detecting supported input types is to simply create an input element and loop through all of the different input types available and check if the type change sticks:

var supported = { date: false, number: false, time: false, month: false, week: false },
    tester = document.createElement('input');

for (var i in supported){
    try {
        tester.type = i;
        if (tester.type === i){
            supported[i] = true;
        }
    } catch (e) {
        // IE raises an exception if you try to set the type to 
        // an invalid value, so we just swallow the error
    }
}

This actually makes use of the fact that browsers which do not support that particular input type will fall back to using text, thereby allowing you to test if they're supported or not.

You can then use supported['week'], for instance, to check for the availability of the week input type, and do your fallbacks through this. See a simple demo of this here: http://www.jsfiddle.net/yijiang/r5Wsa/2/. You might also consider using Modernizr for more robust HTML5 feature detection.


And finally, a better way to get outerHTML is to, believe it or not, use outerHTML. Instead of

var inputAttr = $('<div>').append($(this).clone()).remove().html().toLowerCase();

Why not just use:

var inputAttr = this.outerHTML || new XMLSerializer().serializeToString(this);

(Yes, as you can see, there is a caveat - outerHTML isn't supported by Firefox, so we're going to need a simple workaround, from this Stack Overflow question).


Edit: Found a method to do testing for native form UI support, from this page: http://miketaylr.com/code/html5-forms-ui-support.html. Browsers that support the UI for these types in some way should also prevent invalid values from been entered into these fields, so the logical extension to the test we're doing above would be this:

var supported = {date: false, number: false, time: false, month: false, week: false},
    tester = document.createElement('input');

for(var i in supported){
    tester.type = i;
    tester.value = ':(';

    if(tester.type === i && tester.value === ''){
        supported[i] = true;
    }
}

Again, not 100% reliable - this is only good for types that have certain restrictions on their values, and definitely not very good, but it's a step in the right direction, and certainly would solve your problem now.

See the updated demo here: http://www.jsfiddle.net/yijiang/r5Wsa/3/

空心空情空意 2024-10-08 16:33:05

请求 type 属性并不适用于所有 Android 原生浏览器。他们假装支持 inputType="date",但他们不提供用于日期输入的 UI(例如日期选择器)。

此功能检测对我有用:

   (function() {
        var el = document.createElement('input'),
            notADateValue = 'not-a-date';
        el.setAttribute('type','date');
        el.setAttribute('value', notADateValue);
        return el.value !== notADateValue;
    })();

技巧是在日期字段中设置非法值。如果浏览器清理此输入,它还可以提供日期选择器。

Asking for the type attribute does not work in all Android stock browsers. They pretend that they support inputType="date", but they do not offer an UI (datepicker e.g.) for date inputs.

This feature detection worked for me:

   (function() {
        var el = document.createElement('input'),
            notADateValue = 'not-a-date';
        el.setAttribute('type','date');
        el.setAttribute('value', notADateValue);
        return el.value !== notADateValue;
    })();

The trick is to set an illegal value into a date field. If the browser sanitises this input, it could also offer a datepicker.

記憶穿過時間隧道 2024-10-08 16:33:05

type 属性不是“虚构”元素,它在此处定义:

http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.4

...浏览器只“知道”那里定义的@type值(除非它们支持 HTML5——它定义了一些新值,如“日期”、“电子邮件”等)

当您查询 type 属性时,某些浏览器会向您返回“文本”,因为如果浏览器不支持“日期”类型(或任何它不理解的内容),然后它会回退到默认值 - 即 type="text"

您是否想过在输入中添加一个类名(class="date"),然后您就可以$('.date').each() 然后你检测该集合

The type attribute isn't a "made-up" element, it's defined here:

http://www.w3.org/TR/REC-html40/interact/forms.html#h-17.4

...and browsers only "know" about the @type values defined there (unless they are HTML5 aware -- which has defined some new values like "date", "email" etc)

When you query the type attribute some browsers return "text" to you because if a browser doesn't support the "date" type (or anything it doesn't understand) then it falls back to the default value -- which is type="text"

Have you thought of adding a classname (class="date") to the inputs as well then you can just $('.date').each() and then do you detection on that set

只有一腔孤勇 2024-10-08 16:33:05

我认为这是 JQuery 中的一个错误!如果您查看 JQuery 代码本身中的 attr() 函数,JQuery 首先尝试使用括号表示法获取您传入的名称的值。如果它不是未定义的,那么它返回该值。如果未定义,则使用 getAttribute() 方法。

Jquery 对 $("#elem").attr(name) 执行类似的操作:

 if (elem[ name ] !== undefined)
 {
    return elem[name];
 }
 else
 {
    return elem.getAttribute( name )
 }

问题是 Jquery 假设如果 elem[name] 不是未定义的,则 elem[name] 是正确的。

考虑以下示例:

<input type="date" id="myInput" name="myInput" joel="crawford" />    

var myInput = document.getElementById('myInput');

alert(myInput['type']);//returns text    
alert(myInput.getAttribute('type'));//returns date
alert($("#myInput").attr('type'));//returns text

alert(myInput['joel']);//returns undefined
alert(myInput.getAttribute('joel'));//returns crawford
alert($("#myInput").attr('joel'));//returns crawford

当您传入 .attr("type") 时,myInput['type'] 返回“text”,因此 Jquery 返回“text”。如果您传入 .attr("joel"),则 myInput['joel'] 返回未定义,因此 Jquery 使用 getAttribute('joel') 代替返回“crawford”。

I would argue this is a bug in JQuery! If you look at the attr() function in the JQuery code itself, JQuery first trys to get a value for the name you passed in using bracket notation. If it is not undefined, then it returns that value. If it is undefined, then it usess the getAttribute() method instead.

Jquery does something similar to this for $("#elem").attr(name):

 if (elem[ name ] !== undefined)
 {
    return elem[name];
 }
 else
 {
    return elem.getAttribute( name )
 }

The problem is Jquery is assuming if elem[name] is not undefined, then elem[name] is correct.

Consider the following example:

<input type="date" id="myInput" name="myInput" joel="crawford" />    

var myInput = document.getElementById('myInput');

alert(myInput['type']);//returns text    
alert(myInput.getAttribute('type'));//returns date
alert($("#myInput").attr('type'));//returns text

alert(myInput['joel']);//returns undefined
alert(myInput.getAttribute('joel'));//returns crawford
alert($("#myInput").attr('joel'));//returns crawford

When you pass in .attr("type"), myInput['type'] returns "text", so Jquery returns "text". If you passed in .attr("joel"), myInput['joel'] returns undefined, so then Jquery uses getAttribute('joel') instead which returns "crawford".

这个俗人 2024-10-08 16:33:05

您无法在不支持此功能的浏览器中获取 type="date"。如果浏览器检测到它不理解的类型属性,则会使用 type="text" (默认)覆盖它。

解决这个问题的方法(使用 jQuery)就是简单地添加类日期。

然后你可以做类似的事情

$('input.date').each(function() {
    var $this = $(this);
    if($this.attr('type') != 'date') $this.datepicker();
});

You cannot get type="date" in a browser that doesn't support this. If a browser detects a type-attribute it doesn't understand it overrides it with the type="text" (default).

A way around this (using jQuery) is simply to add the class date as well.

Then you can do something like

$('input.date').each(function() {
    var $this = $(this);
    if($this.attr('type') != 'date') $this.datepicker();
});
2024-10-08 16:33:05

只是 tester.type = i; 在 IE 中抛出异常。固定版本:

var get_supported_html5_input_types = function() {
    var supported = {
            date: false,
            number: false,
            time: false,
            datetime: false,
            'datetime-local':false,
            month: false,
            week: false
        },
        tester = document.createElement('input');
    for(var i in supported){
        // Do nothing - IE throws, FF/Chrome just ignores
        try { tester.type = i; } catch (err) {}
        if(tester.type === i){
            supported[i] = true;
        }
    }
    return supported;
};

console.log(get_supported_html5_input_types());

永远测试,永远不要盲目复制粘贴!

Just tester.type = i; throws exception in IE. Fixed version:

var get_supported_html5_input_types = function() {
    var supported = {
            date: false,
            number: false,
            time: false,
            datetime: false,
            'datetime-local':false,
            month: false,
            week: false
        },
        tester = document.createElement('input');
    for(var i in supported){
        // Do nothing - IE throws, FF/Chrome just ignores
        try { tester.type = i; } catch (err) {}
        if(tester.type === i){
            supported[i] = true;
        }
    }
    return supported;
};

console.log(get_supported_html5_input_types());

Always test, never blindly copy-paste !

海风掠过北极光 2024-10-08 16:33:05

下面是一个 jQuery 脚本,用于检测浏览器是否支持 HTML5 date 格式,如果支持,它将所有 date 字段值更改为 yyyy-mm-dd > 格式,并将所有 datetime 字段值设置为 yyyy-mm-dd hh:mm:ss 格式。

// From https://stackoverflow.com/a/10199306
// If the browser supports HTML5 input type="date", change all the values from y/m/dddd format to yyyy-mm-dd format, so they appear properly:
function fix_date_inputs() {
    try {
        var input = document.createElement('input');
        input.setAttribute('type','date');

        var notADateValue = 'not-a-date';
        input.setAttribute('value', notADateValue); 

        var r = (input.value !== notADateValue);

        if ( r ) {
            $( 'input' ).each( function() {
                if (
                    $(this).attr( 'type' ).match( /^date/ ) // date or datetime
                ) {
                    var m_d_y = $(this).context.attributes.value.value; // Because $(this).val() does not work (returns '')

                    var d = new Date( m_d_y );

                    var month = '' + (d.getMonth() + 1);
                    var day = '' + d.getDate();
                    var year = d.getFullYear();

                    if (month.length < 2) month = '0' + month;
                    if (day.length < 2) day = '0' + day;

                    var yyyy_mm_dd = [ year, month, day ].join( '-' );

                    // If we're processing a datetime, add the time:
                    if (
                        $(this).attr( 'type' ) == 'datetime'
                    ) {
                        var h = '' + d.getHours();
                        var i = '' + d.getMinutes();
                        var s = '' + d.getSeconds();

                        if (h.length < 2) h = '0' + h;
                        if (i.length < 2) i = '0' + i;
                        if (s.length < 2) s = '0' + s;

                        yyyy_mm_dd += ' ' + [ h, i, s ].join( ':' );
                    }

                    $(this).val( yyyy_mm_dd ); // Here, val() works to set the new value. Go figure.
                }
            });

        }
    } catch( e ) {
        alert( 'Internal error: ' + e.message );
    }
}

Here's a jQuery script that detects whether the browser supports HTML5 date format, and if so, it changes all date field values to yyyy-mm-dd format, and all datetime field values to yyyy-mm-dd hh:mm:ss format.

// From https://stackoverflow.com/a/10199306
// If the browser supports HTML5 input type="date", change all the values from y/m/dddd format to yyyy-mm-dd format, so they appear properly:
function fix_date_inputs() {
    try {
        var input = document.createElement('input');
        input.setAttribute('type','date');

        var notADateValue = 'not-a-date';
        input.setAttribute('value', notADateValue); 

        var r = (input.value !== notADateValue);

        if ( r ) {
            $( 'input' ).each( function() {
                if (
                    $(this).attr( 'type' ).match( /^date/ ) // date or datetime
                ) {
                    var m_d_y = $(this).context.attributes.value.value; // Because $(this).val() does not work (returns '')

                    var d = new Date( m_d_y );

                    var month = '' + (d.getMonth() + 1);
                    var day = '' + d.getDate();
                    var year = d.getFullYear();

                    if (month.length < 2) month = '0' + month;
                    if (day.length < 2) day = '0' + day;

                    var yyyy_mm_dd = [ year, month, day ].join( '-' );

                    // If we're processing a datetime, add the time:
                    if (
                        $(this).attr( 'type' ) == 'datetime'
                    ) {
                        var h = '' + d.getHours();
                        var i = '' + d.getMinutes();
                        var s = '' + d.getSeconds();

                        if (h.length < 2) h = '0' + h;
                        if (i.length < 2) i = '0' + i;
                        if (s.length < 2) s = '0' + s;

                        yyyy_mm_dd += ' ' + [ h, i, s ].join( ':' );
                    }

                    $(this).val( yyyy_mm_dd ); // Here, val() works to set the new value. Go figure.
                }
            });

        }
    } catch( e ) {
        alert( 'Internal error: ' + e.message );
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文