如何实现一个tooltip组件
- VUE代码如下
vue
<template>
<div class="box" ref="boxRef">
<div class="box-item"></div>
<div class="box-item"></div>
<div class="box-item"></div>
<div class="box-item"></div>
<div class="box-item"></div>
<div class="box-item"></div>
</div>
</template>
<script setup lang="ts">
import {onMounted, ref} from 'vue';
const boxRef = ref<HTMLElement | null>(null);
// 获取transform 的rotateY的值
const getRotateYFromTransform = (transform: string) => {
return +transform.replace('rotateY(', '').replace('deg)', '');
}
// 计算div的transform rotateY的值 保证rotateY的值在0-360之间
const getRangeRotateY = (rotateY: number) => {
if (rotateY > 360) {
return rotateY - 360;
} else if (rotateY < 0) {
return rotateY + 360;
} else {
return rotateY;
}
}
onMounted(() => {
// 计算鼠标在box div的拖动距离
let x = 0;
let isDown = false;
boxRef.value!.onmousedown = (e) => {
isDown = true;
x = e.clientX;
document.onmousemove = (e) => {
if (isDown) {
const moveX = e.clientX - x;
const box = boxRef.value!;
const rotateY = getRangeRotateY(getRotateYFromTransform(box.style.transform!) + moveX)
boxRef.value!.style.transform = `rotateY(${rotateY}deg)`;
}
}
document.onmouseup = (e) => {
isDown = false;
document.onmousemove = document.onmouseup = null;
}
};
})
</script>
<style lang="scss" scoped>
.box {
margin: auto;
width: 100px;
height: 100px;
background-color: yellow;
transform: rotateY(30deg);
position: relative;
transform-style: preserve-3d;
// animation: ani 5s linear infinite;
}
// 360 /6 = 60
$items: 60;
@for $i from 1 through 6 {
::v-deep(.box-item):nth-child(#{$i}) {
position: absolute;
width: 100px;
height: 100px;
color: #fff;
background-color: rgba(random(255), random(255), random(255), 1);
transform: rotateY($items*$i+deg) translateZ(400px);
transform-style: preserve-3d;
}
}
@keyframes ani {
from {
transform: rotateX(-10deg) rotateY(0deg);
}
to {
transform: rotateX(-10deg) rotateY(360deg);
}
}
</style><template>
<div class="box" ref="boxRef">
<div class="box-item"></div>
<div class="box-item"></div>
<div class="box-item"></div>
<div class="box-item"></div>
<div class="box-item"></div>
<div class="box-item"></div>
</div>
</template>
<script setup lang="ts">
import {onMounted, ref} from 'vue';
const boxRef = ref<HTMLElement | null>(null);
// 获取transform 的rotateY的值
const getRotateYFromTransform = (transform: string) => {
return +transform.replace('rotateY(', '').replace('deg)', '');
}
// 计算div的transform rotateY的值 保证rotateY的值在0-360之间
const getRangeRotateY = (rotateY: number) => {
if (rotateY > 360) {
return rotateY - 360;
} else if (rotateY < 0) {
return rotateY + 360;
} else {
return rotateY;
}
}
onMounted(() => {
// 计算鼠标在box div的拖动距离
let x = 0;
let isDown = false;
boxRef.value!.onmousedown = (e) => {
isDown = true;
x = e.clientX;
document.onmousemove = (e) => {
if (isDown) {
const moveX = e.clientX - x;
const box = boxRef.value!;
const rotateY = getRangeRotateY(getRotateYFromTransform(box.style.transform!) + moveX)
boxRef.value!.style.transform = `rotateY(${rotateY}deg)`;
}
}
document.onmouseup = (e) => {
isDown = false;
document.onmousemove = document.onmouseup = null;
}
};
})
</script>
<style lang="scss" scoped>
.box {
margin: auto;
width: 100px;
height: 100px;
background-color: yellow;
transform: rotateY(30deg);
position: relative;
transform-style: preserve-3d;
// animation: ani 5s linear infinite;
}
// 360 /6 = 60
$items: 60;
@for $i from 1 through 6 {
::v-deep(.box-item):nth-child(#{$i}) {
position: absolute;
width: 100px;
height: 100px;
color: #fff;
background-color: rgba(random(255), random(255), random(255), 1);
transform: rotateY($items*$i+deg) translateZ(400px);
transform-style: preserve-3d;
}
}
@keyframes ani {
from {
transform: rotateX(-10deg) rotateY(0deg);
}
to {
transform: rotateX(-10deg) rotateY(360deg);
}
}
</style>