TAT.dnt transformjs污染了DOM?
In Web开发 on 2016年12月28日 by view: 1,273
5

原文链接: https://github.com/AlloyTeam/AlloyTouch/wiki/Powerful-transformjs

写在前面

上星期在React微信群里,有小伙伴觉得transformjs直接给DOM添加属性太激进,不可取(由于不在那个微信群,不明白为什么React会谈到transformjs?!)。关于这点,其实在一年半前腾讯内部就有相关声音,腾讯内部的小伙伴建议,不要污染那么多吧~~,给个总的namespace,如:

在腾讯内部,还有小伙伴建议,包裹一层把:

总之,就是不要这样子(transformjs目前的姿势):

那么上面这种做法会有什么问题?

  • 既然JS里提供了动态属性并监听变更进行callback的能力为什么不能用?
  • 违反哪条JS最佳实践?
  • 违反哪条Web最佳实践?
  • 违反哪条DOM最佳实践?

后来,我找到以前提修改意见的腾讯小伙伴,他给了这样的回答:

如果以后 w3c 需要给DOM元素扩展 translateX, translateY, translateZ, scaleX, scaleY, scaleZ, rotateX, rotateY, rotateZ, skewX, skewY, originX, originY, originZ,这就留下了巨大的隐患~~

对于这点,我认为,既然domElment.style.transform已经有了,扩展translateX, translateY, translateZ, scaleX, scaleY, scaleZ, rotateX, rotateY, rotateZ, skewX, skewY, originX, originY, originZ的可能性几乎没有,因为其实domElment.style.transform已经提供了足够的灵活性。就算扩展了,transformjs打个补丁包或者prolyfill 一下便可。

然后我又问了一些小伙伴,得到一个非常有趣的回答:

反正你污染了DOM,反正你污染了DOM,反正你污染了DOM….

….

条条大路通罗马

transformjs不仅仅可以mix CSS3 transform到DOM元素,还能mix到任意的对象字面量,也可以把transformjs当作工具,他提供一些基础的数学能力。

这里需要特别注意,以前的姿势可以继续使用,这里另外三种使用姿势。

语法1

如你所见,其他方式都不用变。只是第一个参数不仅仅可以传DOM元素,也可以传任意对象字面量等。

不卖关子,先看使用姿势

看到了没有,你不仅可以传DOM元素进去,也可以传对象字面量。你可以把obj.transform打印出来,上面是选择了90度,所以它生成出来的matrix是:

你同样也可以关闭透视投影,如:

生成出来的matrix是:

那么运动的姿势呢?这里配合tween.js的示例如下:

那么如果用传统的姿势是?

这里由于 TWEEN.Tween会去遍历所以的属性并且设置初始值,如tween里面的代码:

所以不能直接把 new TWEEN.Tween(element)。
因为在start之前,程序其实已经可以完全收集到所有需要to的属性,去运动便可以。我们可以自己封装一个tween去支持这种简便的方式。如:

这里为了简便使用setInterval去进行loop,当然可以换成其他方式。现在便可以使用如下方式:

当然这有点跑题了。这里只是对比直接使用DOM挂载和使用第三方对象挂载的区别。第三方挂载有点隔山打牛的感觉。
当然..,还没有完,不仅仅可以上面那个样子。那还可以把transformjs完全当作一个计算工具来用。

语法2

姿势

打印出来你将得到下面的值:

你想用这个值来干什么就干什么吧。看transformjs源码可以得到 Transform.getMatrix3D一共支持的属性:

语法3

不仅仅是3D matrix, transformjs也提供了2D的工具函数支持。

姿势

打印出来你将得到下面的值:

  • a 水平缩放
  • b 水平拉伸
  • c 垂直拉伸
  • d 垂直缩放
  • tx 水平位移
  • ty 垂直位移

那么得到这个Matrix2D有什么用?

  • 缩放:scale(sx, sy) 等同于 matrix(sx, 0, 0, sy, 0, 0);
  • 平移:translate(tx, ty) 等同于 matrix(1, 0, 0, 1, tx, ty);
  • 旋转:rotate(deg) 等同于 matrix(cos(deg), sin(deg), -sin(deg), cos(deg), 0, 0);
  • 拉伸:skew(degx, degy) 等同于 matrix(1, tan(degy), tan(degx), 1, 0, 0);

看transformjs源码可以得到 Transform.getMatrix2D一共支持的属性:

特别注意事项

Transform.getMatrix2D 和Transform.getMatrix3D都是支持origin特性,请和transform-origin说拜拜
Transform.getMatrix2D 和Transform.getMatrix3D没有使用传统的Math.tan去实现shew,取而代之的是half of rotation

如2d的skew:

以前腾讯IEG的同学问过为什么使用half of rotation,而不使用Math.tan?
原因很简单,Math.tan扭曲力度特别大,而且会有无穷大的值导致扭曲横跨整个屏幕。

而half of rotation则不会。

getMatrix2D有用吗?

用于Dom Transformation时候,可以用于兼容不支持CSS3 3D Transforms的浏览器

如,我们可以很轻松的把一些transformation属性转换成CSS3属性赋给DOM:

用于Canvas和SVG Transformation

什么?还能用于Canvas和SVG?是的,举个例子,在Canvas画一个旋转30度、缩小成0.5倍,并且平移(200,200)的图片:

上面是我们传统的姿势。使用Transform.getMatrix2D 之后,变成这个样子:

可以看到,这里让开发者不用自己去拼凑matrix。SVG的粒子就不再举例,和用于DOM的例子差不多,相信大家能够很快搞定。

开始使用吧

最后,多谢大家对transformjs的建议,有了你们中肯建议和意见,才让它变得更好更灵活更强大。


原创文章转载请注明:

转载自AlloyTeam:http://www.alloyteam.com/2016/12/transformjs-polluting-the-dom/

  1. alice 2017 年 6 月 28 日

    安卓4.4 默认浏览器不支持 hasOwnProperty,这个怎么解决啊

  2. 徐志伟 2017 年 1 月 17 日

    大神,数学真好啊。transform.js库简单的说,就是利用了es5的Object.defineProperty方法给对象的属性,当然这里大神自己重写了添加属性的set和get方法,通过那15个属性([“translateX”, “translateY”, “translateZ”, “scaleX”, “scaleY”, “scaleZ”, “rotateX”, “rotateY”, “rotateZ”, “skewX”, “skewY”, “originX”, “originY”, “originZ”, “perspective”]),当然透视可以关闭,只要设置,必然会触发set中的回调函数,这个回调函数就是三维矩阵各种计算后的值,之后赋给dom。那个腾讯小伙伴说是污染,其实这15个属性也不是保留字,并无大碍,很是同意大神的观点。说了这么多了,大神,能不能拉我进你们162225981那个群啊,加了管理员不给进啊,代码都已经开源了,也不差把人拉进去了吧。

    • TAT.dnt

      TAT.dnt 2017 年 1 月 30 日

      赞。我不是管理员。申请应该就能进吧~~

      • 徐志伟 2017 年 2 月 6 日

        大神,您写的observejs是个好东西,但是需要配合什么用才能发挥到极致啊,难道只是简单的监听任意对象,其属性发生改变则触发相应的回掉函数(由开发者决定观察什么,决定响应什么)。我目前只能觉得observejs能做的就是当对象的属性改变时,可以触发回掉;写动画也可以不需要requestAnimationFrame,只要对象的属性改变就调用回调函数(如果回调函数执行的时间比较长(>100ms),函数只能放在主线程,等待前一个执行完毕挨个执行,这样好吗?requestAnimationFrame起码是个异步的)。希望大神,指点一下observerjs的其它用途,感觉你们团队内部,还配合这其它高大上的库。

  3. exoticknight 2016 年 12 月 31 日

     越来越好啦

发表评论