畅言

畅言

最近见到别的网站用了畅言服务了,对其js代码比较感兴趣,特记录下来。其实,主要就是看一下,原生的js如果创建dom,加载dom而已,其他的,好像也没有什么特别高深的。

加载畅言

(function(){
  var appid = 'XXXXXX',
  conf = 'prod_XXXXXXXX';
  var doc = document,
  s = doc.createElement('script'),
  h = doc.getElementsByTagName('head')[0] || doc.head || doc.documentElement;
  s.type = 'text/javascript';
  s.charset = 'utf-8';
  s.src =  'http://assets.changyan.sohu.com/upload/changyan.js?conf='+ conf +'&appid=' + appid;
  h.insertBefore(s,h.firstChild);
  window.SCS_NO_IFRAME = true;
})()

上面的代码,没有什么好说的,主要是,使用原生的js创建dom,并加载。另外,使用了闭包防止局部变量泄漏。

上面的代码,使用就是为了加载chqangyan.js脚本而已。具体的代码如下:

(function () {
    var createNs = function () {
        if (window.changyan !== undefined) {
            return;
        } else {
            window.changyan = {};
            window.changyan.api = {};
            window.changyan.api.config = function (conf) {
                window.changyan.api.tmpIsvPageConfig = conf;
            };
            window.changyan.api.ready = function (fn) {
                window.changyan.api.tmpHandles = window.changyan.api.tmpHandles || [];
                window.changyan.api.tmpHandles.push(fn);
            };
        }
    };


    var loadVersionJs = function () {
        var loadJs = function (src, fun) {
            var head = document.getElementsByTagName('head')[0] || document.head || document.documentElement;

            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            script.setAttribute('charset', 'UTF-8');
            script.setAttribute('src', src);

            if (typeof fun === 'function') {
                if (window.attachEvent) {
                    script.onreadystatechange = function () {
                        var r = script.readyState;
                        if (r === 'loaded' || r === 'complete') {
                            script.onreadystatechange = null;
                            fun();
                        }
                    };
                } else {
                    script.onload = fun;
                }
            }

            head.appendChild(script);
        };

        var ver = +new Date() + window.Math.random().toFixed(16);
        var protocol = (('https:' == window.document.location.protocol) ? "https://" : "http://");
        var url = protocol + 'changyan.sohu.com/upload/version-v3.js?' + ver;
        loadJs(url);
    };


    createNs();
    loadVersionJs();
}());

这段代码,执行了两个函数createNsloadVersionJs

  • 分析createNs代码

    变量changyan完全没有必要反复加上window,完全能在最后,再执行一句

    window.changyan = changyan;

    即可完成局部变量的绑定。

  • 分析loadVersionJs代码:

    就是创建script,并绑定script加载完成后的回调函数。其主要目的是,加载version-v3.js。就为了加载,写出了这样的代码,感觉一点也不划算。

    另外,window.attachEvent这个函数好像浏览器已经废弃了,但是,有另外一个函数类似的函数window.addEventListener

那么,接下来,看version-v3.js到底是什么东东。

(function () {
    var loadJs = function (src, fun) {
        var head = document.getElementsByTagName('head')[0] || document.head || document.documentElement;

        var script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.setAttribute('charset', 'UTF-8');
        script.setAttribute('src', src);

        if (typeof fun === 'function') {
            if (window.attachEvent) {
                script.onreadystatechange = function () {
                    var r = script.readyState;
                    if (r === 'loaded' || r === 'complete') {
                        script.onreadystatechange = null;
                        fun();
                    }
                };
            } else {
                script.onload = fun;
            }
        }
        head.appendChild(script);
    };


    var fnGetVersion = function () {
        var version = 'v202011181282';
        if (version.indexOf('##CY') >= 0) {
            version = 'v3-debug-v3';
        }

        return version;
    };


    var fnGetCookie = function (fn) {
        var cb = 'changyan' + Math.floor(Math.random() * 1000 * 1000 * 1000);
        var protocol = (('https:' == window.document.location.protocol) ? "https://" : "http://");
        var api = protocol + 'changyan.sohu.com/debug/cookie?callback=' + cb;

        window[cb] = function (data) {
            var cookie = data && data.cookie || '';
            cookie = cookie.split(';');

            var i, v;
            var map = {};
            for (i = 0; i < cookie.length; i++) {
                v = cookie[i];
                v = v.split('=');
                v[0] = v[0] || '';
                v[1] = v[1] || '';
                v[0] = v[0].replace(/^\s/, '').replace(/\s$/,'');
                v[1] = v[1].replace(/^\s/, '').replace(/\s$/,'');
                if (v[0] !== '') {
                    map[v[0]] = v[1];
                }
            }
            if (typeof fn === 'function') {
                fn(map);
            }
        };

        loadJs(api, function () {
            try {
                delete window.cb;
            } catch (e) {
                window[cb] = undefined;
            }
        });
    };


    var fnInit = function () {
        var config = {};
        config.version = fnGetVersion();
        config.protocol = (('https:' == window.document.location.protocol) ? "https://" : "http://");
        config.res = config.protocol + 'changyan.sohu.com/v3/' + config.version + '/src/';
        config.base = config.protocol + 'changyan.sohu.com/';
        config.api = config.protocol + 'changyan.sohu.com/';

        if (config.protocol === 'https://') {
            config.res = config.protocol + 'changyan.sohu.com/v3/' + config.version + '/src/';
            config.base = config.protocol + 'changyan.sohu.com/';
        }

        fnGetCookie(function (cookie) {
            if (cookie.debug_v3 === 'true') {
                loadJs(config.res + 'lib/sea.v1.2.0.js', function () {
                    seajs.use(config.res + '/adapter.js', function (fn) {
                        fn && fn(config, cookie);
                    });
                });
            } else {
                loadJs(config.res + 'adapter.min.js', function () {
                    var adapter = window.changyan.api.getAdapterModules('adapter.js');
                    adapter(config, cookie);
                });
            }
        });
    };
    fnInit();
}());

上面代码,我实在不想看了,测试啊尤其是加载的script代码,反复出现。