HTML5 类型检测和插件初始化

Posted

技术标签:

【中文标题】HTML5 类型检测和插件初始化【英文标题】:HTML5 Type Detection and Plugin Initialization 【发布时间】:2011-05-08 18:33:02 【问题描述】:

第一部分:

我知道有很多东西可以告诉你浏览器是否支持某个 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-including.html

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

第二部分:

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

  <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、函数还是案例?

谢谢大家,

乔尔

【问题讨论】:

【参考方案1】:

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

/*
 * 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 
    
);

一旦你聚焦一个type="date"的输入,这个函数就会被执行,如果它不存在于页面上也没关系,监听器会一直观察直到有一个新的input[type="date" ] 在 body 上,但正如 cmets 所建议的那样,如果您有一个更接近的容器,并且您知道将始终包含输入,那么您可以更改它而不是使用“body”。

无论如何,JS 监听器都很快

【讨论】:

【参考方案2】:

检测支持的输入类型的一种更好的方法是简单地创建一个输入元素并遍历所有可用的不同输入类型并检查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/yijiang/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,所以我们需要一个简单的解决方法,来自 this Stack Overflow question)。


编辑: 找到了一种方法来测试原生表单 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/yijiang/r5Wsa/3/

【讨论】:

感谢您的详细回复!它提供了非常有用的信息来帮助我通过使用更多的 JS 代替 jQuery 来提高脚本的效率。正是我正在寻找的信息类型。您能否就几个项目向我提供一些澄清?您的输入类型检测代码示例如何允许旧版浏览器使用不受支持的 HTML5 类型属性值?那是我的目标。有效检测不受支持的值......不仅仅是检测支持(就像 Modernizr 那样)。也许我误解了样本的目的。再次感谢! @Joel 它不会尝试模拟旧浏览器的行为,因为您已经正确完成了该部分。这是我认为有问题的特征检测部分 - 我知道您正在尝试为此使用属性选择器,但实际上一般来说这些表单元素有更好的标识符 - 例如,@ 987654337@ 需要@ 987654338@ 上班。在这里解析 input 元素的 HTML 是一个非常肮脏的解决方法。 具有讽刺意味的是,如果浏览器不支持现代浏览器功能(var ... in .. 语法),则用于检测现代浏览器功能的代码不起作用。小提琴不适用于支持输入日期的 IE 11... @9ilsdx9rvj0lo for... in 是非常古老的语法。你在想……的。另外,不,我很确定 IE11 不支持 input type=date caniuse.com/#feat=input-datetime @YiJiang IE11 不支持输入 type=date,但您的测试无法检测到它,因为它无法在 IE11 上执行 :=) 这只是一个旁注【参考方案3】:

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

// From https://***.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 );
    

【讨论】:

【参考方案4】:

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());

始终测试,绝不盲目复制粘贴!

【讨论】:

【参考方案5】:

要求 type 属性不适用于所有 android 库存浏览器。他们假装支持 inputType="date",但不提供用于日期输入的 UI(例如 datepicker)。

这个特征检测对我有用:

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

诀窍是在日期字段中设置非法值。如果浏览器清理了这个输入,它还可以提供一个日期选择器。

【讨论】:

【参考方案6】:

我认为这是 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”。

【讨论】:

【参考方案7】:

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

解决这个问题的一种方法(使用 jQuery)就是添加课程日期。

然后你可以做类似的事情

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

【讨论】:

您实际上可以在 jQuery 中获取 type 属性,这就是我的帖子的内容和证明。我希望有人能解释为什么我们必须执行读取类型属性的技巧。 这不是“获取”类型,而是获取原始 html 并“查看”类型。你无法查询。 我认为你可能错了。在桌面和手机上的 IE11 中,我从使用 jQuery 获取输入类型返回“日期”,但都没有提供平台提供的日期选择器。 是的。但是 afaik,他们仍然“支持”type="date",即使它不提供日期选择器。也许它会进行验证或类似操作...无论如何,我什至不确定规范是否要求在 type="date" 上显示日期选择器。 IE9 不支持输入 type=date,但是 JQuery 会报告 type 属性是 date,所以这个技巧对我来说真的不起作用。【参考方案8】:

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

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

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

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

您是否考虑过将类名 (class="date") 也添加到输入中,然后您只需 $('.date').each() 然后在该集合上进行检测

【讨论】:

哦,当然!我并不是说 type 属性不是真实的。我在问为什么你不能像返回一个组成的属性一样返回类型值。 我曾想过只添加类,但我希望有一个全面的后备。

以上是关于HTML5 类型检测和插件初始化的主要内容,如果未能解决你的问题,请参考以下文章

您如何检测“搜索”HTML5 输入的清除?

ActionScript 3 AS3检测flash播放器类型 - broswer插件,独立,IDE等

推荐一款能检测信用卡卡号的有效性类型等信息的JS插件

Lync 检测并提示安装 LWA 插件

navigtor对象和插件检测

播放html5视频时,火狐浏览器显示MIME类型不支持怎么解决?