getBoundingClientRect() 实现购物车飞入案例
此案例结合了vue实现
<!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>getBoundingClientRect</title>
<style>
* {
margin: 0;
padding: 0;
}
#app {
padding: 10px;
}
ul,
li {
list-style: none;
}
li {
display: flex;
align-items: center;
}
li img {
width: 150px;
height: 80px;
}
.cart {
position: absolute;
width: 150px;
height: 80px;
transition: all .5s ease-in;
}
.car-shop {
position: fixed;
right: 10px;
bottom: 10px;
width: 120px;
height: 80px;
line-height: 80px;
text-align: center;
background-color: #ff1234;
color: #fff;
font-size: 16px;
}
</style>
</head>
<body>
<div id="app">
<ul class="list-wrap">
<li class="list-item" v-for="(list,index) in lists" @key="list.id" ref="liAry">
<img :src="list.cover" alt="">
<button @click="addCart(index)">加入购物车</button>
</li>
</ul>
<!-- cart用于做动画,所以用transition 包裹起来 -->
<transition @enter="enter" @after-enter="afterenter">
<span class="cart" v-if="isShow"></span>
</transition>
<div class="car-shop" ref="carShop">
购物车
</div>
</div>
</body>
</html>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
isShow: false, //控制动画元素显示隐藏
currentIndex: -1, //当前选中的索引
lists: [{
cover: 'http://www.javascriptpeixun.cn/files/course/2019/08-02/203853de0f7a753037.png',
id: 1
},
{
cover: 'http://www.javascriptpeixun.cn/files/course/2019/07-30/202711f70eea987000.jpg',
id: 2
},
{
cover: 'http://www.javascriptpeixun.cn/files/course/2019/09-04/211735f96b30549920.jpg',
id: 3
}
]
},
methods: {
addCart(index) {
this.isShow = true;
this.currentIndex = index
},
enter(el, done) { //el是操作动画的元素,done是完成动画后执行的函数
// 进入动画的时候
// 1,获取到点击的哪一个li和li的位置
// 2,把span的位置定位到当前li的位置上,并设置背景图片为当前li的img图片
// 3,计算出购物车的位置
// 4,计算出span到购物车移动的位置
let li = this.$refs.liAry[this.currentIndex]; //获取当前点击的li
//=>1li的位置
let {
x,
y
} = li.getBoundingClientRect();
//=>2span位置设置
el.style.left = `${x}px`;
el.style.top = `${y}px`;
el.style.background =
`url('${this.lists[this.currentIndex]['cover']}') no-repeat center center / 100% 100%`;
//=>3购物车位置 给x,y取一个别名
let {
x: a,
y: b
} = this.$refs.carShop.getBoundingClientRect();
el.style.transform = `translate3d(${a-x}px,${b-y}px,0) scale(0)`;
// 监听动画结束执行done回调
el.addEventListener('transitionend', done, false);
},
afterenter() {
this.isShow = false;
}
}
})
</script>
getBoundingClientRect() 方法解读
以下参考来源于MDN
- Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。
- 返回值是一个 DOMRect 对象。
对象包含了一组用于描述边框的只读属性——left、top、right和bottom,单位为像素。除了 width 和 height 外的属性都是相对于视口的左上角位置而言的。
图例位置
- 空边框盒(译者注:没有内容的边框)会被忽略。如果所有的元素边框都是空边框,那么这个矩形给该元素返回的 width、height 值为0,left、top值为第一个css盒子(按内容顺序)的top-left值。
- 当计算边界矩形时,会考虑视口区域(或其他可滚动元素)内的滚动操作,也就是说,当滚动位置发生了改变,top和left属性值就会随之立即发生变化(因此,它们的值是相对于视口的,而不是绝对的)。如果你需要获得相对于整个网页左上角定位的属性值,那么只要给top、left属性值加上当前的滚动位置(通过window.scrollX和window.scrollY),这样就可以获取与当前的滚动位置无关的值。