前两天遇到个需求:
交互显示XXXX(一个div)动画逐渐缩小,飞入右上角个人中心
当时遇到这个需求的时候我是懵逼的。跟她说实现不了吧?太复杂了。但我刚跟她说完就又很气,就这点东西我都做不出来?主要还是懒呀。开发周期不是很长,以下就跟大家分享一下我的一个实现思路以及实现代码:
实现思路 ___
- 找轮子,可能是没有能发现闪光的眼睛,只找到了扳手 —— html2canvas。
- 获取到需要添加飞入动画的div,以及个人中心(就一个div)的四维:距离顶部、距离左边、宽度、高度。
- 解决css动画问题(这里采用依靠css实现动画的方式,而不是js过多的干涉dom,影响性能)。
- 考虑封装整体功能,以便后续使用与升级优化。
实现代码 ___
这里采用了一种链式调用的写法,确保各功能相互独立,便于后期优化升级。
import html2canvas from "html2canvas" //扳手
class htmlToPic {
/**
* @param {dom} html 需要添加动画的dom
* @param {dom} target 移动至dom
*/
constructor(html, target) {
if (!!html == false || !!target == false) {
throw "创建实例时,请传入需要加入动画的dom与目标dom"
}
this.html = html // 获取到的执行动画dom
this.target = target // 获取到的目标dom
this.getPic = html2canvas(html)
this.pic = null
this.domImg = null
this.body = document.querySelector("body")
this.img = new Image()
console.log(html.offsetLeft)
// html四维
this.imgTop = html.offsetTop + "px"
this.imgLeft = html.offsetLeft + "px"
this.imgWidth = html.offsetWidth + "px"
this.imgHeight = html.offsetHeight + "px"
// target四维
this.targetTop = target.offsetTop + "px"
this.targetLeft = target.offsetLeft + "px"
this.targetWidth = target.offsetWidth + "px"
this.targetHeight = target.offsetHeight + "px"
console.log(this)
// 配置项(可选)
this.options = {
time: 2000, // 动画时间 1000 = 1s
className: "htmlToPic--dom", // 动画img的class
opacity: { // 动画开始、结束时透明度
start: 1,
end: .4
}
}
}
/**
* 初始化
*
* @param {function} f 初始化实例回调
* @param {object} option 可选配置项
*/
init(f = false, option = false) {
if (!!option) {
this.options = {
...this.options,
...option
}
}
this.getPic.then(canvas => {
console.info("====成功初始化html2canvas====")
this.pic = canvas.toDataURL('image/png')
f && f(this)
})
this.img.className = this.options.className
this.img.style.top = this.imgTop
this.img.style.left = this.imgLeft
this.img.style.width = this.imgWidth
this.img.style.height = this.imgHeight
this.img.style.zIndex = 10000
this.img.style.position = "absolute"
this.img.style.opacity = this.options.opacity.start
this.img.style.transition = "all " + this.options.time / 1000 + "s ease-in-out"
// 阻止多次调用
this.init=function(){
console.error("一次初始化只能有一个实例")
}
return "方法体第一个参数为回调函数,初始化的试了会通过此函数回调回来"
}
/**
* 展示
*
* @param {function} f 展示实例后回调
*/
show(f = false) {
this.img.src = this.pic
this.body.appendChild(this.img)
console.info("====成功插入dom====")
this.domImg = document.querySelector(`.${this.options.className}`)
f && f()
return this
}
/**
* 展示
*
* @param {boolean} flag 移动后是否删除 默认不删除
* @param {function} f 移动后回调
*/
move(flag = false, f = false) {
const _this = this;
setTimeout(() => {
console.log("====开始移动====",_this)
_this.domImg.style.opacity = _this.options.opacity.end
_this.domImg.style.top = _this.targetTop
_this.domImg.style.left = _this.targetLeft
_this.domImg.style.width = _this.targetWidth
_this.domImg.style.height = _this.targetHeight
setTimeout(() => {
if (flag) {
_this.domImg.remove()
}
f && f()
}, _this.options.time);
}, 20)
return this
}
/**
* 删除
*/
remove() {
// this.domImg.remove()
console.info("====删除img成功====")
}
}
export default htmlToPic
使用的时候就接近于
let dom = document.querySelector('.box1')
let tar = document.querySelector('.box2')
// 自定义选项
let option = {
time: 3000, // 动画时间 1000 = 1s
className: 'htmlToPic--dom', // 动画img的class
opacity: {
// 动画开始、结束时透明度
start: 1,
end: 0.4,
},
}
let htmlPic = new htmlToPic(dom, tar)
// init 中返的 e 就是创建的实例
// 主要是考虑到html2canvas,需要异步获取转换过来的canvas,所以需要改变一下结构
htmlPic.init((e) => {
e.show().move(true)
},option)
如果有更漂亮的写法欢迎来讨论,让我们一起有条不紊的持续进步。
喜欢的话不妨点个小小的赞与关注,您的赞与关注将是我源源不断的前进动力。