先来看一个例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<style>
* {
padding: 0;
margin: 0;
}
.con {
width: 100px;
height: 100px;
border: 1px solid green;
margin-bottom: 10px;
display: flex;
justify-content: center;
align-items: center;
perspective: 100px;
}
.rotate, .skew, .scale {
width: 50px;
height: 50px;
border: 1px solid red;
background: yellow;
transition: all .5s;
}
</style>
<body>
<h1>transform3D</h1>
<h3>旋转</h3>
<div class="con">
<div class="rotate">
旋转
</div>
</div>
<h3>斜切</h3>
<div class="con">
<div class="skew">
斜切
</div>
</div>
<h3>缩放</h3>
<div class="con">
<div class="scale">
斜切
</div>
</div>
</body>
<!-- <script src="v3.js"></script> -->
<script>
window.onload = function() {
// 执行顺序,先写的后执行
var rotate = document.querySelector('.rotate');
rotate.addEventListener('touchstart', function() {
rotate.style.transform = 'scale(2)'
})
var skew = document.querySelector('.skew');
skew.addEventListener('touchstart', function() {
skew.style.transform = 'skewX(30deg) skewY(60deg)'
})
var scale = document.querySelector('.scale');
scale.addEventListener('touchstart', function() {
scale.style.WebkitTransform = 'translateZ(-100px)'
})
}
</script>
</html>
大家应该都能看的明白,这是用最原始的方法来实现动画。
简单易懂,但是这样的话我们会写很多重复的代码,rotate.style.transform = 'scale(2)',这样的代码每个事件内部我们都要写一遍。
一般遇到重复代码的时候,就可以考虑下是否可以封装函数了,我们先从最简单的参数出发,这个函数大概需要3个参数,ele元素,prop动画的动作,value,动画的值。
所以我们可以先封装这样一个带有3个参数的函数。
v1.js
/**
*
* @param {*} element // 要操作的元素
* @param {*} prop // 运动属性
* @param {*} value // 具体值
*/
function cssTransform(element, prop, value) {
var transform,
transformValue = ''
if(element.transform === undefined) {
element.transform = transform = Object.create(null); // 纯净的对象 没有原型
}
if(value !== undefined){
element.transform[prop] = value;
transform = element.transform;
for(let name in transform) {
switch(name) {
case 'scale':
case 'scaleX':
case 'scaleY':
transformValue += " " + name + '(' + transform[name] + ")";
break;
case 'rotate':
case 'rotateX':
case 'rotateX':
case 'rotateZ':
case 'skewX':
case 'skewY':
transformValue += " " + name + '(' + transform[name] + "deg)";
break;
default:
transformValue += " " + name + '(' + transform[name] + "px)";
break;
}
element.style.WebkitTransform = element.style.transform = transformValue;
}
} else {
element.transform[prop]
}
}
rotate.addEventListener('touchstart', function() {
cssTransform(rotate, 'scale', 2);
})
每次使用的时候直接调用这样的一个函数,传入相应的值就可以了,是不是看起来简单了很多。
但是这样的写法还是有点繁琐,每次都需要传递3个参数。那能不能再简化一个,只传递两个参数呢?
我们给原型加上一个方法,看会怎样?
HTMLElement.prototype.start = function() {
console.log(this)
}
var rotate = document.querySelector('.rotate');
var skew = document.querySelector('.skew');
rotate.addEventListener('touchstart', function() {
rotate.start()
skew.start()
})
可以看到任何一个元素都会有一个start方法,并且内部的this,就是调用者本身。所以我们可以用这种方式来封装
HTMLElement.prototype.cssTransform = function (prop, value) {
this.transform = Object.create(null);
var transformValue = ''
if(value !== undefined){
this.transform[prop] = value;
for(let name in this.transform) {
switch(name) {
case 'scale':
case 'scaleX':
case 'scaleY':
transformValue += " " + name + '(' + this.transform[name] + ")";
break;
case 'rotate':
case 'rotateX':
case 'rotateX':
case 'rotateZ':
case 'skewX':
case 'skewY':
transformValue += " " + name + '(' + this.transform[name] + "deg)";
break;
default:
transformValue += " " + name + '(' + this.transform[name] + "px)";
break;
}
}
this.style.WebkitTransform = this.style.transform = transformValue;
} else {
return this.transform[prop]
}
}
rotate.addEventListener('touchstart', function() {
console.log(1)
rotate.cssTransform('scale', 2)
})
这样调用,也可以实现需求,是不是又简单了一步。
那还能不能再优化呢?我们能不能只传递一个参数呢?
能不能这样 ele.scale(2);就能达到我们想要的效果呢?下面我们来实现一下
function Transform(ele) {
var transform = Object.create(null);
var transformValue = ''
var props = ['scale', 'scaleX', 'scaleY', 'rotate', 'rotateX', 'rotateY', 'rotateZ', 'skewX', 'skewY']
props.forEach(function(prop) {
Object.defineProperty(ele, prop, {
get: function () {
return ele[prop]
},
set: function (value) {
transform[prop] = value;
transformValue = '';
for (var name in transform) {
switch(name) {
case 'scale':
case 'scaleX':
case 'scaleY':
transformValue += " " + name + '(' + transform[name] + ")";
break;
case 'rotate':
case 'rotateX':
case 'rotateX':
case 'rotateZ':
case 'skewX':
case 'skewY':
transformValue += " " + name + '(' + transform[name] + "deg)";
break;
default:
transformValue += " " + name + '(' + transform[name] + "px)";
break;
}
}
ele.style.WebkitTransform = ele.style.transform = transformValue;
}
})
})
return ele;
}
var ele = Transform(rotate);
ele.addEventListener('touchstart', function() {
console.log(1)
ele.scale = 2
})
亲测一下发现,功能实现了,很神奇,这就是我们的数据驱动思想,我只管发指令,具体怎么实现,内部去做处理。这样是不是比最初的那种封装看上去高大上了许多。