$.cssHooks 扩展 jquery 的属性操作

最近在研究 $.transit 然后发现了 $.cssHooks 这个方法,试了一下官方的 demo 表示好像并不是那么回事,所以决定深入的测试一下。

$.cssHooks 的作用在于拓展属性(自己意淫的),比如用 "rotate" 代替 "transform: rotate()" 之类的,酱紫,$(".box1").css({"rotate":"10"});

而且还可以用 "rotate" 代替 "transform:rotate()" 和 "-webkit-transform:rotate()",这样是不是很爽呢...

那么,我们就分两个阶段好了,一获取当前浏览器支持的属性,二拆分成特殊属性,三添加到属性拓展。

获取兼容的属性这个很容易找到啦,但对我这种懒人来说,代码优美最重要咯,行数越少越好了。

var div = document.createElement(‘div‘);
var support = {};
function getVendorPropertyName(prop) {
    if (prop in div.style) return prop;
    var prefixes = [‘Moz‘, ‘Webkit‘, ‘O‘, ‘ms‘];
    var prop_ = prop.charAt(0).toUpperCase() + prop.substr(1);
    for (var i=0; i<prefixes.length; ++i) {
        var vendorProp = prefixes[i] + prop_;
        if (vendorProp in div.style) { return vendorProp; }
    }
}
function checkTransition3dSupport() {
    div.style[support.transform] = ‘‘;
    div.style[support.transform] = ‘rotateY(90deg)‘;
    return div.style[support.transform] !== ‘‘;
}
support.perspective = getVendorPropertyName(‘perspective‘);
support.transition = getVendorPropertyName(‘transition‘);
support.transitionDelay = getVendorPropertyName(‘transitionDelay‘);
support.transform = getVendorPropertyName(‘transform‘);
support.transformOrigin = getVendorPropertyName(‘transformOrigin‘);
support.filter = getVendorPropertyName(‘Filter‘);

这也是看了多家源码后总结出来最简短的了,不要嫌弃。

拆分特殊属性这块,其实没有太多时间重写,先写上 $.transit 的代码好了,之后我会再写一个关于 filter 特殊属性的拆分。

var Transform = function( str ) {
    if (typeof str === ‘string‘) { this.parse(str); }
    return this;
};
// 将 translate() 等转换为数字形态
Transform.prototype.parse = function( str ) {
    var self = this;
    str.replace(/([a-zA-Z0-9]+)\((.*?)\)/g, function(x, prop, val) {
        self.divideString(prop, val);
    });
}
// 将多值字符串拆分
Transform.prototype.divideString = function( prop, val ) {
    var args =
        (typeof val === ‘string‘)  ?
        val.split(‘,‘) :
        (val.constructor === Array) ? val : [ val ];
    args.unshift(prop);
    Transform.prototype.set.apply(this, args);
}
// 设置 transform 的值
Transform.prototype.set = function( prop ) {
    var args = Array.prototype.slice.apply(arguments, [1]);
    if (this.setter[prop]) {
        this.setter[prop].apply(this, args);
    } else {
        this[prop] = args.join(‘,‘);
    }
}
// transform 拆分值设置
Transform.prototype.setter = {
    rotate: function(theta) {
        this.rotate = unit(theta, ‘deg‘);
    },
    rotateX: function(theta) {
        this.rotateX = unit(theta, ‘deg‘);
    },
    rotateY: function(theta) {
        this.rotateY = unit(theta, ‘deg‘);
    },
    scale: function(x, y) {
        if (y === undefined) { y = x; }
        this.scale = x + "," + y;
    },
    skewX: function(x) {
        this.skewX = unit(x, ‘deg‘);
    },
    skewY: function(y) {
        this.skewY = unit(y, ‘deg‘);
    },
    perspective: function(dist) {
        this.perspective = unit(dist, ‘px‘);
    },
    x: function(x) {
        this.set(‘translate‘, x, null);
    },
    y: function(y) {
        this.set(‘translate‘, null, y);
    },
    translate: function(x, y) {
        if (this._translateX === undefined) { this._translateX = 0; }
        if (this._translateY === undefined) { this._translateY = 0; }
        if (x !== null && x !== undefined) { this._translateX = unit(x, ‘px‘); }
        if (y !== null && y !== undefined) { this._translateY = unit(y, ‘px‘); }
        this.translate = this._translateX + "," + this._translateY;
    },
}
// 获取已有属性及其值
Transform.prototype.get = function( prop ) {
    if (this.getter[prop]) {
        return this.getter[prop].apply(this);
    } else {
        return this[prop] || 0;
    }
}
// 获取
Transform.prototype.getter = {
    x: function() {
        return this._translateX || 0;
    },
    y: function() {
        return this._translateY || 0;
    },
    scale: function() {
        var s = (this.scale || "1,1").split(‘,‘);
        if (s[0]) { s[0] = parseFloat(s[0]); }
        if (s[1]) { s[1] = parseFloat(s[1]); }
        return (s[0] === s[1]) ? s[0] : s;
    },
    rotate3d: function() {
        var s = (this.rotate3d || "0,0,0,0deg").split(‘,‘);
        for (var i=0; i<=3; ++i) {
            if (s[i]) { s[i] = parseFloat(s[i]); }
        }
        if (s[3]) { s[3] = unit(s[3], ‘deg‘); }
        return s;
    }
}
// 将多值合并为 3d 状态
Transform.prototype.toString = function( use3d ) {
    var re = [];
    for (var i in this) {
        if (this.hasOwnProperty(i)) {
            var sure = (!support.transform3d) && (
                (i === ‘rotateX‘) ||
                (i === ‘rotateY‘) ||
                (i === ‘perspective‘) ||
                (i === ‘transformOrigin‘))
            if (sure) { continue; }
            if (i[0] !== ‘_‘) {
                if (use3d && (i === ‘scale‘)) {
                    re.push(i + "3d(" + this[i] + ",1)");
                } else if (use3d && (i === ‘translate‘)) {
                    re.push(i + "3d(" + this[i] + ",0)");
                } else {
                    re.push(i + "(" + this[i] + ")");
                }
            }
        }
    }
    return re.join(" ");
}

  

最后一步,添加到 $.cssHooks 中,具体 $.cssHooks 怎么用,搜文档比看我写过程其实要更精确

// 添加特殊兼容性
$.cssHooks[‘transit:transform‘] = {
    get: function(elem) {
        return $(elem).data(‘transform‘) || new Transform();
    },
    set: function(elem, value) {
        if (!(value instanceof Transform)) {
            value = new Transform(value);
        }
        elem.style[support.transform] = value.toString();
        $(elem).data(‘transform‘, value);
    }
};
// 兼容 transform 属性
$.cssHooks.transform = {
    set: $.cssHooks[‘transit:transform‘].set
};

// 让特殊值可拥有过渡效果
function registerCssHook(prop, isPixels) {
    if (!isPixels) { $.cssNumber[prop] = true; }
    // $.transit.propertyMap[prop] = support.transform;
    $.cssHooks[prop] = {
        get: function(elem) {
            var t = $(elem).css(‘transit:transform‘);
            return t.get(prop);
        },
        set: function(elem, value) {
            var t = $(elem).css(‘transit:transform‘);
            t.divideString(prop, value);
            $(elem).css({ ‘transit:transform‘: t });
        }
    };
}
registerCssHook(‘scale‘);
registerCssHook(‘scaleX‘);
registerCssHook(‘scaleY‘);
registerCssHook(‘translate‘);
registerCssHook(‘rotate‘);
registerCssHook(‘rotateX‘);
registerCssHook(‘rotateY‘);
registerCssHook(‘rotate3d‘);
registerCssHook(‘perspective‘);
registerCssHook(‘skewX‘);
registerCssHook(‘skewY‘);
registerCssHook(‘x‘, true);
registerCssHook(‘y‘, true);

  

ok,加上了上面这三串之后,你会发觉,$(".box1").css({"rotate":"10"}); 成为了现实,当初还要用插件和写多个 transform 已经不需要了。而且 $.animate 也可以哟。

然而,$.cssHook 并不完善,所以会出现 rotateX  / perspective 等无效的情况,

而 css 本身也有不足,比如 scaleX 的默认值为 0,本身没有 translate 那么添加 translate 动画也是无效的

家里电脑坏了,不开森,不开森,不开森...

时间: 2024-10-11 00:27:09