• mass Framework css模块 v3


    本模块最大的亮点是完美解决了一个世界难题,在IE678下模拟CSS3 transform 2D。

    CSS3 transform 2D归根结底就是矩阵变换的问题,大家都知道利用IE的矩阵滤镜来解。但里面的坑太多,一旦发生旋转或扭曲,然后再进行位移,之前所有的JS库都是计算错误的。本来将一步步带你揭开这谜底。

    要实现css transform 2D,就要动用到一个CSS3新属性——transform。但在本文写作之时,还没有任何一个浏览器支持w3c所说的那个标准属性,都是带前缀。因此mass Framework,使用了一个叫cssName的方法,取得所有能用的私有实现名。transform在框架可能用WebkitTransform, MozTransform, OTransform, msTramsform代替。你们会注意,IE9下竟然是小写开头,这是一个坑。

    赋值时,有两种形式。最初是使用translate, scale, rotate, skew等方法进行变菁,后来添加了一个与IE滤镜很相似的matrix方法。

    -webkit-transform: rotate(60deg) skew(0deg, -30deg) scale(1, 1.15);
    -webkit-transform: matrix(-1,0,0,1,0,0)
    

    此外,还有translateX,translateY,skewX,skewY,scaleX,scaleY。它们在CSS中不区分大小写的,因此JS框架要使用toLowerCase避雷。此外,skew是不标准的,这是第二个坑。

    像skew与rotate开头的方法,它们的参数必须带单位,这是第三个坑。

    scale方法允许只传入一个参数,第二个参数默认为等于第一个参数,这是第四个坑。

    matrix形式下赋值,FF的第五个参数与第六个参数必须带单位,这是第五个坑。

    像"rotate(60deg) skew(0deg, -30deg) scale(1, 1.15)"这样的写法,其实是进行了三次矩阵乘法,并且可以重复定义两个以上相同函数。这是第七个坑。

    -webkit-transform: translate(10px 20px) rotate(60deg) skew(0deg, -30deg) scale(1, 1.15) translateX(110px)//位移了两次了。
    

    取值时,都会自动转换为matrix形式,但每个浏览器的精度都不一样,这非常不利于测试。比如,FF小数点后有六位,opera有两位,IE9有五位,webkit系多达16位,另,IE678的矩阵滤镜也是16位。对于太小的位数,我们完全可以忽略掉。在浏览器中,如果一个数字的小数点后有超过八位数值,就会用指数表示,那么我们可以用/e/来检测,再用toFixed进行微调!这是第八坑。

    竟然是矩阵相乘,必须有一个初始矩阵。但如果没有设置css3 transform属性,标准浏览器是返回"none"字符串,而不是我们期望的matrix形式。IE678也一样,返回null。由于标准浏览器的计算都是浏览器自行搞定,难点就在IE了。

       var ident  = "DXImageTransform.Microsoft.Matrix"
        adapter[ "transform:get" ] = function(node, name){
            var m = $._data(node,"matrix")
            if(!m){
                if(!node.currentStyle.hasLayout){
                    node.style.zoom = 1;
                }
                //IE9下请千万别设置  
                //http://www.cnblogs.com/Libra/archive/2009/03/24/1420731.html
                if(!node.filters[ident]){
                    var old = node.currentStyle.filter;//防止覆盖已有的滤镜
                    node.style.filter =  (old ? old +"," : "") + " progid:" + ident + "(sizingMethod='auto expand')";
                }
                var f = node.filters[ident];
                m = new $.Matrix2D( f.M11, f.M12, f.M21, f.M22, f.Dx, f.Dy);
                $._data(node,"matrix",m ) //保存到缓存系统,省得每次都计算
            }
            return name === true ? m : m.toString();
        }
    

    上面代码有几个注意点,滤镜必须hasLayout,因此使用zoom hack。由于滤镜都是共用一个属性,我们不知道这元素之前绑定了多个滤镜,如透明滤镜,PNG补丁滤镜,盒子阴影滤镜,这些都是很常用的,因此我们要防止覆盖已有的滤镜。这是第九个坑。brendankenny在《On the Behavior of 2d Transformations in Internet Explorer, Part 2》吹嘘,其找到一种方法能快速围绕元素中心变形,其实是大谬其然!直接覆写已有滤镜了!

    // set linear transformation via Matrix Filter
    var filt = 'progid:DXImageTransform.Microsoft.Matrix(';
    filt +=   'M11=' + a;
    filt += ', M21=' + b;
    filt += ', M12=' + c;
    filt += ', M22=' + d;
    filt += ', SizingMethod="auto expand")';
    target.style['filter'] = filt;//★★★出问题的代码
     
    // assuming a-d are local variables
    // and halfW and halfH are initialized properly
     
    // horizontal shift
    a = Math.abs(a); // or go ternary
    c = Math.abs(c);
    var sx = (a - 1)*halfW + c*halfH;
     
    // vertical shift
    b = Math.abs(b);
    d = Math.abs(d);
    var sy = b*halfW + (d - 1)*halfH;
     
    // translation, corrected for origin shift
    // rounding helps--but doesn't eliminate--integer jittering
    target.style.left = Math.round(x + e - sx) + 'px';
    target.style.top = Math.round(y + f - sy) + 'px';
    
    

    而元素默认是围绕中心变形,这就是最大的坑,第十个坑。IE滤镜是围张左上角变形的。为了模拟这效果,老外前赴后继封闭研究它。其中最杰出的方案,由heygrady 在《Correcting Transform Origin and Translate in IE》,至后来的 useragentman的cssSandpaper,louisremi的jquery.transform2都是沿袭其思路。然后,美中不足的是heygrady 取变形前的矩形尺寸是不可行的:

      var filter = $elem[0].style.filter;
        $elem[0].style.filter = '';
        
        // measure the element
        var width = $elem.outerWidth();
        var height = $elem.outerHeight();
        
        // re-do the filter
        $elem[0].style.filter = filter;//这其实变不回去了
    

    它们计算新矩阵的坐标也异常复杂,IE下只能用相对定位或margin来模拟,但不管什么做,都要重新计算左下角的坐标。haygrady用了一个文件jquery.matrix.calculations.js来放置这些函数,可见复杂度多大。就算计出来,多多少少有偏差。因此在这里我必须转向了。下面是我获取变形前的矩形的尺寸的方法:

               var filter = node.filters[ident];
                filter.M11 =  filter.M22 = 1;//取得未变形前的宽高,原始矩阵为[1,0,0,1,0,0]
                filter.M12 =  filter.M21 = 0;
                var width = node.offsetWidth;
                var height = node.offsetHeight;
                filter.M11 = m.a;//进行矩阵变换
                filter.M12 = m.c
                filter.M21 = m.b;
                filter.M22 = m.d;
                filter.Dx  = m.tx;
                filter.Dy  = m.ty;
                $._data(node,"matrix",m);
                var tw =  node.offsetWidth, th = node.offsetHeight;//取得变形后高宽
                node.style.position = "relative";
                node.style.left = (width - tw)/2  + m.tx + "px";
                node.style.top = (height - th)/2  + m.ty + "px";
    

    可能有人问,为什么不一开始就缓存它们的宽高呢?因为可能会有直接把滤间写到外部样式表的情况,而这样式表又先于我们的库加载,因此这时也取得变形前的宽高。

    剩下来就是计算宽高了,这个用矩阵乘法就可以算出了,结果也在上面。

    最后放个例子:

              $.require("ready,css",function(){
    
                    $(".sample1").css("transform","scale(1.3) rotate(270deg) skew(-40deg, 0deg) translate(200px,-140px)")
    
                });
    

    源码地址:css.js, css_fix.js

    这是测试
  • 相关阅读:
    [转载][开源框架推荐]VTDXML:世界上最快的XML处理框架
    iptables规则的查看、添加、删除和修改
    [转载]Linux大文件传输
    nginx+ php 安装配置实用
    wojilu框架代码分析之ActionProcessor.Process()
    数据库范式通俗理解,谈谈数据库设计
    我记录综合系统学习研究之用户管理二(wojilu.Web.Controller.Users MainController)
    我记录学习研究之前端开发二(js基于1.8版)
    我记录综合系统学习研究之开篇
    我记录综合系统学习研究之用户管理一(wojilu.Web.Controller.Users MainController)
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/2491937.html
Copyright © 2020-2023  润新知