空闲时写了一个3d切换器,灵感来自于转行前画3d工程图,效果如图:
功能:按住鼠标中间,变为3d模式,点击6个页面中的某一个页面,页面旋转放大,恢复到2d图形,3d图消失。再次点击鼠标中间,恢复为3d(含动画效果),按住中键不放,可以左右或者上下拖动,3d图片做720°旋转。
效果可在:此处查看 请使用chrome打开
转动原理:由于正方体只有6个面,所以ul+6个li标签,先做出正方体布局。li标签布局出正方向后,都是相对于ul标签的位置,所以转动ul标签,正方形并不会散架。鼠标水平移动X为ul transform:rotateX(x),鼠标竖直移动Y为ul的transform:rotateY(-Y) 实现转动。-Y是为了一开始竖直方向不要反方向转动。
关于坐标轴正方向:x轴:从左到右,y轴:从上到下,z轴:从屏幕到眼睛。坐标系是会转动的,这点非常恶心。
转动正方向:眼睛在坐标原点观察,逆时针为正方向。比如rotateX(30deg),指绕x轴正方向转30°。看到的那一面是下面往上跑的。
动画布局:ul li 为百分比布局,外层套一层div,实际切换动画由放大缩小div的大小来实现。动画时保存3d图形位置,当然只需要保存ul的转动数据,当按下中键后,恢复ul转动数据,恢复div大小,就可以了。
动画层:1、div tansition all 1s 这个动画是渐变放大与缩小,让ul与li都同时放大缩小。 2、ul transition all 1s 这儿需要动态加入属性,转动时不需要,切换时才需要,效果为切换时转动放大和缩小 3、transiton-group 包裹li标签,这儿动画是为了其中5个标签渐变消失,只留一个标签。
有了上面的理论,基本可以写出来了,这儿贴出代码。
<template> <div class='r' @mousedown='start'> <div ref='odiv' :style='odiv' class='oDiv'> <ul :class='ulClass' :style="ulSty" v-show='showUl' > <transition-group name='tt' enter-active-class='animated fadeIn' leave-active-class='animated fadeOut'> <!--淡入淡出效果--> <li v-for='n in 6' class='li' v-show='showLi[n-1]' ref='n' :key='n' @mousedown='show(n,$event)'> <component :is='msg[n-1]' class='com'></component> </li> </transition-group> </ul> </div> </transition> </div> </template> <script> import pieChart from './pieChart.vue' import barChart from './barChart.vue' import info from './info.vue' import table1 from './table.vue' import baidu from './baidu.vue' import reg from './reg.vue' export default{ data(){ return{ msg:['info','barChart','reg','table1','baidu','pieChart'], n:'', m:true, showUl:true, ulClass:'ul1', flag:true, odiv:{ '300px', height:'300px', margin:'50px auto 100px', transition:'all 1s' }, showLi:[true,true,true,true,true,true], ulSty:{ transform:'' }, changeSty:[], drag:{lastX:0,lastY:0,X:0,Y:0}, } }, components:{ pieChart,barChart,info,table1,baidu,reg }, methods:{ show(n,e){//点击鼠标左键,显示该组件。 if(e.button!=0)return if(!this.flag)return this.flag=false//show某个组件的时候,不能再次show它。 this.n=nthis.odiv.width='100%' this.odiv.height='500px' let b= this.$refs.n[n-1].style let d=getComputedStyle(this.$refs.n[n-1],null)['background'] b.overflow='visible' b.opacity='1' b.background='#fff' b.transition='all 1s' this.showLi=[false,false,false,false,false,false] this.showLi[n-1]=true this.ulClass='ul1 move' let c=getComputedStyle(this.$refs.n[n-1],null)['transform'] this.changeSty=[this.ulSty.transform,c,d] this.ulSty.transform='rotateX(0deg) rotateY(0deg)' b.transform='rotateX(0deg) rotateY(0deg) translateZ(0px)' }, init(){//当点击鼠标中键,恢复3d图形之前的位置。初始化li,ul,div的属性。 let b= this.$refs.n[this.n-1].style b.overflow='hidden' b.opacity='0.8' b.background=this.changeSty[2] b.transform=this.changeSty[1] this.odiv.width='300px' this.odiv.height='300px' this.showLi=[true,true,true,true,true,true] this.ulClass='ul1' this.ulSty.transform=this.changeSty[0] }, start(e){//转动效果 if(e.button!=1)return if(this.n){ this.init() } e.preventDefault(); this.flag=true let x1=e.clientX, y1=e.clientY document.onmousemove=(evt)=>{ let dx=evt.clientX-x1 let dy=evt.clientY-y1 this.drag.X=(this.drag.lastX+dx)%360 this.drag.Y=(this.drag.lastY+dy)%360 this.ulSty.transform='rotateX('+ -this.drag.Y+'deg) rotateY('+this.drag.X+'deg)' } document.onmouseup=()=>{ this.drag.lastX=this.drag.X this.drag.lastY=this.drag.Y document.onmouseup=null document.onmousemove=null } } }, } </script> <style lang="stylus" scoped> .com position:absolute 100% .r 100% wh() 100% height:100% .ul1 position relative wh() transform-style: preserve-3d; .move transition all 1s .li list-style:none wh() position:absolute font-size 40px background:#fff z-index:0 transform-origin:center center overflow:hidden transition:all 1s n(x,y,z) transform:rotateY(y) rotateX(x) translateZ(150px) background:rgba(z,0.8) .li:nth-child(1) n(0,90deg,burlywood) .li:nth-child(2) n(0,-90deg,beige) .li:nth-child(3) n(90deg,0,lightyellow) .li:nth-child(4) n(180deg,0,pink) .li:nth-child(5) n(270deg,0,#20A0FF) .li:nth-child(6) n(0,0,aquamarine) </style>