使用Vue实现手风琴菜单效果

使用vue的指令个事件冒泡委托给一个事件处理
使用Vue实现手风琴菜单效果
使用

    <vertical-menu :menuList="dataList" :initIndex="0"  @fold-body="foldHandle" @go-state="goWhere"></vertical-menu>



 data() {
        return {
            isMin:false,
            dataList:[
                {
                    path: 'home',
                    name: '服务组件',
                    icon:"icon-shouye",
                    children:[

                        {
                            name: '通知组件',
                            path: 'layout',
                        },

                    ]
                },
                {
                    icon:"icon-shouye",
                    name: 'UI组件',
                    path: '',
                    children:[
                        {
                            name: '布局组件',
                            path: 'layout',
                        },
                        {
                            name: '按钮组件',
                            path: 'button',
                        },
                        {
                            name: '弹框组件',
                            path: 'modal',
                        },
                        {
                            name: '富文本',
                            path: 'editor',
                        }

                    ]
                },
                {
                    icon:"icon-shouye",
                    name: '通信组件',
                    path: '',
                    children:[
                        {
                            name: '实时聊天',
                            path: 'actualChat',
                        }

                    ]
                }
            ]
        }
    },
    methods:{

        foldHandle(isFold){
            this.isMin = isFold;
        },
        goWhere(item){
            if(item.type===1){
                this.$router.push(`/utils/${item.path}`);
            }

        }



    }

<div class="c-vertical">
    <ul  @click="clickHandle">
        <li :class="['menu-item',{'parent-active':index===pIndex&&isActive}]" :data-val="index"
            v-for="(item,index) in menuList"
            :key="index"
        >
            <a href="javascript:;" class="clearFix">
                <i :class="['iconfont',item.icon]"></i>
                <span>
                    {{item.name}}
                </span>
                <i :class="['iconfont','icon-xiangyoujiantou',{'rotate-icon':pIndex===index&&isActive}]" v-if="item.children"></i>
            </a>
            <ul v-slide="item.children&&index===pIndex&&isActive">
                <li :class="['child-item',{'child-active':cIndex===num}]"
                    :data-val="num"
                    v-for="(unit,num) in item.children" :key="num"
                >
                    <a>
                        <span>{{unit.name}}</span>
                    </a>
                </li>
            </ul>
        </li>
    </ul>
    <div :class="['fold-bottom',{'transform-min':isTransform}]" @click="transformHandle">
       <span>
           <i :class="['iconfont','icon-xiangyoujiantou',{'fold-icon':isTransform}]"></i>
       </span>
    </div>
</div>
    props:{
        menuList:{
            type:Array,
            default:""
        },
        initIndex:{
            type:Number,
            default:0
        },

    },
    data() {
        return {
            pIndex:this.initIndex,
            cIndex:0,
            childHeight:0,
            isActive:true,
            isTransform:false
        }
    },
    created(){

    },

    methods:{
        clickHandle(event){
            let isChild = true,pNum;
            let parentTarget = getTarget(event,"menu-item");
            let childTarget = getTarget(event,"child-item");
            isChild =this.isTouchChild(childTarget);
            pNum = dataSet(parentTarget,"val");
            if(isChild){
                this.cIndex = dataSet(childTarget,'val');
                if(this.menuList[this.pIndex].children){
                    this.$emit("go-state",{
                        name:this.menuList[this.pIndex].children[this.cIndex].name,
                        path:this.menuList[this.pIndex].children[this.cIndex].path,
                        type:this.menuList[this.pIndex].children[this.cIndex].type
                    });
                }

            }else{
                if(this.pIndex===pNum){
                    this.isActive=!this.isActive;
                }else{
                    this.isActive = true;
                    this.pIndex = pNum;
                }
                this.cIndex = 0;
                this.$emit("go-state",{
                    name:this.menuList[this.pIndex].name,
                    path:this.menuList[this.pIndex].path,
                    type:this.menuList[this.pIndex].type
                });


            }
        },
        isTouchChild(childTarget){
            if(childTarget===NaN || childTarget===null || childTarget===undefined){
               return false;
            }else{
                return true;
            }
        },
        transformHandle(){
            this.isTransform=!this.isTransform;
            this.isActive=false;
            this.$emit("fold-body",this.isTransform);
        }
    },
    directives: {
        slide: {
            inserted:function(el,binding){
                if(binding.value){
                    let height = el.scrollHeight;
                    el.style.cssText = `height:${height}px;`;
                }
            },
            update: function (el,binding) {
                let newVal = binding.value,oldVal=binding.oldValue;
                if(newVal===oldVal){
                    return;
                };
                if(binding.value){
                    let height = el.scrollHeight;
                    el.style.cssText = `height:${height}px;`;
                }else{
                    el.style.cssText=`height:0;`;
                }
            },


        }
    },
.c-vertical{
  font-size: 16px;
  width: 200px;
  position: relative;
  height: 100%;
  &:after{
    content: "";
    display: block;
    width: 1px;
    height: 100%;
    background: #dcdee2;
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    z-index: 1;
  }
  >ul{
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
  }
  .menu-item >ul{
    height: 0;
    overflow: hidden;
    transition: height 0.3s ease-in-out;
  }
  .menu-item a{
    position: relative;
    display: block;
    height: 45px;
    line-height: 45px;
    padding-left: 15px;
    width:auto;
    color: #515a6e;
  }
  .menu-item >a i:first-child{
    position: absolute;
  }
  .menu-item >a i:last-child{
    float: right;
    margin-right: 20px;
    transition: all 0.3s ease-in-out;
  }
  .menu-item a >span{
    margin-left: 30px;
  }
  .parent-active > a{
    color: #ff9900;
    background-color: #f0faff;
    &:before {
      content: "";
      position: absolute;
      left: 0;
      width: 2px;
      height: 45px;
      background: #34a0ce;
      opacity: 1;
      transition: all .3s;
    }
  }
  .child-active a{
    color: #ff9900;
    background: #f3f3f3;
  }
  .child-item a >span{
    margin-left: 30px;
  }

  .menu-item >a .rotate-icon{
    transform: rotate(90deg);
  }

  .fold-bottom{
    position: absolute;
    bottom: 0;
    line-height: 40px;
    height: 40px;
    background: #f0faff;
    width: 100%;
    transition: width 0.3s ease-in-out;
    span{
      position: relative;
      width: 100%;
      height: 40px;
      display: block;
    }
    i{
      position: absolute;
      transform: rotate(0deg);
      width: 100%;
      text-align: center;
      height: 40px;
      transition: all 0.3s ease-in-out;
    }
    .fold-icon{

      transform: rotate(-180deg);
    }

  }
  .transform-min{
    width: 40px;
  }
}