需求分析:进入产品列表,点击缩略图旁+号,有个该商品被动态添加到购物车的动画。让我们实现这个动画吧。
如下图:
通过动图可以发现移动的曲线是蜿蜒曲折的,这就用到了贝塞尔曲线。
贝塞尔曲线链接
实现原理:先创建一个隐藏的圆点在购物车icon那里。当点击+
号时,让圆点先移动到当前点击+
的位置并让其显示。然后开始动画,让圆点移动回到原来的购物车icon位置并让其隐藏。
使用vue提供的vue动画和贝塞尔曲线来实现移动动画
vue动画详情链接
<template>
<div>
<van-nav-bar
title="图书战术"
left-text="返回"
left-arrow
@click-left="onClickLeft"
>
<template #right>
<van-icon name="cart-o" size="18" />
<div class="shop_car_icon">{
{ shopCarNum }}div>
template>
van-nav-bar>
<div class="bookmall__list">
<ul>
<li class="bookmall__item" v-for="(item, index) in testList" :key="index" @click="goBookUrl(item)">
<div class="bookmall__item-left">
{
{ item }}
div>
<div class="bookmall__item-right">
<h5>{
{ item }} <span>{
{ item }}span>h5>
<p><span>分类:span>{
{ item }}<span style="margin-left: 10px;padding: 10px;" class="shopCarAdd" @click.stop="addToShopCars"><van-icon name="add" color="rgb(238, 57, 57"/>span>p>
<p class="bookmall__item-right-tag"><span>标签:span>{
{ item }}p>
<p class="bookmall__item-right-sub2">
{
{ item }}
p>
div>
li>
ul>
div>
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter"
>
<div class="shop_car_ball" v-show="shopCarBall">
<div class="linner_ball">
<van-icon name="add" color="rgb(238, 57, 57"/>
div>
div>
transition>
div>
template>
.van-nav-bar {
position: fixed;
width: 100%;
}
.shop_car_icon {
position: absolute;
top: 10px;
right: -8px;
font-size: 10px;
background-color: rgb(238, 57, 57);
border-radius: 50%;
text-align: center;
color: rgb(82, 80, 80);
line-height: 0;
display: table-cell;
vertical-align: middle;
padding: 8px 2px;
}
.bookmall__list {
padding-top: 40px;
.bookmall__item {
display: flex;
padding: 10px;
border-bottom: 1px a #000;
.bookmall__item-left {
flex: 25%;
margin-right: 5px;
img {
width: 90px;
}
}
.bookmall__item-right {
flex: 75%;
height: 130px;
overflow: hidden;
h5 {
font-size: 16px;
span {
margin-left: 65px;
font-weight: 400;
font-size: 12px;
color: rgb(107, 106, 106);
}
}
p {
font-size: 13px;
}
.bookmall__item-right-tag {
color: rgb(119, 118, 118);
}
}
}
}
.bookmall__item .bookmall__item-right-sub2 ::after {
content: "...";
position: absolute;
right: 0;
bottom: 0;
}
.shop_car_ball {
position: fixed;
top: 10px;
right: 12px;
z-index: 9;
font-size: 16px;
// transition: all .25s cubic-bezier(0.49, -0.29, 0.75, 90.41);
/* 贝塞尔曲线 */
transition: all .25s cubic-bezier(.17, .86, .73, .14);
.linner_ball {
transition: all .25s linear;
}
}
export default {
data () {
return {
shopCarNum: window.localStorage.getItem('shopcarnum') || 0,
shopCarBall: false,
shopCarBallEl: null,
ss: null,
// demo测试数据
testList: new Array(1,2,3,4,5)
}
},
methods: {
addToShopCars (e) {
this.shopCarBallEl = e.target
this.shopCarBall = true
},
// 动画开始
beforeEnter (el) {
// 获取元素的大小及其相对于视口的位置
const dom = this.shopCarBallEl.getBoundingClientRect()
const offsetX = window.innerWidth - dom.left - 16
const offsetY = dom.top - 22
el.style.display = ''
// y轴是曲直向上的,x轴是蜿蜒的向右的
el.style.transform = `translate3d(0, ${
offsetY}px, 0)`
const linnerBall = el.querySelector('.linner_ball')
linnerBall.style.transform = `translate3d(-${
offsetX}px, 0, 0)`
},
enter (el, done) {
// 触发重绘,来实现动画的移动过程
this.ss = document.body.offsetHeight
el.style.transform = `translate3d(0, 0, 0)`
const linnerBall = el.querySelector('.linner_ball')
linnerBall.style.transform = `translate3d(0, 0, 0)`
el.addEventListener('transitionend', done)
},
afterEnter (el) {
this.shopCarBall = false
el.style.display = 'none'
this.shopCarNum++
}
},
watch: {
// 监听shopCarNum属性,只考虑新增。新增时储存本地做永久化处理
shopCarNum (newValue) {
window.localStorage.setItem('shopcarnum', newValue)
}
}
}
这样我们就实现购物车的动态添加demo。