<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml">
<wml xml:lang="zh">
<head>
<meta http-equiv="Content-Type" content="text/vnd.wap.wml; charset=utf-8"/>
<meta http-equiv="Cache-Control" content="no-cache"/></head>
<card title="YUI 读码日记之 YAHOO.env.ua - Gracecode.com">
<p>正如 YAHOO.env.ua 字面所指（ua 就是 <a href="http://www.gracecode.com/Archive/Display/437" title="http://www.gracecode.com/Archive/Display/437">user-agent</a> 的意思），这篇文章主要分析 YUI 如何检测浏览器的类型与版本。有关 YAHOO.en.ua 的文档<a href="http://developer.yahoo.com/yui/docs/YAHOO.env.ua.html" title="http://developer.yahoo.com/yui/docs/YAHOO.env.ua.html">在这里说明</a>。</p>

<p>目前为止，检测浏览器与版本主要有两大主流的做法。其一，就是分析浏览器提供的 user-agent 字符串；其二，就是根据其功能判别。YUI 使用第一种判断方式，也就是分析 user-agent 字符串。</p>

<p>下面是 YUI 相应的代码实现，经过本人精简以后并加了点注释，这段程序在 %BUILD%/yahoo/yahoo.js 中。</p>

<pre>YAHOO.env.ua = function() {
    var o={ie:0, opera:0, gecko:0, webkit:0, mobile: null};
    var ua=navigator.userAgent, m;

    // 是否为基于 KHTML 引擎的浏览器，比如 Konqueror 。
    if ((/KHTML/).test(ua)) {
        o.webkit=1;
    }

    // 检测 Apple 系列的浏览器，包括移动版本
    m=ua.match(/AppleWebKit\/([^\s]*)/);
    if (m&amp;&amp;m[1]) {
        o.webkit=parseFloat(m[1]);

        // YUI 是我见过的唯一一个检测移动浏览器的框架 :^)
        if (/ Mobile\//.test(ua)) {
            o.mobile = &quot;Apple&quot;; // iPhone or iPod Touch
        } else {
            m=ua.match(/NokiaN[^\/]*/);
            if (m) {
                o.mobile = m[0]; // Nokia N-series, ex: NokiaN95
            }
        }
    }

    if (!o.webkit) { // 检测其他浏览器
        // 检测 Opera
        m=ua.match(/Opera[\s\/]([^\s]*)/);
        if (m&amp;&amp;m[1]) {
            o.opera=parseFloat(m[1]);
            // 是否为 Opera 移动版本
            m=ua.match(/Opera Mini[^;]*/);
            if (m) {
                o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
            }
        } else {
            // 检测 IE 和 Mozilla
            m=ua.match(/MSIE\s([^;]*)/);
            if (m&amp;&amp;m[1]) {
                o.ie=parseFloat(m[1]);
            } else {
                m=ua.match(/Gecko\/([^\s]*)/);
                if (m) {
                    o.gecko=1;
                    m=ua.match(/rv:([^\s\)]*)/);
                    if (m&amp;&amp;m[1]) {
                        o.gecko=parseFloat(m[1]);
                    }
                }
            }
        }
    }
    
    return o;
}();</pre><p>根据代码的流程，我们可以很容易理解 YUI 判断浏览器的逻辑。而我在之前也分析过 <a href="http://www.gracecode.com/Archive/Display/696" title="http://www.gracecode.com/Archive/Display/696">jQuery 在这方面是如何做的</a>，可以对比参照下。</p>

<p>从代码量上考虑，jQuery 的代码是非常的精简的，而 YUI “看起来”更像是我们平常一般的写法：保守、但是有效。而我个人更倾向于 jQuery 的写法，当然 YUI 这这样的判断流程自然也是有它的道理的。</p>

<p>请允许我多事一下，下面是本人根据 jQuery 的代码“重写” YUI 的 YAHOO.env.ua ，让大家见笑了。</p>

<pre>YAHOO.env.ua = function() {
    var ua = navigator.userAgent.toLowerCase();
    var version = (ua.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1];
    return {
        webkit: /webkit/.test(ua) ? version : 0,
        opera: /opera/.test(ua) ? version : 0,
        ie: /msie/.test(ua) &amp;&amp; !/opera/.test(ua) ? version : 0,
        gecko: /mozilla/.test(ua)&amp;&amp;!/(compatible|webkit)/.test(ua) ? version : 0,
        mobile: / mobile\//.test(ua) || ua.match(/nokian[^\/]*/) || 
                                       ua.match(/opera mini[^;]*/) ? version : 0
    };
}();</pre>
<p>
<a href="http://www.gracecode.com/wap/">Gracecode.com</a> |
<a href="http://www.gracecode.com/wap/d/1013 ">Permalink</a>(<a href="http://www.gracecode.com/Archive/Display/1013 ">xHTML</a>) |
<a href="http://www.gracecode.com/Trackback/Recieve/1013/hhu48i">Trackback</a> |
<a href="http://rss.gracecode.com">Rss</a>
</p>
</card>
</wml>