JS实现网站点击事件的统计功能

JS实现网站点击事件的统计功能。

/** 
 * 点击事件上报,分为立即上报和延时上报,延时上报通过cookie存储。 
 *  
 * 一、配置参数,主要用于定义上报的一些配置信息。通过在外部定义_clickc对象重置参数。 
 *     参数名称       类型          默认值             说明 
 *     selector:      string        '_click_rp'        点击触发的选择器,支持ID、class 
 *     prefix:        string        '_rp_'             需要上报的参数属性名前缀,如_rp_type,表示要上报type参数的值 
 *     cookie:        string        '_click_rp'        延迟上报时的cookie名称 
 *     domain:        string        '.skye.com'    cookie存储的域名(可以通过使用的网站来获得) 
 *     delay:         boolean       false              是否延迟上报,延迟上报通过cookie实现 
 *     delay_attr:    string        _delay             标签中指定是否延迟上报,优先级最高,ture延时,其他不延时。 
 *      
 * 二、外部参数,主要用于定义上报的参数。通过在外部定义_clickq数组增加参数。 
 * 
 * 三、标签参数,使用前缀_rp_定义,上报的时候会将所有_rp_开头的参数上报。参数的格式分为两种,1种纯字符,1中回调函数。 
 * <a class="_click_rp" href="" _rp_a="aa" _rp_b="bb">a</a>,表示上报时的参数为a=aa&b=bb 
 * 1,纯字符,直接定义字符,表示需要上传参数的值。 
 * 2,回调函数,以javascript:开头。只需定义函数体,在函数体中返回参数的值。 
 * 如,<a href="/qa_question/press.html" id="ques_search_btn" class="_click_rp" _rp_act="javascript:if($('#ques_search_btn').text()=='提问'){return 'act_qa_ques';}else{return 'act_search';}"><span>提问</span></a> 
 * 
 * 四、延时上报,分为三种优先级,如下由高到低 
 * 1,标签属性_delay是否指定为true,如果是表示延迟上报。 
 * 2,是否为特定标签,如a标签本窗口打开(target等于"_self"或空),submit按钮。 
 * 3,配置参数中指定的delay参数。 
 *  
 * 五、支持:需要依赖jQuery插件。 
 *  
 * 六、使用案列 
 * 1,引入JS 
 * var _clickq = _clickq || []; 
 * _clickq.push(['param1', 'value1']); 
 * var _clickc = {selector:'_click_rps'}; 
 * (function() { 
 *  var click = document.createElement("script"); 
 *  click.src = "//cache.skye.com/js/lib/stat/click.js"; 
 *  var s = document.getElementsByTagName("script")[0];  
 *  s.parentNode.insertBefore(click, s); 
 * })(); 
 *  
 * 2,定义选择器和上传参数 
 * 如,<a class="_click_rp" href="" _rp_a="aa" _rp_b="bb">a</a> 
 */  
(function () {  
    // 默认参数  
    var options = {  
        selector: '_click_rp',  
        prefix: '_rp_',  
        cookie: '_click_rp',  
        domain: '.skye.com',  
        delay: false,  
        delay_attr: '_delay'  
    };  
  
    var params = {};  
    var _params = {};  
    var clickObj = null; // 当前点击对象  
  
    // 获得对象  
    var getObject = function(selector) {  
        if (typeof(selector) == 'object') {  
            return selector;  
        } else {  
            var obj = $('#'+selector);  
            if (obj.length) {  
                return obj;  
            }  
            obj = $('.'+selector);  
            if (obj.length) {  
                return obj;  
            }  
            return null;  
        }  
    }  
    // 获得选择器  
    var getSelector = function(selector) {  
        return '#' + selector + ',.' + selector;  
    }  
    // 操作cookie函数  
    var getCookie = function(c_name) {  
        if (document.cookie.length>0) {  
            c_start = document.cookie.indexOf(c_name + "=")  
            if (c_start!=-1) {   
                c_start=c_start + c_name.length+1   
                c_end=document.cookie.indexOf(";",c_start)  
                if (c_end==-1) c_end=document.cookie.length  
                return unescape(document.cookie.substring(c_start,c_end))  
            }  
        }  
        return "";  
    }  
    var setCookie = function(c_name,value,expiredays,path,domain) {  
        var exdate = new Date()  
        exdate.setDate(exdate.getDate()+expiredays)  
        var cookie = c_name+ "=" +escape(value)+((expiredays==null) ? "" : ";expires="+exdate.toGMTString());  
        if (path) cookie = cookie + ";path=" + path;  
        if (domain) cookie = cookie + ";domain=" + domain;  
        document.cookie = cookie;  
    }  
  
    // 获得标签中的参数  
    var getAttrParam = function() {  
        if ( clickObj ) {  
            var attrs = clickObj.get(0).attributes;  
            $.each(attrs, function(i) {  
                var name = attrs[i].name;  
                if ( name.indexOf(options.prefix) == 0 ) {  
                    name = name.replace(options.prefix, '');  
                    var value = attrs[i].value;  
                    if ( value.indexOf('javascript:') == 0 ) {  
                        // 执行js获得参数值  
                        value = value.replace('javascript:', '');  
                        eval('var valFun = function() {'+ value +'};');  
                        value = valFun();  
                    }  
                    params[name] = value;  
                }  
            });  
        }  
    }  
    // 获得默认参数  
    var getDefaultParam = function() {  
        if(document) {  
            params.url = document.URL || '';  
            params.referrer = document.referrer || '';  
        }  
        // 时间  
        var date = new Date();  
        params.ltime = date.getTime() / 1000;  
  
        // 时间戳  
        params.t = date.getTime();  
    }  
    var getParamStr = function() {  
        getAttrParam();  
        getDefaultParam();  
        // 合并配置参数  
        for(var key in _params) {  
            params[key] = _params[key];  
        }  
        //拼接参数串  
        var args = '';   
        for(var i in params) {  
            if(args != '') {  
                args += '&';  
            }     
            args += i + '=' + encodeURIComponent(params[i]);  
        }  
        return args;  
    }  
  
    // 清空参数  
    var clearParam = function() {  
        params = {};  
    }  
  
    // 是否立即上报,如果跳转页面,则计入延时上报  
    var getIsDelay = function() {  
        if ( clickObj ) {  
            // 有具体指定  
            if ( clickObj.attr(options.delay_attr) == 'true' ) {  
                return true;  
            }  
            // 特定标签  
            // a标签  
            if ( clickObj.is('a') ) {  
                if ( clickObj.attr('href').indexOf('javascript:') == 0 ) {  
                    return false;  
                }  
                if ( clickObj.attr('target') && clickObj.attr('target') != '_self' ) {  
                    return false;  
                }  
                return true;  
            }  
            // submit按钮  
            if ( (clickObj.is('input') || clickObj.is('button')) && clickObj.attr('type') == 'submit' ) {  
                return true;  
            }  
        }  
        return options.delay;  
    }  
      
    // 加入cookie,下次上报  
    var setDelayCookie = function() {  
        // 获得参数  
        var args = getParamStr();  
        var cookieStr = getCookie(options.cookie);  
        if ( cookieStr == '' ) {  
            cookieStr = args;  
        } else {  
            cookieStr = cookieStr + ',' + args;  
        }  
        setCookie(options.cookie, cookieStr, 7, '/', options.domain);  
        clearParam();  
    }  
  
    // 上报cookie  
    var rpCookie = function() {  
        // 获得cookie,循环操作  
        var cookieStr = getCookie(options.cookie);  
        if ( cookieStr ) {  
            var cookieArr = cookieStr.split(',');  
            for(var key in cookieArr){    
                rpClick(cookieArr[key]);  
            }    
            setCookie(options.cookie, '', 7, '/', options.domain);  
        }  
    }  
  
    // 上报  
    var rpClick = function(args) {  
        if ( args == undefined ) {  
            args = getParamStr();  
        }  
        var img = new Image(1, 1);  
        img.src = 'http://data.skye.com/stat/click?' + args;  
        console.info(img.src);  
        clearParam();  
    }  
  
    // js上报函数  
    var rpComm = function(obj) {  
        console.info('click');  
        clickObj = obj;  
        if ( getIsDelay() ) {  
            setDelayCookie();  
        } else {  
            rpClick();  
        }  
    }  
  
    //解析外部配置  
    if(_clickc) {  
        for(var i in _clickc) {  
            options[i] = _clickc[i];  
        }     
    }  
      
    //解析外部参数  
    if(_clickq) {  
        for(var i in _clickq) {  
            _params[_clickq[i][0]] = _clickq[i][1];  
        }  
    }  
  
    // 提供外部js函数  
    $.rpComm = function(obj) {  
        rpComm(obj);  
    }  
    $.fn.rpComm = function() {  
        rpComm($(this));  
    }  
  
    // cookie中的上报  
    rpCookie();  
  
    // 初始化信息  
    var _time = new Date().valueOf();  
    var selector = getSelector(options.selector);  
    $('body').delegate(selector,'click',function() {  
        // 连续点击限制  
        if(new Date().valueOf() - _time < 300) {  
            return;  
        }  
        _time = new Date().valueOf();  
        rpComm($(this));  
    });  
})();  


网站分析统计JS源码分享

之前公司做了一个分析云平台,用来跟踪收集海量的用户行为的相关数据,供运营人员实时监控网站访问量,统计PV,UV,独立IP,访问时段,访问时长,热点追踪等多类信息,我用JS写了一个小插件,只需要再页面加载这个js文件即可,供有需要的朋友参考,该插件分为两部分组成,一部分是分析的主JS,另一部分功能是用来提供热点地图绘制信息。

/**

  • 分析主JS,该JS部署时放在页面</boday>标签之前,所有引入的其他JS位置之后
  • 该JS文件会自动加载hot.js文件,进行行为追踪,无需配置。
  • 配置说明:
  • 如果追踪页面加载速度,需要在页面标签<head>内靠前位置Javascript语句块中嵌入代码: var _speedMark = new Date(); 如不配置,该功能不可用,这种方式实现比较传统,为的是兼容更多的浏览器,如果只考虑高版本的浏览器,可以用很简单很直接的方式来解决。这里就不累赘讲述了。
    */

/参数说明

  • bs 浏览器及版本,中间固定用“/”隔开: 如 Firefox/29
  • fl Flash版本:如 13.0 r0
  • hp 是否设置为首页,y表是,否则为空
  • jv 是否禁用脚本:0表否,1表是
  • lg 浏览器语言:如 zh-cn
  • ps 页面加载用时:如 271 单位为毫秒,如没配置该属性,ps没值,网页首次加载有值,其它情况下值为0
  • pvi 用户标识:如 5699369775 第一次访问页面时产生,只要用户不清除客户端cookie,该值永远存在
  • rurl 上一个页面地址
  • scl 屏幕颜色深度:如 24-bit
  • scr 屏幕分辨率: 如 1600x900
  • sh 滚动条可滚动高度:如 3259
  • si 本地一次会话标识: 如 s479879256
  • tz 区时:如 8
  • ui 登陆的用户ID,未登陆时没有该值:如 7155113994790596
  • url 当前的URL
  • x 鼠标点击事件时,相对body中轴线的x坐标, 中轴线左边为负,右边为正,此值只有开启热点追踪时才会产生,页面初始化时无值
  • y 鼠标点击事件时的y坐标,此值只有开启热点追踪时才会产生,页面初始化时无值
    *

参数说明/

/使用方法
*

  • 配置方式:
  • 在页面</body>标签之前其他外部文件引入之后的位置加入该js引用
    *
  • <script type="text/javascript" src ="ea.js" > </script>
    *

使用方法/

; (function () {
    function ea() {
        this.url = [];
        this.init()
    }
    var h, k, j, l, p, r, q, n, m, o,
        f = {};
    ea.prototype = {
        init: function () {
            f ? l = f : l = {};
            h = document;
            k = h.location;
            j = h.body;
            m = navigator;
            p = m.platform;
            q = this.getCookieSetDomain();
        },
        run: function () {
            g.init();
            this.url.push(this.getUrl());
            this.url.unshift("http://180.163.187.8:1080/go.php?");
            this.url.push(this.getRefInfo());
            this.url.push(this.getPvi());
            this.url.push(this.getSi());
            this.url.push(this.getMainEnvInfo());
            this.url.push(this.getExtendEnvInfo());
            this.url.push(this.getBrowserInfo());
            this.url.push(this.getPageSpeed());
            this.url.push(this.getScrollHeight());
            this.url.push(this.getUi());
            g.save();
            this.sendInfo(this.url.join(""));
            //this.loadHotClick(this);
        },
        loadHotClick: function (a) {
            u && u.getScript({
                url: "hot.js",
                callback: function () {
                    (new hot(a)).watchClick();
                }
            })
        },
        inArray: function (a, c) {
            for (i = 0; i < a.length && a[i] != c; i++);
            return i != a.length;
        },
        getUi: function () {
            var a = "",
                b = "";
            a = unescape(g.get("pi=", !0));

            if ("-" != a) {
                for (var a = a.split(";"), c = 0; c < a.length; c++) {
                    b = a[c];
                    break;
                }
            }
            return "&ui=" + b;

        },
        getUrl: function () {
            return "&url=" + escape(h.URL);
        },
        getRefInfo: function () {
            return "&rurl=" + escape(h.referrer.substr(0, 100));
        },
        getPageSpeed: function () {
            return "undefined" == typeof _speedMark ? "&ps=" : "&ps=" + (new Date - _speedMark);
        },
        getPvi: function () {
            try {
                return m.cookieEnabled ? "&pvi=" + g.setCookie("pgv_pvi", !0) : "&pvi=NoCookie";
            } catch (a) {
                return "&pvi=NoCookie";
            }
        },
        getSi: function () {
            return "&si=" + g.setCookie("ssi");
        },
        getBrowserInfo: function () {
            var a = b.detect();
            return "&os=" + a.os + "&bs=" + a.browser + "/" + a.version;
        },
        getScrollHeight: function () {
            return "&sh=" + Math.max(j.scrollHeight, h.documentElement.scrollHeight);
        },
        getMainEnvInfo: function () {
            var a = "";
            try {
                var c = "-",
                    b = "-",
                    d = "-",
                    e = "-",
                    o = 0;
                self.screen && (c = screen.width + "x" + screen.height, b = (screen.colorDepth || 0) + "-bit");
                m.language ? d = m.language.toLowerCase() : m.browserLanguage && (d = m.browserLanguage.toLowerCase());
                o = m.javaEnabled() ? 1 : 0;
                e = -((new Date).getTimezoneOffset()) / 60;
                a = "&scr=" + c + "&scl=" + b + "&lg=" + d + "&jv=" + o + "&tz=" + e
            } catch (g) { } finally {
                return a
            }
        },
        getExtendEnvInfo: function () {
            var a = "";
            try {
                var c = k.href,
                    b = "",
                    a = a + ("&fl=" + this.getFlashInfo());
                j.addBehavior && (j.addBehavior("#default#homePage"), j.isHomePage(c) && (a += "&hp=y")) || (a += "&hp=");
                j.addBehavior && (j.addBehavior("#default#clientCaps"), b = j.connectionType);
            } catch (d) { } finally {
                return a
            }
        },
        getFlashInfo: function () {
            var a = "-",
                c = navigator;
            try {
                if (c.plugins && c.plugins.length)
                    for (var b = 0; b < c.plugins.length; b++) {
                        if (-1 < c.plugins[b].name.indexOf("Shockwave Flash")) {
                            a = c.plugins[b].description.split("Shockwave Flash ")[1];
                            break
                        }
                    } else if (window.ActiveXObject)
                        for (b = 12; 5 <= b; b--) try {
                            if (eval("new ActiveXObject('ShockwaveFlash.ShockwaveFlash." +
                                b + "');")) {
                                a = b + ".0";
                                break
                            }
                        } catch (d) { }
            } catch (e) { }
            return a
        },
        getParameter: function (a, c) {
            if (a && c) {
                var b = c.match(RegExp("(\\?|#|&)" + a + "=([^&^#]*)(#|&|$)"));
                return b ? b[2] : ""
            }
            return ""
        },
        getCookieSetDomain: function () {
            var a =
                window.location.host,
                c = {
                    "com.cn": 1,
                    "net.cn": 1,
                    "gov,cn": 1,
                    "com.hk": 1
                },
                b = a.split(".");
            2 < b.length && (a = (c[b.slice(-2).join(".")] ? b.slice(-3) : b.slice(-2)).join("."));
            return a
        },
        sendInfo: function (a) {
            n = new Image(1, 1);
            n.onload = n.onerror = function () {   
                n.onload = n.onerror = null;
                n = null;
            }
            n.src = a;
        }
    };
    var u = {
        config: {
            url: "",
            charset: "utf-8",
            callback: function () { }
        },
        merge: function (a, c) {
            for (var b in c) a[b] = c[b];
            return a
        },
        getScript: function (a) {
            var c;
            this.config = this.merge(this.config, a);
            a = document.createElement("script");
            a.setAttribute("type", "text/javascript");
            a.setAttribute("charset", this.config.charset);
            a.setAttribute("src", this.config.url);
            var b = document.getElementsByTagName("script")[0];
            b.parentNode.insertBefore(a, b);
            c = this.config.callback;
            a.onload = a.onreadystatechange = function () {
                ("undefined" == typeof this.readyState || "loaded" == this.readyState || "complete" == this.readyState) && c()
            }
        }
    },
    d = {
        GetRandomNum: function (a, b) {
            var g = b - a;
            var r = Math.random();
            return (a + Math.round(r * g));
        }
    },
    g = {
        sck: [],
        sco: {},
        init: function () {
            var a = this.get("pgv_info=", !0);
            if ("-" != a) {
                for (var a = a.split("&"), c = 0; c < a.length; c++) {
                    var b = a[c].split("=");
                    this.set(b[0], unescape(b[1]))
                }
            }
        },
        get: function (a, c) {
            var b = c ? h.cookie : this.get("pgv_info=", !0),
                d = "-",
                e;
            e = b.indexOf(a);
            if (-1 < e) {
                e += a.length;
                d = b.indexOf(";", e); -1 == d && (d = b.length);
                if (!c) {
                    var f = b.indexOf("&", e); -1 < f && (d = Math.min(d, f))
                }
                d = unescape(b.substring(e, d))
            }
            return d
        },
        set: function (a, c) {
            this.sco[a] = c;
            for (var b = !1, d = this.sck.length, e = 0; e < d; e++)
                if (a == this.sck[e]) {
                    b = !0;
                    break
                }
            b || this.sck.push(a)
        },
        setCookie: function (a, c) {
            var b = g.get(a + "=", c);
            if ("-" == b) {
                c ? b = "" : b = "s";
                var d = (new Date).getUTCMilliseconds(),
                    b = b + Math.round(2147483647 * Math.abs(Math.random() + 1)) * (d + 1) % 1E10
            }
            c ? this.saveCookie(a + "=" + b, "expires=Sun, 18 Jan 2038 00:00:00 GMT;") : this.set(a, b);
            return b
        },
        save: function () {
            if (l.sessionSpan) {
                var a = new Date;
                a.setTime(a.getTime() + 6E4 * l.sessionSpan)
            }
            for (var c = "", b = this.sck.length, d = 0; d < b; d++) c += this.sck[d] + "=" + this.sco[this.sck[d]] + "&";
            c = "pgv_info=" + c.substr(0, c.length - 1);
            b = "";
            a && (b = "expires=" + a.toGMTString());
            this.saveCookie(c, b)
        },
        saveCookie: function (a, c) {
            h.cookie = a + ";path=/;domain=" + q + ";" + c
        }
    },
    b = {
        detect: function () {
            var ret = {
                browser: this.search(this.data.bs),
                version: this.search(navigator.userAgent),
                os: this.search(this.data.os)
            };
            if (ret.os == 'Linux') {
                var distros = ['CentOS', 'Debian', 'Fedora', 'Gentoo', 'Mandriva', 'Mageia', 'Red Hat', 'Slackware', 'SUSE', 'Turbolinux', 'Ubuntu'];
                for (var i = 0; i < distros.length; i++) {
                    if (navigator.userAgent.toLowerCase().match(distros[i].toLowerCase())) {
                        ret.distro = distros[i];
                        break;
                    }
                }
            }
            return ret;
        },
        search: function (data) {
            if (typeof data === "object") {
                for (var i = 0; i < data.length; i++) {
                    var dataString = data[i].string,
                    dataProp = data[i].prop;
                    this.version_string = data[i].versionSearch || data[i].identity;
                    if (dataString) {
                        if (-1 != dataString.indexOf(data[i].subString)) {
                            return data[i].identity;
                        }
                    } else if (dataProp) {
                        return data[i].identity;
                    }
                }
            } else {
                var index = data.indexOf(this.version_string);
                if (index == -1) return;
                return parseFloat(data.substr(index + this.version_string.length + 1));
            }
        },
        data: {
            bs: [
            { string: navigator.userAgent, subString: "Chrome", identity: "Chrome" },
            { string: navigator.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb" },
            { string: navigator.vendor, subString: "Apple", identity: "Safari", versionSearch: "Version" },
            { prop: window.opera, identity: "Opera", versionSearch: "Version" },
            { string: navigator.vendor, subString: "iCab", identity: "iCab" },
            { string: navigator.vendor, subString: "KDE", identity: "Konqueror" },
            { string: navigator.userAgent, subString: "Firefox", identity: "Firefox" },
            { string: navigator.vendor, subString: "Camino", identity: "Camino" },
            { string: navigator.userAgent, subString: "Netscape", identity: "Netscape" },
            { string: navigator.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE" },
            { string: navigator.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv" },
            { string: navigator.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla" }
            ],
            os: [
            { string: navigator.platform, subString: "Win", identity: "Windows" },
            { string: navigator.platform, subString: "Mac", identity: "Mac" },
            { string: navigator.userAgent, subString: "iPhone", identity: "iPhone/iPod" },
            { string: navigator.userAgent, subString: "iPad", identity: "iPad" },
            { string: navigator.userAgent, subString: "Android", identity: "Android" },
            { string: navigator.platform, subString: "Linux", identity: "Linux" }
            ]
        }
    };
    ea && (new ea).run();
})();

第二部分,热点追踪,主要记录鼠标操作的页面位置信息,通过主jS自动加载,当然需要配置,如果不要记录热点追踪,可以在上面主JS配置不要加载。

以下是hot.js文件的内容

/**

  • 热点跟踪js,将通过ea.js按需加载,目前限制了整个文档跟踪,仅仅跟踪html文档中以下几种标签类型:"A"/"IMG"/"INPUT"/"BUTTON"/"SELECT"/"OBJECT"/"TEXTAREA"/"EMBED"
    */
function hot(a) {
    this.t = a
}
hot.prototype = {
    sendHeat: function (a) {
        var b, d = [],
            q = document.body,
            s = document.documentElement;

        if (a.r && 1 == a.r) {
            d.push("&x=" + a.x);
            d.push("&y=" + a.y);
            a = this.t.url.join("") + d.join("");

            b = this.t.getParameter("ps", a);
            a = a.replace("ps=" + b, "" == b ? "ps=" : "ps=0");
            a = a.replace("sh=" + b, "sh=" + Math.max(q && q.scrollHeight, s && s.scrollHeight));
            this.t.sendInfo(a);
        }
    },
    getPos: function (a, d, b, c) {
        var b = b || 0,
            c = c || 0,
            d = d || document,
            e = a || window.event,
            t = e.srcElement || e.target,
            r = 0,
            a = {},
            a = e.pageX || e.pageY ? {
                x: e.pageX,
                y: e.pageY
            } : {
                x: e.clientX + Math.max(d.documentElement.scrollLeft, d.body.scrollLeft) - d.body.clientLeft,
                y: e.clientY + Math.max(d.documentElement.scrollTop, d.body.scrollTop) - d.body.clientTop
            };
        a.x += b;
        a.y += c;
        d = Math.max(Math.max(document.body.clientWidth, document.body.offsetWidth), Math.max(document.body.scrollWidth, document.documentElement.scrollWidth)) / 2;
        a.x = a.x - d + window.screen.width / 2 - (Math.max(document.body.scrollHeight, document.documentElement.scrollHeight) > ("undefined" == typeof window.innerHeight ? document.documentElement.clientHeight : window.innerHeight) ? 8.5 : 0);

        a.x = a.x > d ? a.x - d : -(d - a.x);

        switch (t.tagName) {
            case "A":
            case "IMG":
            case "INPUT":
            case "EMBED":
            case "BUTTON":
            case "SELECT":
            case "OBJECT":
            case "TEXTAREA":
                a.r = 1;
                break;
            default:
                a.r = r;
        }
        return a
    },
    clickHeat: function (a) {
        this.sendHeat(this.getPos(a))
    },
    watchClick: function (a) {
        var d = function (a, b, c) {
            var d = function (a) {
                a = window.event || a;
                target = a.srcElement || a.target;
                c(a, target)
            };
            a.attachEvent ? a.attachEvent("on" + b, d) : a.addEventListener(b, d, !1)
        },
            b = this;
        if (a) b.clickHeat(evt);
        else {
            a = document;
            d(a, "click", function (a) {
                b.sendHeat(b.getPos(a))
            });
            for (var c = a.getElementsByTagName("iframe"), e = 0, a = c.length; e < a; e++) try {
                (function () {
                    var a = c[e],
                        f = a.contentWindow.document;
                    d(f, "click",
                        function (d) {
                            var c = b.getElementPos(a);
                            b.sendHeat(b.getPos(d, f, c.x, c.y))
                        })
                })()
            } catch (f) { }
        }
    },
    getElementPos: function (a) {
        if (null === a.parentNode || "none" == a.style.display) return !1;
        var d = navigator.userAgent.toLowerCase(),
            b = null,
            c = [];
        if (a.getBoundingClientRect) return d = a.getBoundingClientRect(), a = Math.max(document.documentElement.scrollTop, document.body.scrollTop), b = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft), {
            x: d.left + b - document.body.clientLeft,
            y: d.top + a - document.body.clientTop
        };
        if (document.getBoxObjectFor) d = document.getBoxObjectFor(a), c = [d.x - (a.style.borderLeftWidth ? Math.floor(a.style.borderLeftWidth) : 0), d.y - (a.style.borderTopWidth ? Math.floor(a.style.borderTopWidth) : 0)];
        else {
            c = [a.offsetLeft, a.offsetTop];
            b = a.offsetParent;
            if (b != a)
                for (; b;) c[0] += b.offsetLeft, c[1] += b.offsetTop, b = b.offsetParent;
            if (-1 < d.indexOf("opera") || -1 < d.indexOf("safari") && "absolute" == a.style.position) c[0] -= document.body.offsetLeft, c[1] -= document.body.offsetTop
        }
        for (b = a.parentNode ? a.parentNode : null; b && "BODY" !=
            b.tagName && "HTML" != b.tagName;) c[0] -= b.scrollLeft, c[1] -= b.scrollTop, b = b.parentNode ? b.parentNode : null;
        return {
            x: c[0],
            y: c[1]
        }
    }
};
window.hot = hot;

转载http://www.cnblogs.com/allen-tech/p/4737118.html

微信小程序(应用号)来了,开发者准备好了吗?

微信在张小龙眼中是不完美了,或者说是没有达到他的预期的产品。这个过程中的产品演变,慢慢探索的过程也是他不断完善产品,达成自己最初微信设定的一个过程。而这次的应用号就是来扭转这个局面的尝试。

在今年1月11日举行的微信公开课PRO版上,张小龙在演讲中提到:微信的本意并不是要做成一个只是传播内容的平台,而是要做一个提供服务的平台所以微信团队专门拆出了服务号,但服务号以提供服务为主,基于一个诉求,“这不是我们想看到的。现在我们将开发一个新的形态,叫做应用号。”

根据张小龙的描述,应用号的形态大致为:“一种新的公众号形态,这种形态下面用户关注了一个公众号,就像安装了一个APP一样。他要找这个公众号的时候就像找一个APP,在平时这个号不会向用户发东西的,所以APP就会很安静的存在那里,等用户需要的时候找到它就好了,这样的话我们可以尝试做到让更多的APP有一种更轻量的形态,但是又更好使用的一种形态来存在,这是我们在探讨的一种新的公众号形态,叫应用号,这里只是提前剧透一点点东西。”

9月22日凌晨,微信公众平台开始陆续对外发送小程序内测邀请。小程序即被外界广为关注的微信“应用号”。

目前还只是内测阶段,只有少量服务号可以申请内测,用户还无法使用。官方会慢慢扩大内测范围,统一时间开放给客户用。

我理解的应用号也就是 微信规范下的HTML5应用,界面风格统一,功能上借助微信jssdk实现更多的功能扩展,一个轻量化的app。

关于更多看
http://tech.qq.com/a/20160922/000527.htm

为什么要做这个微信小程序?张小龙本来是准备用服务号来解决商家的信息服务问题的,但是商家根本没有玩转或理解张小龙的本意,转而成为商家推广的工具,不断发送消息给用户的一个渠道。即时有的也做了html5相关应用,但是用户体验和应用质量都参差不齐,无法在用户群中形成服务号即提供服务的理念。
这次应用号我推测,1、会取消给用户群发消息的功能,至少不会是发文章的这种方式,最多也就是服务通知类型。2、应用号应该有一个对应的平台,集中展示的地方。让用户形成,哦这里都是服务应用的印象,从而形成使用习惯。3、有先关审核机制,保证应用的质量。虽说张小龙说不是应用分发平台,但是一旦在用户心中形成这就是微信小应用这样的印象,那么应用的数量和质量都会影响整个平台的口碑。

移动端文字垂直居中问题

现象:
在某些手机上,height 和 line-height 设置相同时,文字不垂直居中,文字会偏上一点,height 越小时越明显。尝试多种方法无果,有人说是字体问题,参考其他 UI 框架,也存在此问题。

解决方法:
line-height的兼容问题不太好解决,容器高度越小,显示效果的差距越明显。稍微大一点的高度,最好把line-height设置为高度+1px,两个平台显示都还不错。

参考:
https://segmentfault.com/a/1190000006237977

前端这些年发生了什么?

以下是转自知乎的一个回答,这个回答的问题是“在国内前端领域里优秀的人很多,为什么没人做出 angularjs 、jQuery 之类优秀的框架?”
而我认为这个回答正好回答了前端的发展轨迹,这些框架到底解决了什么问题,给前端新人一个整体上的理解。更好的在学习之前能有个全面了解,不至于盲人摸象。

一个框架能不能火,最关键的不是技术实现上多 nb,而是在于这个框架是否代表了一种(在其所处的时代)先进的开发理念。

举例来说,在大部分开发者都在为浏览器兼容性和设计糟糕的原生 DOM API 叫苦连天的时候,jQuery 的横空出世自然显得光彩夺目。那个年代,大家根本不把前端当应用来写,能爽快的操作 DOM 就已经足够成为王道了。jQuery 简洁的语法,华丽的链式 API,同时掩盖了各种兼容问题,能不火吗?

慢慢地,大家发现前端要做应用,光有华丽的 DOM 操作也不够,还得有应用结构。所以 Backbone 出现了,把 MVX 的概念引入了前端,让大家发现原来前端也是可以有架构的。

再接着,大家发现 Backbone 的视图层依然需要手动侦听 model 的变化做各种 DOM 操作,数据到视图的映射依然繁琐。于是大家开始推崇 MVVM 数据绑定,(其实 Knockout 是和 Backbone 差不多时间出现的,只不过由于其实现不如 Backbone 来得简明易懂,所以不如 Backbone 火),于是 Angular 火了。

不得不承认,即使是放眼全球,前端开发理念相比软件开发的其他领域,也基本上是属于一个跟随的状态。比如最近函数式编程就在对前端开发产生着巨大的冲击 - 首当其冲的就是以幂等渲染函数为核心概念的 React。由于 React 本身的函数式血脉,以它作为渲染层引入其他函数式理念变得触手可及,于是我们看见现在国外前端在研究的都是 immutability, FRP, uni-directional data flow, stateless stores, isomorphic application 之类看上去高大上的话题。

如果你现在去基于一个已经普及的理念新写一个框架,即使实现得再好,也不过是造了一个轮子。当然,造一个同类理念中最好的轮子,还是会有很多人来用,但这毕竟只是一个改进的轮子,大家不会把你当做一个划时代的东西去推崇。只有当你把一个从没在这个领域出现过的理念实现了,才能够达到 jQuery, Backbone, Angular, React 这些里程碑式的框架所达到的地位。(顺便广告下,在前后端数据通信这块,Meteor 可以算是一个里程碑式的存在,Relay 可能是下一个)

所以说到底,能不能搞出风靡的东西,一部分是眼界,一部分是时势。首先只有把眼界开拓到当前领域的边界之外,才可能做出开拓这个领域的东西。国内的前端界目前基本是处于跟随国外前端界的状况(就像国外前端界跟随整个软件开发领域一样),从眼界上来说就差了一个身位,又如何奢求能够做出划时代的东西?

作者:尤雨溪
链接:http://www.zhihu.com/question/30809709/answer/52499916
来源:知乎
著作权归作者所有,转载请联系作者获得授权。