mass Framework event模块 v5

主要改动以下:

  1. css_fix去掉对auto的处理
  2. 为了提高性能,内部使用getter, getStyle进行快速取样式精确值
  3. 利用css3 calc函数进行增量或减量的样式设置
  4. 为cssNumber添加两个新成员
  5. 尝式使用Shadow DOM获取默认样式值

css.js

define("css", top.getComputedStyle ? ["$node"] : ["$css_fix"], function($) {
    var adapter = $.cssHooks || ($.cssHooks = {}),
        rrelNum = /^([\-+])=([\-+.\de]+)/,
        rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
        cssTransform = $.cssName("transform");
    //这里的属性不需要自行添加px
    $.cssNumber = $.oneObject("columnCount,fillOpacity,fontSizeAdjust,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom,rotate");
    //有关单位转换的 http://heygrady.com/blog/2011/12/21/length-and-angle-unit-conversion-in-javascript/
    if(window.getComputedStyle) {
        $.getStyles = function(node) {
            return window.getComputedStyle(node, null);
        }
        adapter["_default:get"] = function(node, name, styles) {
            var ret, width, minWidth, maxWidth
            styles = styles || getStyles(node);
            if(styles) {
                ret = name == "filter" ? styles.getPropertyValue(name) : styles[name]
                var style = node.style; //这里只有firefox与IE10会智能处理未插入DOM树的节点的样式,它会自动打内联样式
                if(ret === "" && !$.contains(node.ownerDocument, node)) {
                    ret = style[name]; //其他需要我们手动取内联样式
                }
                //  Dean Edwards大神的hack,用于转换margin的百分比值为更有用的像素值
                // webkit不能转换top, bottom, left, right, margin, text-indent的百分比值
                if(/^margin/.test(name) && rnumnonpx.test(ret)) {
                    width = style.width;
                    minWidth = style.minWidth;
                    maxWidth = style.maxWidth;

                    style.minWidth = style.maxWidth = style.width = ret;
                    ret = styles.width;

                    style.width = width;
                    style.minWidth = minWidth;
                    style.maxWidth = maxWidth;
                }
            }
            return ret;
        }
    }
    var getStyles = $.getStyles;
    delete $.getStyles;
    //用于性能优化,内部不用转换单位,属性名风格及进行相对赋值,远比调用$.css高效
    var getter = adapter["_default:get"];

    function parseNumber(styles, name) {
        return parseFloat(styles[name]) || 0;
    }

    adapter["zIndex:get"] = function(node) {
        while(node.nodeType !== 9) {
            //即使元素定位了,但如果zindex设置为"aaa"这样的无效值,浏览器都会返回auto;
            //如果没有指定zindex值,IE会返回数字0,其他返回auto
            var position = getter(node, "position") || "static";
            if(position !== "static") {
                // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
                var value = parseInt(getter(node, "zIndex"), 10);
                if(!isNaN(value) && value !== 0) {
                    return value;
                }
            }
            node = node.parentNode;
        }
        return 0;
    }
    adapter["_default:set"] = function(node, name, value) {
        node.style[name] = value;
    }
    // 获取CSS3变形中的角度
    adapter["rotate:get"] = function(node) {
        return $._data(node, 'rotate') || 0;
    }
    if(cssTransform) {
        adapter["rotate:set"] = function(node, name, value) {
            $._data(node, 'rotate', value);
            node.style[cssTransform] = 'rotate(' + (value * Math.PI / 180) + 'rad)';
        }
    }

    var supportBoxSizing = $.cssName("box-sizing");
    adapter["boxSizing:get"] = function(node, name) {
        return supportBoxSizing ? getter(node, name) : document.compatMode == "BackCompat" ? "border-box" : "content-box"
    }

    $.css = function(node, name, value, styles) {
        if(node.style) { //注意string经过call之后,变成String伪对象,不能简单用typeof来检测
            var prop = $.String.camelize(name)
            name = $.cssName(name);
            styles = styles || getStyles(node);
            if(value === void 0) { //获取样式
                return(adapter[prop + ":get"] || getter)(node, name, styles);
            } else { //设置样式
                var type = typeof value,
                    temp;
                if(type === "string" && (temp = rrelNum.exec(value))) {
                    if($.support.calc && name in styles) {
                        //在firefox18, ie10中必须要求运算符两边都有空白才生效
                        var cur = styles[name],
                            unit = (cur.match(/[a-z%]+$/) || [""])[0];
                        return node.style[name] = $.support.calc + "(" + [styles[name], temp[1], temp[2] + unit].join(" ") + ")";
                    } else {
                        value = (+(temp[1] + 1) * +temp[2]) + parseFloat($.css(node, name, void 0, styles));
                        type = "number";
                    }
                }
                if(type === "number" && !isFinite(value + "")) { //因为isFinite(null) == true
                    return;
                }
                if(type === "number" && !$.cssNumber[prop]) {
                    value += "px";
                }
                if(value === "" && !$.support.cloneBackgroundStyle && name.indexOf("background") === 0) {
                    node.style[name] = "inherit";
                }
                (adapter[prop + ":set"] || adapter["_default:set"])(node, name, value, styles);
            }
        }
    }

    $.fn.css = function(name, value) {
        return $.access(this, name, value, $.css);
    }
    var cssPair = {
        Width: ['Left', 'Right'],
        Height: ['Top', 'Bottom']
    }
    var cssShow = {
        position: "absolute",
        visibility: "hidden",
        display: "block"
    }

    function showHidden(node, array) {
        //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
        if(node && node.nodeType == 1 && node.offsetWidth == 0) {
            if(getter(node, "display") == "none") {
                var obj = {
                    node: node
                }
                for(var name in cssShow) {
                    obj[name] = node.style[name];
                    node.style[name] = cssShow[name];
                }
                array.push(obj);
            }
            showHidden(node.parentNode, array);
        }
    }


    function setWH(node, name, val, extra) {
        var which = cssPair[name],
            styles = getStyles(node);
        which.forEach(function(direction) {
            if(extra < 1) val -= parseNumber(styles, 'padding' + direction);
            if(extra < 2) val -= parseNumber(styles, 'border' + direction + 'Width');
            if(extra === 3) {
                val += parseFloat(getter(node, 'margin' + direction, styles)) || 0;
            }
            if(extra === "padding-box") {
                val += parseNumber(styles, 'padding' + direction);
            }
            if(extra === "border-box") {
                val += parseNumber(styles, 'padding' + direction);
                val += parseNumber(styles, 'border' + direction + 'Width');
            }
        });
        return val
    }

    function getWH(node, name, extra) { //注意 name是首字母大写
        var hidden = [];
        showHidden(node, hidden);
        var val = setWH(node, name, node["offset" + name], extra);
        for(var i = 0, obj; obj = hidden[i++];) {
            node = obj.node;
            for(name in obj) {
                if(typeof obj[name] == "string") {
                    node.style[name] = obj[name];
                }
            }
        }
        return val;
    }

    //========================= 处理 width, height, innerWidth, innerHeight, outerWidth, outerHeight ========
    "Height,Width".replace($.rword, function(name) {
        var lower = name.toLowerCase(),
            clientProp = "client" + name,
            scrollProp = "scroll" + name,
            offsetProp = "offset" + name;
        $.cssHooks[lower + ":get"] = function(node) {
            return getWH(node, name, 0) + "px"; //添加相应适配器
        }
        $.cssHooks[lower + ":set"] = function(node, nick, value) {
            var box = $.css(node, "box-sizing"); //nick防止与外面name冲突
            node.style[nick] = box == "content-box" ? value : setWH(node, name, parseFloat(value), box) + "px";
        }
        "inner_1,b_0,outer_2".replace($.rmapper, function(a, b, num) {
            var method = b == "b" ? lower : b + name;
            $.fn[method] = function(value) {
                num = b == "outer" && value === true ? 3 : num;
                return $.access(this, num, value, function(node, num, size) {
                    if($.type(node, "Window")) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
                        return node["inner" + name] || node.document.documentElement[clientProp];
                    }
                    if(node.nodeType === 9) { //取得页面尺寸
                        var doc = node.documentElement;
                        //FF chrome    html.scrollHeight< body.scrollHeight
                        //IE 标准模式 : html.scrollHeight> body.scrollHeight
                        //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
                        return Math.max(
                        node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]);
                    } else if(size === void 0) {
                        return getWH(node, name, num)
                    } else {
                        return num > 0 ? this : $.css(node, lower, size);
                    }
                }, this)
            }
        })

    });
    //========================= 生成 show hide toggle =========================
    var cacheDisplay = $.oneObject("a,abbr,b,span,strong,em,font,i,img,kbd", "inline"),
        blocks = $.oneObject("div,h1,h2,h3,h4,h5,h6,section,p", "block"),
        sandbox, sandboxDoc
        shadowRoot, shadowDoc, shadowBody, shadowWin, reuse
        $.applyShadowDOM = function(callback) {
            //用于提供一个沙箱环境,IE6-10,opera,safari,firefox使用iframe, chrome20+使用Shodow DOM
            if(!shadowRoot) {
                if(window.WebKitShadowRoot) { //如果支持WebKitShadowRoot
                    shadowRoot = new WebKitShadowRoot($.html);
                    shadowBody = document.createElement("div");
                    shadowBody.style.cssText = "0px;height:0px;"
                    shadowRoot.appendChild(shadowBody);
                } else {
                    shadowRoot = document.createElement("iframe");
                    shadowRoot.frameBorder = shadowRoot.width = shadowRoot.height = 0;
                }
            }
            if(shadowRoot.nodeType == 1) {
                $.html.appendChild(shadowRoot);
                if(!reuse) { //firefox, safari, chrome不能重用shadowDoc,shadowWin
                    shadowDoc = shadowRoot.contentDocument || shadowRoot.contentWindow.document;
                    shadowWin = shadowDoc.defaultView || shadowDoc.parentWindow;
                    shadowDoc.write("<!doctype html><html><body>");
                    shadowDoc.close();
                    reuse = window.VBArray || window.opera; //opera9-12, ie6-10有效
                }
                callback(shadowWin, shadowDoc, shadowDoc.body);
                $.html.removeChild(shadowRoot);
            } else {
                callback(window, document, shadowBody);
                shadowBody.innerHTML = "";
            }
        }
    $.mix(cacheDisplay, blocks);
    $.parseDisplay = function(nodeName) {
        nodeName = nodeName.toLowerCase();
        if(!cacheDisplay[nodeName]) {
            $.applyShadowDOM(function(win, doc, body) {
                var node = doc.createElement(nodeName),
                    val
                    body.appendChild(node);
                if(win.getComputedStyle) {
                    val = win.getComputedStyle(node, null).display
                } else {
                    val = node.currentStyle.display;
                }
                cacheDisplay[nodeName] = val; 
            });
        }
        return cacheDisplay[nodeName];
    }

    function isHidden(node) {
        return node.sourceIndex === 0 || getter(node, "display") === "none" || !$.contains(node.ownerDocument, node);
    }
    $._isHidden = isHidden;

    function toggelDisplay(nodes, show) {
        var elem, values = [],
            status = [],
            index = 0,
            length = nodes.length;
        //由于传入的元素们可能存在包含关系,因此分开两个循环来处理,第一个循环用于取得当前值或默认值
        for(; index < length; index++) {
            elem = nodes[index];
            if(!elem.style) {
                continue;
            }
            values[index] = $._data(elem, "olddisplay");
            status[index] = isHidden(elem)
            if(!values[index]) {
                values[index] = status[index] ? $.parseDisplay(elem.nodeName) : getter(elem, "display");
                $._data(elem, "olddisplay", values[index])
            }
        }
        //第二个循环用于设置样式,-1为toggle, 1为show, 0为hide
        for(index = 0; index < length; index++) {
            elem = nodes[index];
            if(!elem.style) {
                continue;
            }
            show = show === -1 ? !status[index] : show;
            elem.style.display = show ? values[index] : "none";
        }
        return nodes;
    }
    $.fn.show = function() {
        return toggelDisplay(this, 1);
    }
    $.fn.hide = function() {
        return toggelDisplay(this, 0);
    }
    //state为true时,强制全部显示,为false,强制全部隐藏
    $.fn.toggle = function(state) {
        return toggelDisplay(this, typeof state == "boolean" ? state : -1);
    }

    //========================= 处理 offset =========================

    function setOffset(node, options) {
        if(node && node.nodeType == 1) {
            var position = getter(node, "position");
            //强逼定位
            if(position === "static") {
                node.style.position = "relative";
            }
            var curElem = $(node),
                curOffset = curElem.offset(),
                curCSSTop = getter(node, "top"),
                curCSSLeft = getter(node, "left"),
                calculatePosition = (position === "absolute" || position === "fixed") && [curCSSTop, curCSSLeft].indexOf("auto") > -1,
                props = {},
                curPosition = {},
                curTop, curLeft;
            if(calculatePosition) {
                curPosition = curElem.position();
                curTop = curPosition.top;
                curLeft = curPosition.left;
            } else {
                //如果是相对定位只要用当前top,left做基数
                curTop = parseFloat(curCSSTop) || 0;
                curLeft = parseFloat(curCSSLeft) || 0;
            }

            if(options.top != null) {
                props.top = (options.top - curOffset.top) + curTop;
            }
            if(options.left != null) {
                props.left = (options.left - curOffset.left) + curLeft;
            }
            curElem.css(props);
        }
    }

    $.fn.offset = function(options) { //取得第一个元素位于页面的坐标
        if(arguments.length) {
            return(!options || (!isFinite(options.top) && !isFinite(options.left))) ? this : this.each(function() {
                setOffset(this, options);
            });
        }

        var node = this[0],
            doc = node && node.ownerDocument,
            pos = {
                left: 0,
                top: 0
            };
        if(!doc) {
            return pos;
        }
        //http://hkom.blog1.fc2.com/?mode=m&no=750 body的偏移量是不包含margin的
        //我们可以通过getBoundingClientRect来获得元素相对于client的rect.
        //http://msdn.microsoft.com/en-us/library/ms536433.aspx
        var box = node.getBoundingClientRect(),
            win = getWindow(doc),
            root = (navigator.vendor || doc.compatMode == "BackCompat") ? doc.body : doc.documentElement,
            clientTop = root.clientTop >> 0,
            clientLeft = root.clientLeft >> 0,
            scrollTop = win.pageYOffset || root.scrollTop,
            scrollLeft = win.pageXOffset || root.scrollLeft;
        // 把滚动距离加到left,top中去。
        // IE一些版本中会自动为HTML元素加上2px的border,我们需要去掉它
        // http://msdn.microsoft.com/en-us/library/ms533564(VS.85).aspx
        pos.top = box.top + scrollTop - clientTop, pos.left = box.left + scrollLeft - clientLeft;

        return pos;
    }
    //========================= 处理 position =========================
    $.fn.position = function() { //取得元素相对于其offsetParent的坐标
        var offset, node = this[0],
            parentOffset = { //默认的offsetParent相对于视窗的距离
                top: 0,
                left: 0
            }
        if(!node || node.nodeType !== 1) {
            return
        }
        //fixed 元素是相对于window
        if(getter(node, "position") === "fixed") {
            offset = node.getBoundingClientRect();
        } else {
            offset = this.offset(); //得到元素相对于视窗的距离(我们只有它的top与left)
            var offsetParent = this.offsetParent();
            if(offsetParent[0].tagName !== "HTML") {
                parentOffset = offsetParent.offset(); //得到它的offsetParent相对于视窗的距离
            }
            var styles = getStyles(offsetParent[0]);
            parentOffset.top += parseNumber(styles, "borderTopWidth");
            parentOffset.left += parseNumber(styles, "borderLeftWidth");
        }
        return {
            top: offset.top - parentOffset.top - parseFloat(getter(node, "marginTop", styles)) || 0,
            left: offset.left - parentOffset.left - parseFloat(getter(node, "marginLeft", styles)) || 0
        };
    }
    //https://github.com/beviz/jquery-caret-position-getter/blob/master/jquery.caretposition.js
    //https://developer.mozilla.org/en-US/docs/DOM/element.offsetParent
    //如果元素被移出DOM树,或display为none,或作为HTML或BODY元素,或其position的精确值为fixed时,返回null
    $.fn.offsetParent = function() {
        return this.map(function() {
            var el = this.offsetParent;
            while(el && (el.parentNode.nodeType !== 9) && getter(el, "position") === "static") {
                el = el.offsetParent;
            }
            return el || document.documentElement;
        });
    }
    $.fn.scrollParent = function() {
        var scrollParent, node = this[0],
            pos = getter(node, "position")
            if((window.VBArray && (/(static|relative)/).test(pos)) || (/absolute/).test(pos)) {
                scrollParent = this.parents().filter(function() {
                    return(/(relative|absolute|fixed)/).test(getter(this, "position")) && (/(auto|scroll)/).test(getter(this, "overflow") + $.css(this, "overflow-y") + $.css(this, "overflow-x"));
                }).eq(0);
            } else {
                scrollParent = this.parents().filter(function() {
                    return(/(auto|scroll)/).test(getter(this, "overflow") + $.css(this, "overflow-y") + $.css(this, "overflow-x"));
                }).eq(0);
            }
        return(/fixed/).test(pos) || !scrollParent.length ? $(document) : scrollParent;
    }
    //========================= 处理 scrollLeft scrollTop =========================
    "scrollLeft_pageXOffset,scrollTop_pageYOffset".replace($.rmapper, function(_, method, prop) {
        $.fn[method] = function(val) {
            var node, win, top = method == "scrollTop";
            if(val === void 0) {
                node = this[0];
                if(!node) {
                    return null;
                }
                win = getWindow(node); //获取第一个元素的scrollTop/scrollLeft
                return win ? (prop in win) ? win[prop] : win.document.documentElement[method] : node[method];
            }
            return this.each(function() { //设置匹配元素的scrollTop/scrollLeft
                win = getWindow(this);
                if(win) {
                    win.scrollTo(!top ? val : $(win).scrollLeft(), top ? val : $(win).scrollTop());
                } else {
                    this[method] = val;
                }
            });
        };
    });

    function getWindow(node) {
        return $.type(node, "Window") ? node : node.nodeType === 9 ? node.defaultView || node.parentWindow : false;
    }
    return $;
});

css_fix.js

define("css_fix", !! top.getComputedStyle, ["$node"], function($) {
    var adapter = $.cssHooks = {},
        ie8 = !! top.XDomainRequest,
        rfilters = /[\w\:\.]+\([^)]+\)/g,
        rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
        rposition = /^(top|right|bottom|left)$/,
        salpha = "DXImageTransform.Microsoft.Alpha",
        border = {
            thin: ie8 ? '1px' : '2px',
            medium: ie8 ? '3px' : '4px',
            thick: ie8 ? '5px' : '6px'
        };
    $.getStyles = function(node) {
        return node.currentStyle;
    }
    adapter["_default:get"] = function(node, name, styles) {
        //取得精确值,不过它有可能是带em,pc,mm,pt,%等单位
        var currentStyle = styles || node.currentStyle;
        var ret = currentStyle[name];
        if((rnumnonpx.test(ret) && !rposition.test(ret))) {
            //①,保存原有的style.left, runtimeStyle.left,
            var style = node.style,
                left = style.left,
                rsLeft = node.runtimeStyle.left;
            //②由于③处的style.left = xxx会影响到currentStyle.left,
            //因此把它currentStyle.left放到runtimeStyle.left,
            //runtimeStyle.left拥有最高优先级,不会style.left影响
            node.runtimeStyle.left = currentStyle.left;
            //③将精确值赋给到style.left,然后通过IE的另一个私有属性 style.pixelLeft
            //得到单位为px的结果;fontSize的分支见http://bugs.jquery.com/ticket/760
            style.left = name === 'fontSize' ? '1em' : (ret || 0);
            ret = style.pixelLeft + "px";
            //④还原 style.left,runtimeStyle.left
            style.left = left;
            node.runtimeStyle.left = rsLeft;
        }
        if(ret == "medium") {
            name = name.replace("Width", "Style");
            //border width 默认值为medium,即使其为0"
            if(currentStyle[name] == "none") {
                ret = "0px";
            }
        }
        return ret === "" ? "auto" : border[ret] || ret;
    }
    //========================= 处理 opacity =========================
    adapter["opacity:get"] = function(node) {
        //这是最快的获取IE透明值的方式,不需要动用正则了!
        var alpha = node.filters.alpha || node.filters[salpha],
            op = alpha ? alpha.opacity : 100;
        return(op / 100) + ""; //确保返回的是字符串
    }
    //http://www.freemathhelp.com/matrix-multiplication.html
    //金丝楠木是皇家专用木材,一般只有皇帝可以使用做梓宫。
    adapter["opacity:set"] = function(node, name, value, currentStyle) {
        var style = node.style;
        if(!isFinite(value)) { //"xxx" * 100 = NaN
            return;
        }
        value = (value > 0.999) ? 100 : (value < 0.001) ? 0 : value * 100;
        if(!currentStyle.hasLayout) style.zoom = 1; //让元素获得hasLayout
        var filter = currentStyle.filter || style.filter || "";
        //http://snook.ca/archives/html_and_css/ie-position-fixed-opacity-filter
        //IE78的透明滤镜当其值为100时会让文本模糊不清
        if(value == 100) { //IE78的透明滤镜当其值为100时会让文本模糊不清
            // var str =  "filter: progid:DXImageTransform.Microsoft.Alpha(opacity=100) Chroma(Color='#FFFFFF')"+
            //   "progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand',"+
            //   "M11=1.5320888862379554, M12=-1.2855752193730787,  M21=1.2855752193730796, M22=1.5320888862379558)";
            value = style.filter = filter.replace(rfilters, function(a) {
                return /alpha/i.test(a) ? "" : a; //可能存在多个滤镜,只清掉透明部分
            });
            //如果只有一个透明滤镜 就直接去掉
            if(value.trim() == "" && style.removeAttribute) {
                style.removeAttribute("filter");
            }
            return;
        }
        //如果已经设置过透明滤镜可以使用以下便捷方式
        var alpha = node.filters.alpha || node.filters[salpha];
        if(alpha) {
            alpha.opacity = value;
        } else {
            style.filter = ((filter ? filter + "," : "") + "alpha(opacity=" + value + ")");
        }
    }
    /**========================= 处理 user-select =========================
     * auto——默认值,用户可以选中元素中的内容
     * none——用户不能选择元素中的任何内容
     * text——用户可以选择元素中的文本
     * element——文本可选,但仅限元素的边界内(只有IE和FF支持)
     * all——在编辑器内,如果双击/上下文点击发生在子元素上,改值的最高级祖先元素将被选中。
     * -moz-none——firefox私有,元素和子元素的文本将不可选,但是,子元素可以通过text重设回可选。
     * https://developer.mozilla.org/en-US/docs/CSS/user-select
     */
    adapter["userSelect:set"] = function(node, name, value) {
        var allow = /none/.test(value) ? "on" : "",
            e, i = 0,
            els = node.getElementsByTagName('*');
        node.setAttribute('unselectable', allow);
        while((e = els[i++])) {
            switch(e.tagName) {
            case 'IFRAME':
            case 'TEXTAREA':
            case 'INPUT':
            case 'SELECT':
                break;
            default:
                e.setAttribute('unselectable', allow);
            }
        }
    };
    //========================= 处理 background-position =========================
    adapter["backgroundPosition:get"] = function(node, _,style ) {
        return style.backgroundPositionX + " " + style.backgroundPositionX;
    };
    //========================= 处理 rotate =========================
    var stransform = "DXImageTransform.Microsoft.Matrix";
    adapter.centerOrigin = "margin";
    adapter["rotate:set"] = function(node, name, value) {
        $._data(node, 'rotate', value);
        var matrix = node.filters[stransform];
        if(!matrix) {
            node.style.filter += "progid:" + stransform + "(M11=1,M12=1,M21=1,M22=1,sizingMethod='auto expand')";
            matrix = node.filters[stransform];
        }
        var _rad = value * Math.PI / 180,
            costheta = Math.cos(_rad),
            sintheta = Math.sin(_rad);
        matrix.M11 = costheta;
        matrix.M12 = -sintheta;
        matrix.M21 = sintheta;
        matrix.M22 = costheta;
        name = adapter.centerOrigin;
        node.style[name == 'margin' ? 'marginLeft' : 'left'] = -(node.offsetWidth / 2) + (node.clientWidth / 2) + "px";
        node.style[name == 'margin' ? 'marginTop' : 'top'] = -(node.offsetHeight / 2) + (node.clientHeight / 2) + "px";
    }
    return $;
});
机器瞎学/数据掩埋/模式混淆/人工智障/深度遗忘/神经掉线/计算机幻觉/专注单身二十五年
原文地址:https://www.cnblogs.com/rubylouvre/p/2881248.html