css實現3D長方形,可旋轉
阿新 • • 發佈:2019-02-12
先上圖:
實現過程:
1、長方體六個面
before,after, top ,buttom,left,right
2、每個面不同旋轉角度
before: 向前移動一半width寬度,transform: translateZ(${width/2}px)
after: 向後移動一半width寬度、y軸旋轉180度 transform: `translateZ(${-width/2}px) rotateY(180deg)`
top: 以top為軸,x軸旋轉90度,向後移動一半寬度 transform-origin: top; transform: `rotateX(90deg) translate(0, ${-width/2}px)`}
bottom: 以bottom為軸,x軸旋90度,向後移動一半寬度, 放縮width/height,width: `${width}px`, height: `${height}px`,transform: `rotateX(90deg) translate(0, ${-width/2}px) scale(0,width/height)`
left: 以left為軸,y軸旋轉-90度,向左移動一半寬度,{transform: `rotateY(-90deg) translate(${-width/2}px, 0)`}
right: 以right為軸,y軸旋轉90度,向右移動一半寬度,{transform: `rotateY(90deg) translate(${width/2}px, 0)`}
3、在外圈div做旋轉
4、程式碼:box.vue
<template> <div class="box-wrap"> <div class="box" id="box" style="transform: rotateX(0deg) rotateY(0deg);" :style="{width: `${width}px`, height: `${height}px`}" @mousedown="mousedown" @mousemove="mousemove" @mouseup="mouseup" @mouseout="mouseup"> <div id="face-before" class="face face-before" :style="{transform: `translateZ(${width/2}px)`}"> <slot name="before" ></slot> </div> <div id="face-after" class="face face-after" :style="{transform: `translateZ(${-width/2}px) rotateY(180deg)`}"> <slot name="after"></slot> </div> <div id="face-top" class="face face-top" :style="{width: `${width}px`, height: `${width}px`, transform: `rotateX(90deg) translate(0, ${-width/2}px)`}"> <slot name="top"></slot> </div> <div id="face-bottom" class="face face-bottom" :style="{width: `${width}px`, height: `${height}px`,transform: `rotateX(90deg) translate(0, ${width/2}px) scale(0,width/height)`}"> <slot name="buttom"></slot> </div> <div id="face-left" class="face face-left" :style="{transform: `rotateY(-90deg) translate(${-width/2}px, 0)`}" > <slot name="left"></slot> </div> <div id="face-right" class="face face-right" :style="{transform: `rotateY(90deg) translate(${width/2}px, 0)`}"> <slot name="right"></slot> </div> </div> </div> </template> <script> export default { name: 'box', data() { return { canMove: false, startX: 0, startY: 0, currentDeg: 0, } }, props: { width: { type: Number, default: 300, }, height: { type: Number, default: 300, }, }, methods: { // mouseenter(ev) { // 按下滑鼠 // this.canMove = true; // this.startX = ev.clientX; // this.startY = ev.clientY; // }, mousedown(ev) { // 按下滑鼠 this.canMove = true; this.startX = ev.clientX; this.startY = ev.clientY; }, mousemove(ev) { // 滑鼠移動 if(this.canMove) { const $box = document.getElementById('box'); const obj = this.getTransform(); const x = this.startX - ev.clientX; const y = this.startY - ev.clientY; const newx = (obj.x - (y / this.height * 180)); const newy = (obj.y - (x / this.width * 180)); console.log('x / this.width * 90===', x / this.width * 180); console.log('newy===', newy); this.startX = ev.clientX; this.startY = ev.clientY; $box.style.transform = `rotateX(-5deg) rotateY(${newy}deg)`; this.currentDeg = newy; } }, mouseout() { // 滑鼠離開 if(this.canMove) { const $box = document.getElementById('box'); const value = this.currentDeg % 90; if(Math.abs(value) >= 45) { $box.style.transform = `rotateX(0deg) rotateY(${this.currentDeg + (90 - value) + 0.01}deg)`; }else { $box.style.transform = `rotateX(0deg) rotateY(${this.currentDeg - value + 0.01}deg)`; } this.canMove = false; } }, showAuto() { const $box = document.getElementById('box'); $box.style['transform-origin'] = 'center'; $box.style.transform = `rotateX(-20deg) rotateY(20deg)`; }, showTop() { const $box = document.getElementById('box'); $box.style['transform-origin'] = 'center'; $box.style.transform = `rotateX(-89.999deg) rotateY(0deg)`; }, showLeft() { const $box = document.getElementById('box'); $box.style['transform-origin'] = 'center'; $box.style.transform = `rotateX(0deg) rotateY(89.999deg)`; }, mouseup() { // 滑鼠離開 if(this.canMove) { const $box = document.getElementById('box'); const value = this.currentDeg % 90; if(Math.abs(value) >= 45) { if(value < 0) { $box.style.transform = `rotateX(0deg) rotateY(${this.currentDeg - (90 - Math.abs(value)) + 0.01}deg)`; }else { $box.style.transform = `rotateX(0deg) rotateY(${this.currentDeg + (90 - Math.abs(value)) + 0.01}deg)`; } }else { if(value < 0) { $box.style.transform = `rotateX(0deg) rotateY(${this.currentDeg - value + 0.01}deg)`; }else { $box.style.transform = `rotateX(0deg) rotateY(${this.currentDeg + value + 0.01}deg)`; } } this.canMove = false; } }, reset() { const $box = document.getElementById('box'); $box.style.transform = `rotateX(-20deg) rotateY(20deg)`; }, getTransform() { const $box = document.getElementById('box'); const ts = $box.style.transform.split(' '); const xs = ts[0].indexOf('X('); const xe = ts[0].indexOf('deg'); const ys = ts[1].indexOf('Y('); const ye = ts[1].indexOf('deg'); const x = ts[0].substring(xs + 2, xe); const y = ts[1].substring(ys + 2, ye); return { x, y, } }, }, mounted() { }, } </script> <style lang="scss" scoped> .box-wrap { .box { position: relative; z-index: 6; margin: auto; transform-style: preserve-3d; transform-origin: center, center; transition: transform 1s; .face { position: absolute; width: 100%; height: 100%; opacity: 0.3; font-size: 30px; } .face-before { transform: translateZ(150px); background-color: rgb(0, 255, 170); text-align: left; } .face-after { transform-origin: center; transform: translateZ(-150px) rotateX(-180deg); background-color: #0088cc; } .face-top { transform-origin: top; transform: rotateX(90deg) translate(0, -150px); background-color: rgb(255, 0, 170); } .face-bottom { transform-origin: bottom; transform: rotateX(-90deg) translate(0, 150px); background-color: rgb(0, 255, 85); } .face-left { transform-origin: left; transform: rotateY(-90deg) translate(-150px, 0); background-color: rgb(255, 208, 0); } .face-right { transform-origin: right; transform: rotateY(90deg) translate(150px, 0); background-color: rgb(255, 208, 0); } } } </style>
5、使用:
<template>
<div class="app-home">
<header class="header">
<div class="content">
<div class="header-left">
<span class="title">凡夫俗子</span>
<span class="desc">我們追尋夢想, 因為那最令人開心</span>
</div>
<div class="header-right">
</div>
</div>
</header>
<box :height="300" :width="600" ref="box">
<template slot="before">
<div>before</div>
</template>
<template slot="after">
<div>after</div>
</template>
<template slot="left">
<div>left</div>
</template>
<template slot="right">
<div>right</div>
</template>
<template slot="top">
<div>top</div>
</template>
<template slot="bottom">
<div>bottom</div>
</template>
</box>
</div>
</template>
<script>
import box from '@/web/components/box3.vue'
export default {
name: 'HelloWorld',
data () {
return {
boxWidth: 1152,
boxHeight: 600,
}
},
components: {
box
},
methods: {
goTopClick() {
this.$refs.box.showTop();
},
goLeftClick() {
this.$refs.box.showLeft();
},
showAuto() {
this.$refs.box.showAuto();
}
},
mounted() {
this.boxHeight = document.documentElement.clientHeight - 15;
window.onresize = () => {
this.boxHeight = document.documentElement.clientHeight - 15;
};
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss">
.app-home {
background-color: #f5f5f5;
.header {
width: 100%;
height: 60px;
margin-bottom: 15px;
background-color: rgba(255,255,255,.5);
.content {
width: 1200px;
min-width: 1200px;
margin: auto;
overflow: auto;
padding-left: 24px;
padding-right: 24px;
color: #00bbd3;
.header-left {
.title {
display: inline-block;
vertical-align: middle;
margin-right: 24px;
line-height: 60px;
font-size: 25px;
letter-spacing: 0.2em;
}
.desc {
display: inline-block;
vertical-align: middle;
line-height: 60px;
font-size: 14px;
}
}
.header-right {
font-size: 12px;
}
}
}
}
</style>