178 lines
3.8 KiB
Vue
Executable File
178 lines
3.8 KiB
Vue
Executable File
<template>
|
|
<div @mousemove="handleMouseMove">
|
|
<ul id="ul1">
|
|
<li class="ation-li" v-for="(item, index) in props.dataE" :key="index" ref="cards">
|
|
<div class="pt10px pb10px text-15px title">{{ item.title }}</div>
|
|
<div class="text-12px leading-15px sub-title" @click="downloadHandle(item)">
|
|
{{ item.content }}
|
|
</div>
|
|
</li>
|
|
<div id="earth" class="earth"></div>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { nextTick } from 'vue'
|
|
|
|
const emit = defineEmits(['downloadHandle'])
|
|
const downloadHandle = (item) => {
|
|
emit('downloadHandle', item, 5)
|
|
}
|
|
|
|
const props = defineProps({
|
|
//对象写法
|
|
dataE: {
|
|
type: Array, //接受的数据类型
|
|
default: [] //接受默认数据
|
|
}
|
|
})
|
|
|
|
const numCards = ref(10)
|
|
const mouseX = ref(0)
|
|
const mouseY = ref(0)
|
|
const isDragging = ref(false)
|
|
|
|
const handleMouseMove = (event) => {
|
|
const rect = event.currentTarget?.getBoundingClientRect()
|
|
mouseX.value = event.clientX - rect.left
|
|
mouseY.value = event.clientY - rect.top
|
|
}
|
|
|
|
watch(
|
|
() => props.dataE,
|
|
(newValue, oldValue) => {
|
|
nextTick(() => {
|
|
updateRotation()
|
|
// autoRotate();
|
|
})
|
|
}
|
|
)
|
|
|
|
const updateRotation = () => {
|
|
const cardRefs = ref([])
|
|
const earth = ref(null)
|
|
|
|
cardRefs.value = document.querySelectorAll('#ul1 li')
|
|
earth.value = document.getElementById('earth')
|
|
console.log(cardRefs, 1111)
|
|
setInterval(() => {
|
|
numCards.value = cardRefs.value.length
|
|
cardRefs.value.forEach((card, index) => {
|
|
const d = (360 / numCards.value) * index + mouseX.value / 10
|
|
let radian = (d * Math.PI) / 180
|
|
let opacity = (Math.cos(radian) + 1) / 2
|
|
card.style.transform = `rotateY(${d}deg) translateZ(280px) rotateY(${-d}deg)`
|
|
card.style.opacity = opacity * opacity
|
|
|
|
if (Math.abs(d) < 30) {
|
|
card.style.zIndex = 2
|
|
if (earth.value) {
|
|
earth.value.style.transform = 'translateZ(-400px)'
|
|
}
|
|
} else {
|
|
card.style.zIndex = -1
|
|
if (earth.value) {
|
|
earth.value.style.transform = 'translateZ(400px)'
|
|
}
|
|
}
|
|
})
|
|
}, 30)
|
|
}
|
|
|
|
const autoRotate = () => {
|
|
const interval = setInterval(() => {
|
|
if (!isDragging.value) {
|
|
// 自动旋转的速度
|
|
mouseY.value += 1
|
|
}
|
|
}, 30)
|
|
|
|
onMounted(() => {
|
|
clearInterval(interval)
|
|
})
|
|
}
|
|
</script>
|
|
|
|
<style lang="less">
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style: none;
|
|
}
|
|
|
|
html {
|
|
overflow: hidden;
|
|
}
|
|
|
|
body {
|
|
background: #000;
|
|
}
|
|
|
|
#ul1 {
|
|
position: relative;
|
|
width: 139px;
|
|
height: 121px;
|
|
margin: 190px auto;
|
|
background: none;
|
|
transform-style: preserve-3d;
|
|
transform: perspective(1320px) rotateX(-15deg) rotateY(0deg);
|
|
}
|
|
|
|
#ul1 li {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 40px;
|
|
width: 100%;
|
|
height: 100%;
|
|
transition: 1s all ease;
|
|
transform: rotateY(0deg) translateZ(0px);
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
// background: rgba(14, 116, 238, 0.8);
|
|
background-image: url('./images/biaoq.png');
|
|
color: rgb(255, 255, 255);
|
|
line-height: 10px;
|
|
text-align: center;
|
|
padding: 8px 8px 40px;
|
|
/* font-size: 30px; */
|
|
p {
|
|
font-size: 15px;
|
|
}
|
|
}
|
|
|
|
#ul1 li img {
|
|
width: 100%;
|
|
}
|
|
|
|
#earth {
|
|
position: absolute;
|
|
top: 2%;
|
|
left: 50%;
|
|
width: 260px;
|
|
height: 260px;
|
|
margin-top: -222px;
|
|
margin-left: -130px;
|
|
border-radius: 50%;
|
|
background-image: url('./images/diqiu.png');
|
|
background-size: cover;
|
|
transform-style: preserve-3d;
|
|
transform: translateZ(400px);
|
|
z-index: 1;
|
|
transition: transform 0.5s ease;
|
|
}
|
|
.ation-li {
|
|
display: flex;
|
|
align-items: center;
|
|
// justify-content: center;
|
|
flex-direction: column;
|
|
.title {
|
|
color: white;
|
|
}
|
|
.sub-title {
|
|
color: #00e4ff;
|
|
text-align: start;
|
|
}
|
|
}
|
|
</style>
|