Weex實現炫酷的側滑菜單效果

最近在在bindingX,使用bindingX結合weex手勢可以比較輕鬆實現很炫酷的富交互效果,且性能很好,這裏實現一個側滑菜單的效果。weex中集成並使用bindingX看篇BindingX在weex中使用

老規矩,先上效果圖

側滑菜單效果圖
側滑菜單效果圖

側滑組件源碼:

<!--側滑菜單實現-->
<template>
   <div class="container" :style="{backgroundColor:backgroundColor}">
       <div ref="left"   class="left" :style="{height:height,left:0,width:leftWidth*2}">
            <slot name="left"></slot>
       </div>
       <div ref="right" @touchstart="touchstart" class="right" :style="{height:height}">
           <slot name="right"></slot>
       </div>
   </div>
</template>

<script>
    var modal=weex.requireModule('modal');
    var binding = weex.requireModule('binding');
    import { parse } from 'bindingx-parser'
    export default {
        name: "slider-menu",
        props:{
            timeFunction:{
                default:"linear",
                type:String
            },
            animationT:{
                default:200,
                type:Number
            },
            leftWidth:{
                default:200,
                type:Number
            },
            backgroundColor:{
                default:"#ffa00f",
                type:String
            },
        },
        data(){
            return{
                height:0,
                dx:0,
                endX:0,
                scaleX:1,
                scaleY:1,
                isSlide:false,
                animationIng:false,
            }
        },
        methods:{
            touchstart(e){
                let self=this;
                if(this.animationIng){
                    return;
                }
                let rightRef=self.$refs.right.ref;
                let translate_x_expression="";
                let scaleX_expression='';
                let scaleY_expression='';
                if (!self.isSlide){
                    translate_x_expression=`x>0?x+0:x-x`;
                    scaleX_expression=`x>0?1-(x/1200):1`;
                    scaleY_expression=`x>0?1-(x/1200):1`;
                }else{
                    translate_x_expression=`x+${this.leftWidth}`;
                    scaleX_expression=`x>0?${self.scaleX}-(x/1200):${self.scaleX}-((1-${self.scaleX})/200)*x`;
                    scaleY_expression=`x>0?${self.scaleY}-(x/1200):${self.scaleY}-((1-${self.scaleY})/200)*x`;
                }
                binding.bind({
                    anchor:rightRef,
                    eventType:'pan',
                    props:[
                        {
                            element:rightRef,
                            property:'transform.translateX',
                            expression:parse(translate_x_expression)
                        },
                        {
                            element:rightRef,
                            property:'transform.scaleX',
                            expression:parse(scaleX_expression)
                        },
                        {
                            element: rightRef,
                            property: 'transform.scaleY',
                            expression: parse(scaleY_expression)
                        }
                    ]
                },function (event) {
                    if(event.state==='end'){
                        self.dx=event.deltaX;
                        // modal.alert({message:self.scale })
                        if (!self.isSlide){
                            if(self.dx<0){
                                return;
                            }
                            self.scaleX = self.scaleX-event.deltaX/1200;
                            self.scaleY = self.scaleY-event.deltaX/1200;
                        }else{
                            // modal.alert({message:event })
                            self.scaleX = self.scaleX-event.deltaX/1200;
                            self.scaleY = self.scaleY-event.deltaX/1200;
                            // modal.alert({message:self.scaleX })
                        }
                        self.exeAnimation();
                    }
                })
            },
            //生成表達式
            getLeftExpression(){
                let self=this;
                let final_x=0;
                let final_scaleX=0;
                let final_scaleY=0;
                let changed_x=0;
                let opacity_expression="";
                let scale_expression='';
                //如果不是收起狀態
                if (!self.isSlide){
                    final_x =this.leftWidth;
                    changed_x =this.leftWidth-Math.abs(self.dx);
                    final_scaleX = (1-400/1200);
                    final_scaleY = (1-400/1200);
                    let changed_scaleX=final_scaleX-self.scaleX;
                    let changed_scaleY=final_scaleY-self.scaleY;
                    scale_expression = self.timeFunction+"(t,"+1+","+-0.5+","+self.animationT+")";
                    opacity_expression=self.timeFunction+`(t,${1},${0},${self.animationT})`;
                }else{
                    final_x = this.leftWidth;
                    changed_x = -self.dx;
                    final_scaleX = (1-400/1200);
                    final_scaleY = (1-400/1200);
                    let changed_scaleX=final_scaleX-self.scaleX;
                    let changed_scaleY=final_scaleY-self.scaleY;
                    scale_expression = self.timeFunction+"(t,"+0.5+","+0.5+","+self.animationT+")";
                    opacity_expression=self.timeFunction+`(t,${0},${1},${self.animationT})`;
                }
                return {
                    opacity_expression:opacity_expression,
                    scale_expression:scale_expression,
                }
            },
            //生成表達式
            getExpression(type){
                let self=this;
                let final_x=0;
                let final_scaleX=0;
                let final_scaleY=0;
                let changed_x=0;
                let translate_x_expression="";
                let scaleX_expression='';
                let scaleY_expression='';
                if(type){
                    self.dx=0;
                    self.isSlide=false;
                    final_x = 0;
                    final_scaleX = 1;
                    final_scaleY = 1;
                    changed_x = -this.leftWidth-self.dx;
                    let changed_scaleX=1-self.scaleX;
                    let changed_scaleY=1-self.scaleY;
                    translate_x_expression = self.timeFunction+ `(t,${this.leftWidth+self.dx},${changed_x},${self.animationT})`;
                    scaleX_expression=self.timeFunction+`(t,${self.scaleX},${changed_scaleX},${self.animationT})`;
                    scaleY_expression=self.timeFunction+`(t,${self.scaleY},${changed_scaleY},${self.animationT})`;
                    return {
                        translate_x_expression:translate_x_expression,
                        scaleX_expression:scaleX_expression,
                        scaleY_expression:scaleY_expression,
                        final_scaleX:final_scaleX,
                        final_scaleY:final_scaleY
                    }
                }
                //如果不是收起狀態
                if (!self.isSlide){
                    if(Math.abs(self.dx)<this.leftWidth) { // 復位
                        self.isSlide=false;
                        final_x = 0;
                        final_scaleX = 1;
                        final_scaleY = 1;
                        changed_x = 0-self.dx;
                        let changed_scaleX=1-self.scaleX;
                        let changed_scaleY=1-self.scaleY;
                        translate_x_expression = self.timeFunction+"(t,"+self.dx+","+changed_x+","+self.animationT+")";
                        scaleX_expression=self.timeFunction+`(t,${self.scaleX},${changed_scaleX},${self.animationT})`;
                        scaleY_expression=self.timeFunction+`(t,${self.scaleY},${changed_scaleY},${self.animationT})`;
                    } else if(Math.abs(self.dx) >this.leftWidth) { // 執行
                        self.isSlide=true;
                        final_x =this.leftWidth;
                        changed_x =this.leftWidth-Math.abs(self.dx);
                        final_scaleX = (1-400/1200);
                        final_scaleY = (1-400/1200);
                        let changed_scaleX=final_scaleX-self.scaleX;
                        let changed_scaleY=final_scaleY-self.scaleY;

                        translate_x_expression = self.timeFunction+"(t,"+self.dx+","+changed_x+","+self.animationT+")";
                        scaleX_expression=self.timeFunction+`(t,${self.scaleX},${changed_scaleX},${self.animationT})`;
                        scaleY_expression=self.timeFunction+`(t,${self.scaleY},${changed_scaleY},${self.animationT})`;
                    }
                }else{
                    if(self.dx<0) { // 復位
                        self.isSlide=false;
                        final_x = 0;
                        final_scaleX = 1;
                        final_scaleY = 1;
                        changed_x = -this.leftWidth-self.dx;
                        let changed_scaleX=1-self.scaleX;
                        let changed_scaleY=1-self.scaleY;
                        translate_x_expression = self.timeFunction+ `(t,${this.leftWidth+self.dx},${changed_x},${self.animationT})`;
                        scaleX_expression=self.timeFunction+`(t,${self.scaleX},${changed_scaleX},${self.animationT})`;
                        scaleY_expression=self.timeFunction+`(t,${self.scaleY},${changed_scaleY},${self.animationT})`;
                    } else if(self.dx>0) { // 執行
                        self.isSlide=true;
                        final_x = this.leftWidth;
                        changed_x = -self.dx;
                        final_scaleX = (1-400/1200);
                        final_scaleY = (1-400/1200);
                        let changed_scaleX=final_scaleX-self.scaleX;
                        let changed_scaleY=final_scaleY-self.scaleY;
                        translate_x_expression = self.timeFunction+`(t,${this.leftWidth+self.dx},${changed_x},${self.animationT})`;
                        scaleX_expression=self.timeFunction+`(t,${self.scaleX},${changed_scaleX},${self.animationT})`;
                        scaleY_expression=self.timeFunction+`(t,${self.scaleY},${changed_scaleY},${self.animationT})`;
                    }
                }

                return {
                    translate_x_expression:translate_x_expression,
                    scaleX_expression:scaleX_expression,
                    scaleY_expression:scaleY_expression,
                    final_scaleX:final_scaleX,
                    final_scaleY:final_scaleY
                }
            },
            //執行動畫
            exeAnimation(userDo){
                let self=this;
                this.animationIng=true;
                let rightRef=self.$refs.right.ref;
                let { translate_x_expression,
                    scaleX_expression,
                    scaleY_expression,
                    final_scaleX,
                    final_scaleY} =
                    this.getExpression(userDo);
                binding.bind({
                    eventType:'timing',
                    exitExpression: parse(`t>${this.animationT}`),
                    props:[
                        {
                            element:rightRef,
                            property:'transform.translateX',
                            expression:parse(translate_x_expression)
                        },
                        {
                            element:rightRef,
                            property:'transform.scaleX',
                            expression:parse(scaleX_expression)
                        },
                        {
                            element:rightRef,
                            property:'transform.scaleY',
                            expression:parse(scaleY_expression)
                        }
                    ]
                },function (event) {
                    if(event.state === 'end'||event.state === 'exit') {
                        self.scaleX = final_scaleX;
                        self.scaleY = final_scaleY;
                        self.animationIng=false;
                        // self.exeLeftAnimation()
                        binding.unbindAll()
                    }
                })
            },
            exeLeftAnimation(){
                let self=this;
                this.animationIng=true;
                let leftRef=self.$refs.left.ref;
                let { opacity_expression,
                    scaleX_expression,
                   } =
                    this.getLeftExpression();
                binding.bind({
                    eventType:'timing',
                    exitExpression: parse(`t>${this.animationT}`),
                    props:[
                        {
                            element:leftRef,
                            property:'transform.opacity',
                            expression:parse(opacity_expression)
                        },
                        {
                            element:leftRef,
                            property:'transform.scale',
                            expression:parse(scaleX_expression)
                        },
                    ]
                },function (event) {
                    if(event.state === 'end'||event.state === 'exit') {
                        binding.unbindAll()
                    }
                })
            }
        },
        created(){
            let height=weex.config.env.deviceHeight;
            let width=weex.config.env.deviceWidth;
            this.height= height/width*750+60;``
            // modal.alert({message:this.height})
        }
    }
</script>

<style scoped>
     .container{
         width: 1200px;
         flex-direction: row;
     }
    .left{
        width: 200px;
        position: absolute;
        top:0;
    }
    .right{
        width: 1200px;
        background-color: #ffffff;
    }

</style>

使用方法:

<template>
    <div>
        <slider-menu  ref="menue" :left-width="250" timeFunction="easeOutBounce">
            <div slot="left" >
                <div @click="selectItem" style="width: 250px;height: 100px;align-items: center;justify-content: center;margin-top: 400px">
                     <text style="font-size: 34px;font-weight: bold;color: white">菜單一</text>
                </div>
                <div @click="selectItem" style="width: 250px;height: 100px;align-items: center;justify-content: center">
                    <text style="font-size: 34px;font-weight: bold;color: white">菜單二</text>
                </div>
                <div @click="selectItem" style="width: 250px;height: 100px;align-items: center;justify-content: center">
                    <text style="font-size: 34px;font-weight: bold;color: white">菜單三</text>
                </div>
            </div>
            <div slot="right">
                 <head title="測試slider-menu "></head>
            </div>
        </slider-menu>
    </div>
</template>

<script>
    import SliderMenu from "../components/sliderMenu.vue";
    import Head from "../components/head.vue";
    export default {
        components: {
            Head,
            SliderMenu},
        name: "slider-menu-demo",
        data() {
            return {

            }
        },
        methods:{
            selectItem(){
                this.$refs.menue.exeAnimation(1);
            }
        }
    }
</script>

<style scoped>

</style>

 在代碼簡潔以及動畫表現方面還有一些提升空間,可以自己酌情修改一下。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章