最近写了一个带有侧边栏的棱柱旋转动效窗口,结果发现侧边栏有无背景色会影响右侧prism的旋转动效。
- 当siderbar有背景色时,prism的旋转动效会出现类似棱柱左右不相连导致穿透的状况;
- 当siderbar没有背景色时,prism的旋转动效正常。
<template>
<div class="prism-rotate-container">
<div class="sidebar">
<div v-for="(item, index) in faces " :key="index" :class="'sideitem-' + index" class="side_item" :style={backgroundColor:colorarr[index]} v-clicklazy="()=>{rotateClick(index)}">
{{ index }}
</div>
</div>
<div class="prism">
<div v-for="( item, index ) in faces " :key=" index " :class=" 'item-' + index " class="face">
{{ index }}
</div>
</div>
</div>
</template>
<script setup lang="ts">
let props = defineProps<{
numFaces: number
}>();
let faces = reactive<any[]>([]);
const randomColor = () => `#${Math.floor(Math.random() * 16777215).toString(16)}`;
const colorarr = reactive<string[]>([])
//初始化页面宽度
const innerwidth = ref(window.innerWidth-200);
// const innerwidth = ref(300);
//面与y轴夹角
const anglePerFace = computed(() => {
console.log("anglePerFace", anglePerFace)
return 360 / props.numFaces
})
// 将角度转换为弧度
const toRadians = (degrees: number) => {
return degrees * Math.PI / 180;
}
//景深
const perspective = computed(() => {
console.log("perspective", (innerwidth.value / 2) / (Math.tan(toRadians(anglePerFace.value / 2))))
return (innerwidth.value / 2) / (Math.tan(toRadians(anglePerFace.value / 2)))
})
window.addEventListener('resize', () => {
innerwidth.value = window.innerWidth
})
watch(
() => props.numFaces,
() => {
faces = new Array(props.numFaces).fill({ x: 0, y: 0, z: 0 });
nextTick(() => {
updateStyles(props.numFaces);
})
for (let i = 0; i < props.numFaces; i++) {
colorarr.push(randomColor())
}
},
{ deep: true, immediate: true }
)
const updateStyles = (num: number) => {
const box = document.querySelector(".prism-rotate-container");
box?.setAttribute("style", `--perspective:${perspective.value}px`)
degchage(num)
};
const degchage = (num: number) => {
for (let i = 0; i < num; i++) {
const style = `--bg-color: ${colorarr[i]};--text-color:white;--transform-route:${ i * anglePerFace.value}deg;--transform-z:${perspective.value}px;--transform-y:300px`;
const listItem = document.querySelector(`.item-${i}`);
listItem?.setAttribute('style', style);
}
}
const rotateClick = (index:number) => {
const style = `--prismtransform-route:${-index*anglePerFace.value }deg;`;
const Prism = document.querySelector(`.prism`);
Prism?.setAttribute('style', style);
}
</script>
<style scoped lang="scss">
@mixin percentwh($px) {
width: $px;
height: $px;
}
@keyframes rotate {
0% {
transform: rotate3d(0, 1, 0, 0deg);
}
100% {
transform: rotate3d(0, 1, 0, 360deg);
}
}
.prism-rotate-container {
position: relative;
@include percentwh(100%);
background-color: #0075ff;
display: flex;
justify-content: flex-start;
align-items: center;
.sidebar {
width: 200px;
background-color: antiquewhite;
height: 100%;
z-index: 1;
.side_item {
height: 30px;
line-height: 30px;
text-align: center;
}
}
.prism {
flex: 1;
height: 100%;
transform-style: preserve-3d;
transform: rotateY(var(--prismtransform-route));
transition: all 1s linear;
// perspective:calc(var(--perspective)) ;
// background-color: #bbff00;
// animation: rotate 10s infinite linear;
.face {
// transform-style: preserve-3d;
border: 2px solid #000;
@include percentwh(100%);
position: absolute;
background-color: var(--bg-color);
color: var(--text-color);
transform: rotateY(var(--transform-route)) translateZ(var(--transform-z));
// transform-origin: center center var(--perspective);
transition: all 1s linear;
overflow: hidden;
}
}
}
</style>