一般如果要做一些简单的动画css3就可以了,但是如果要绘制一些复杂的动画那就得用到js,在这里我们会css和js结合一起制作动画
通过自定义变量在行内样式中添加变量 <div :style="{'--w':'100px','--h':'100px'}"></div>
然后在css样式中就可以直接使用了 .box{width:var(--w);height:var(--h);}
<template>
<!-- 添加购物测的按钮-->
<div class="addShop" @mousedown="handleMousedown" @mousemove="handleMousemove" @mouseup="handleMouseup"
ref="addShop"
@click="handleAddShop">+
</div>
<!--购物车-->
<div class="shopCar" ref="shopCar">购物车</div>
</template>
<script setup>
import {onMounted, ref, reactive, onUnmounted} from "vue";
const addShop = ref(null)
const shopCar = ref(null)
//添加按钮的尺寸
const PLUS_SIZE = 40
const isDragging = ref(false)
const handleAddShop = () => {
//添加移动的按钮
const plusDiv = document.createElement('div')
plusDiv.className = "plus";
plusDiv.id = "plus";
plusDiv.innerHTML = `<span class="plusIcon">+</span>`;
//获取添加购物元素的范围信息
const addShopRect = addShop.value.getBoundingClientRect();
//计算该元素到视口左边的距离
const left = addShopRect.left + addShopRect.width / 2 - PLUS_SIZE / 2, top = addShopRect.top - PLUS_SIZE;
//获取购物测元素的范围信息
const shopCarRect = shopCar.value.getBoundingClientRect();
//计算添加元素与购物车元素的距离x和高度
const x = shopCarRect.left + shopCarRect.width / 2 - PLUS_SIZE / 2 - left,
y = shopCarRect.top - PLUS_SIZE / 2 - top;
//给移动的动画添加属性
plusDiv.style.setProperty('--left', `${left}px`)
plusDiv.style.setProperty('--top', `${top}px`)
plusDiv.style.setProperty('--x', `${x}px`)
plusDiv.style.setProperty('--y', `${y}px`)
//在动画结束后移除元素
plusDiv.addEventListener('animationend', () => {
plusDiv.remove()
})
isDragging.value = false
//把元素添加到视口
const appDiv = document.getElementById('app')
appDiv.appendChild(plusDiv)
}
onMounted(() => {
document.addEventListener('mousemove', handleMousemove)
document.addEventListener('mouseup', handleMouseup)
})
onUnmounted(() => {
document.removeEventListener('mousemove', handleMousemove)
document.removeEventListener('mouseup', handleMouseup)
})
//记录鼠标移动的距离
const x = ref(0)
const y = ref(0)
const handleMousedown = (event) => {
isDragging.value = true
x.value = event.clientX
y.value = event.clientY
}
const handleMousemove = (event) => {
if (isDragging.value) {
if (event.clientY > 0 && (event.clientY <= (document.body.getBoundingClientRect().height - PLUS_SIZE)) && event.clientX > 0 && (event.clientX <= (document.body.getBoundingClientRect().width - PLUS_SIZE))) {
y.value = event.clientY
addShop.value.style.top = `${event.clientY}px`
addShop.value.style.left = `${event.clientX}px`
}
}
}
const handleMouseup = () => {
isDragging.value = false
}
</script>
.plus {
position: fixed;
left: 0;
top: 0;
width: 40px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
}
.plusIcon {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
background: #2a36ff;
color: #FFFFFF;
font-size: 32px;
border-radius: 50%;
}
.plus {
left: var(--left);
top: var(--top);
}
.shopCar {
position: fixed;
bottom: 5%;
left: 5%;
background: #2a36ff;
color: #FFFFFF;
height: 40px;
width: 80px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 10px;
cursor: pointer;
}
.addShop {
position: fixed;
right: 0;
top: 30%;
background: #2a36ff;
color: #fff;
width: 40px;
height: 40px;
display: flex;
font-size: 32px;
justify-content: center;
align-items: center;
border-radius: 50%;
cursor: pointer;
user-select: none;
}
@keyframes moveY {
to {
transform: translateY(var(--y));
}
}
.plus {
--duration: 0.8s;
animation: moveY var(--duration) cubic-bezier(.5, -0.5, 1, 1);
}
@keyframes moveX {
to {
transform: translateX(var(--x));
}
}
.plusIcon {
animation: moveX var(--duration) linear;
}