zoukankan      html  css  js  c++  java
  • 移动端二三事【三】:transform的矩阵(matrix)操作、transform操作函数及注意事项

    *每当在DOM浏览器中增加动态效果时,使用强大的transform和transition,总是很酸爽。抛开css,使用js操作transform还真的有点复杂,涉及到线性代数中的矩阵,但是js操作又不可避免的会用到。俗话说,山水有相逢,早日学会,早日总结,方便以后用到。今天就与大家分享一下,transform的注意事项以及transform矩阵操作的一些技巧。

    *首先说一些小的注意事项,硬菜在后面!

    1.js操作transition时需使用驼峰命名增加前缀:

    div.style.WebkitTransform = div.style.transform = "rotate(90deg)";

    2.多个transition操作的执行顺序:先写的后后执行

    以下以两个div为例,点击后执行不同的过渡效果:

        div[0].addEventListener('touchend', function(e) {
            this.style.WebkitTransform = this.style.transform = "scale(.5) translateX(100px)";
        });
        div[1].addEventListener('touchend', function(e) {
            this.style.WebkitTransform = this.style.transform = "translateX(100px) scale(.5)";
        });

    初始 效果:

    点击后的效果:

    页面代码如下,可自己拎下来运行:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,user-scalable=no" />
    <title>执行顺序</title>
    <style type="text/css">
    #box {
         100px;
        border: 1px solid #000;
        padding: 100px;
    }
    .div {
         100px;
        height: 100px;
        margin: 10px 0;
        background: red;
        transition: 3s;
        -webkit-transform-origin: 0 0;
        transform-origin: 0 0;
    }
    </style>
    <script type="text/javascript">
    document.addEventListener('touchstart', function(e) {
        e.preventDefault();
    });
    window.onload = function(){
        var div = document.querySelectorAll('.div');
        div[0].addEventListener('touchend', function(e) {
            this.style.WebkitTransform = this.style.transform = "scale(.5) translateX(100px)";
        });
        div[1].addEventListener('touchend', function(e) {
            this.style.WebkitTransform = this.style.transform = "translateX(100px) scale(.5)";
        });
    };
    </script>
    </head>
    <body>
    <div id="box">
        <div class="div"></div>
        <div class="div"></div>
    </div>    
    </body>
    </html>

    3.移动端在操作结点位置时,尽量使用translate,而操作left或margin等都会引起页面回流(reflow),我们要做的就是尽可能地避免回流,尽可能的减少重绘。

    举个栗子使用translate模拟垂直滚动条:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>垂直滚动</title>
    <meta name="viewport" content = "width=device-width,user-scalable=no">
    <style type="text/css">
    body {
        margin: 0;
    }
    html,
    body {
        overflow: hidden;
        height: 100%;
        position: relative;
    }
    header{
        height: 40px;
        background: #000;
        color: #fff;
        text-align: center;
        font-size: 20px;
        line-height: 40px;
    }
    #wrap {
        position: absolute;
        left: 0;
        right: 0;
        top: 40px;
        bottom: 0px;    
        overflow: hidden;    
    }
    #list {
        margin: 0;
        padding: 0;
        list-style: none;
    }
    #list li {
        height: 30px;
        border-bottom: 1px solid #000;
        line-height: 30px;
        text-indent: 20px;
    }
    </style>
    <script type="text/javascript">
    document.addEventListener("touchstart",function(e){
            e.preventDefault();
    });
    function setListInner(){
        var list = document.querySelector('#list');
        var inner = "";
        for(var i = 0; i < 100; i++){
            inner += "<li>这是第"+i+"个li</li>"
        }    
        list.innerHTML = inner;
    }
    window.onload = function(){
        setListInner();
        var wrap = document.querySelector('#wrap');
        var list = document.querySelector('#list');
        var startPoint = 0;
        var startEl = 0;
        var elTranslateY = 0;
        list.addEventListener('touchstart', function(e) {
            startPoint = e.changedTouches[0].pageY;
            startEl = elTranslateY;
        });
        list.addEventListener('touchmove', function(e) {
            var nowPoint = e.changedTouches[0].pageY; 
            var dis =  nowPoint - startPoint;
            elTranslateY = startEl + dis;
            list.style.WebkitTransform = list.style.transform = "translateY("+elTranslateY+"px)";
        });
    };
    </script>
    </head>
    <body>
    <header>垂直滚动</header>
    <div id="wrap">
        <ul id="list"></ul>
    </div>
    </body>
    </html>

     4.矩阵操作

    大家都知道当使用js获取transform时获取的是一个矩阵:

        div[0].style.WebkitTransform = div[0].style.transform = "scale(.5) translateX(100px)";
        //最终样式才能获取到transform的矩阵参数字符串
        console.log(getComputedStyle(div[0])["transform"]);                  //  matrix(0.5, 0, 0, 0.5, 50, 0)
        console.log( typeof (getComputedStyle(div[0])["transform"]));       //  string
        console.log(div[0].style.transform);                               //   scale(0.5) translateX(100px)
        console.log(typeof (div[0].style.transform));                     //  string

     *矩阵参数对应的变量:
       matrix( a, b, c, d, e, f ),基础值为:

       matrix( 1, 0, 0, 1, 0, 0 )

    基础效果如下:

    1.改变位移:

    //位移:
    //x为轴位移量,y为y轴位移量,可使用负数
    //x轴位移 = e + x;
    //y轴位移 = f + y;
    //如下为左移100像素,下移50像素
    div[0].style.transform = "matrix(1, 0, 0, 1, -100, 50)";

    改变位移效果:

    2.缩放:

    (1) x轴缩放:操作变量a,c,e

    //x轴:
    //a = a*x;
    //c = c*x;
    //e = e*x;
    //x为缩放倍数
    div[0].style.transform = "matrix(.5, 0, 0, 1, 0, 0)";

    x轴缩放0.5效果:

    (2)y轴缩放:操作变量b,d,f

    //y轴:
    //b = b*x;
    //d = d*x;
    //f = f*x;
    div[0].style.transform = "matrix(1, 0, 0, .5, 0, 0)";

    y轴缩放后效果:

    由此就可以解释,在使用css命令时的执行顺序问题:

    //先执行matrix(.5, 0, 0, 1, 0, 0)
    //后执行matrix(.5, 0, 0, 1, 100, 0)
    div[0].style.transform = "scaleX(.5) translateX(100px)";
    //先执行matrix(1, 0, 0, 1, 100, 0)
    //后执行matrix(.5, 0, 0, 1, 50, 0)
    div[0].style.transform = "translateX(100px) scaleX(.5)";

    3.斜切:

    (1)x轴斜切:

    //x轴斜切30度:单位(deg)
    //操作参数c,修改参数时需要转化为弧度
    //弧度 = Math.tan(角度/180*Math.PI);
    div[0].style.transform = "matrix(1, 0, "+Math.tan(30/180*Math.PI)+", 1, 0, 0)";

    效果如下:

    (2)y轴斜切:

    //y轴斜切30度:单位(deg)
    //操作参数b,修改参数时需要转化为弧度
    div[0].style.transform = "matrix(1,"+Math.tan(30/180*Math.PI)+",0, 1, 0, 0)";

    效果如下:

    4.旋转rotate:

    //旋转:
    //修改a,b,c,d四个参数
    var a = Math.cos(45/180*Math.PI);
    var b = Math.sin(45/180*Math.PI);
    var c = -Math.sin(45/180*Math.PI);
    var d = Math.cos(45/180*Math.PI);
    div[0].style.transform = "matrix("+ a +","+ b +","+ c +","+ d +",0,0)";

    效果如下:

     5.transform操作函数封装

    若现在有这么一个需求,每次点击div后,使其旋转30deg,那么我们是无法直接操作transform完成的,通过js修改操作css的transform无法记录当前的状态(旋转角度等)。因此需要转换思想进行函数封装,封装的原理是添加自定义属性,再利用自定义属性为相应结点添加transform。

    function cssTransform(element, attr, val){
        if(!element.transform){
            element.transform = {};
        }    
        if(typeof val === "undefined"){ 
            if(typeof element.transform[attr] === "undefined"){
                switch(attr){
                    case "scale":
                    case "scaleX":
                    case "scaleY":
                    case "scaleZ":
                        element.transform[attr] = 100;
                        break;
                    default:
                        element.transform[attr] = 0;    
                }
            } 
            return element.transform[attr];
        } else {
            element.transform[attr] = val;
            var transformVal  = "";
            for(var s in element.transform){
                switch(s){
                    case "scale":
                    case "scaleX":
                    case "scaleY":
                    case "scaleZ":
                        transformVal += " " + s + "("+(element.transform[s]/100)+")";
                        break;
                    case "rotate":
                    case "rotateX":
                    case "rotateY":
                    case "rotateZ":
                    case "skewX":
                    case "skewY":
                        transformVal += " " + s + "("+element.transform[s]+"deg)";
                        break;
                    default:
                        transformVal += " " + s + "("+element.transform[s]+"px)";                
                }
            }
            element.style.WebkitTransform = element.style.transform = transformVal;
        }
    }

    注意!如果要获取transform相关的属性,那transform相关的设置 也必须是通过该方法设置的!

    利用封装的函数,就可以完成刚才的需求。完整的代码如下,可自行运行查看效果:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,user-scalable=no" />
    <title>点击旋转30deg</title>
    <style type="text/css">
        #box {
             100px;
            height: 100px;
            border: 1px solid #000;
            padding: 100px;
        }
        #div {
            height: 100px;
            background: red;
            transition: .5s;
        }
    </style>
    <script type="text/javascript">
    function cssTransform(element, attr, val){
        if(!element.transform){
            element.transform = {};
        }    
        if(typeof val == "undefined"){ 
            if(!element.transform[attr]){
                switch(attr){
                    case "scale":
                    case "scaleX":
                    case "scaleY":
                    case "scaleZ":
                        element.transform[attr] = 100;
                        break;
                    default:
                        element.transform[attr] = 0;    
                }
            } 
            return element.transform[attr];
        } else {
            element.transform[attr] = val;
            var transformVal  = "";
            for(var s in element.transform){
                switch(s){
                    case "scale":
                    case "scaleX":
                    case "scaleY":
                    case "scaleZ":
                        transformVal += " " + s + "("+(val/100)+")";
                        break;
                    case "rotate":
                    case "rotateX":
                    case "rotateY":
                    case "rotateZ":
                    case "skewX":
                    case "skewY":
                        transformVal += " " + s + "("+val+"deg)";
                        break;
                    default:
                        transformVal += " " + s + "("+val+"px)";                
                }
            }
            element.style.WebkitTransform = element.style.transform = transformVal;
        }
    }
    window.onload = function(){
        var div = document.querySelector('#div');
        div.addEventListener('touchend', function(e) {
            var deg = cssTransform(this, "rotate");
            deg += 30;
            cssTransform(this, "rotate", deg);
        });
    };
    </script>
    </head>
    <body>
    <div id="box">
        <div id="div"></div>
    </div>
    </body>
    </html>
  • 相关阅读:
    function函数
    for的衍生对象
    前端发展史
    字符串替换
    正则
    DOM和BOM的区别与联系
    BOM
    DOM
    css单位分析
    API and Web API
  • 原文地址:https://www.cnblogs.com/pomelott/p/7784684.html
Copyright © 2011-2022 走看看