08335 / hivui-platform-template
hivui平台项目模板
Newer
Older
hivui-platform-template / project / hivuiMain / views / layout / components / allFuncMenu / index.vue
<template>
    <div class="boxMain" ref="allFuncMenu" @mouseenter="showBox" @mouseleave="hideBox" :style="allFuncMenuStyle">
        <div class="searchBox">
            <input type="text" :placeholder="$t('hivuiMain_allfuncmenu_text')" 
            v-model.trim="searchWord" 
            @keyup="handleSeachKeyUp"
            />
            <i class="iconfont icon-search"></i>                   
        </div>
        <div ref="listBox" class="listBox" :style="listBoxStyle">
            <ul class="level1List" v-if="searchWord==''">
                <template v-for=" (item1,index) in menus">
                    <li :key="'level1-'+index" :class="item1.type!='dir'&&!item1.children&&'funcBtn'" :title="item1.type!='dir'?item1.name:''" @click="funcClick(item1)" v-if="item1.isShow">
                        <itemIcon :item="item1"></itemIcon>
                        <span>{{item1.name}}</span>
                        <ul class="level2List" v-if="item1.children && item1.children.length">
                            <template v-for=" (item2,index) in item1.children">
                                <li :key="'level2-'+index" :class="item2.type!='dir'&&!item2.children&&'funcBtn'" :title="item2.type!='dir'?item2.name:''" @click="funcClick(item2)" v-if="item2.isShow">
                                    <itemIcon :item="item2"></itemIcon>
                                    <span>{{item2.name}}</span>
                                    <!-- <i v-if="item2.type=='dir'" class="el-icon-caret-bottom"></i> -->
                                    <ul class="level3List" v-if="item2.children && item2.children.length">
                                        <template v-for=" (item3,index) in item2.children">
                                            <menus :class="'funcBtn level3Dir'" :key="'level3-'+index" :level="0" :parent="allFuncMenu" :menuitem="item3" v-if="item3.isShow&&item3.children&&item3.children.length"></menus>
                                            <li v-else-if="item3.isShow" :class="'funcBtn'" :key="'level3-'+index" :title="item3.type!='dir'?item3.name:''" @click="funcClick(item3)" >
                                                <itemIcon :item="item3"></itemIcon>
                                                <span>{{item3.name}}</span>
                                            </li>
                                        </template>
                                    </ul>
                                </li>
                            </template> 
                        </ul>
                    </li>
                </template>
                <li v-show="menus.length==0">
                    {{$t("hivuiMain_nodata")}}
                </li>
            </ul>
            <!-- 搜索结果列表 -->
            <ul class="searchResultList" v-else>
                <li v-for=" (searchItem,index) in searchList" :key="'search-'+index" :data-index="index" :class="seldIndex==index&&'itemSeld'" :title="searchItem.name" @click="funcClick(searchItem)">
                    <itemIcon :item="searchItem"></itemIcon>
                    <span>{{searchItem.name}}</span>
                </li>
                <li v-show="searchList.length==0">
                    {{$t("hivuiMain_nodata")}}
                </li>
            </ul>
        </div>
        
    </div>
</template>
<script>
import pinyin from 'js-pinyin';
import itemIcon from './itemIcon';
import menus from './menus';
import cloneDeep from 'lodash/cloneDeep';
export default {
    inject:['addTab'],
    provide(){
        let me=this;
        return {
            showAllFuncBox(){
                me.showBox();
            },
            hideAllFuncBox(){
                me.hideBox();
            },
        }
    },
    props:{
        triggerObj:{
            type:Object,
        }
    },
    components:{
        itemIcon,menus
    },
    data(){
        return {
            searchWord:"",
            searchList:[],
            seldIndex:0,
            allFuncMenuStyle:"",
            listBoxStyle:"",
            loading:false,
            loadingTime:200,
            triggerTimer:null,
        };
    },
    computed:{
        menus(){
            //调整排序,功能页面排前面
            function sort(list){
                let dirList=list.filter(item=>{
                    return item.type=="dir";
                });
                let funcList=list.filter(item=>{
                    return item.type!="dir";
                });
                list=funcList.concat(dirList);
                for(let item of list){
                    if(item.type=='dir'){
                        if(item.children&&item.children.length>0){
                            item.children=sort(item.children);
                        }
                    }
                }
                return list;
            }
            return sort(cloneDeep(this.$store.getters.menus));
        },
    },
    watch:{ 
        searchWord(newVal,oldVal){
            this.seldIndex=0;
            this.doSearch(newVal);
        }
    },
    mounted(){
        let me=this;
        
    },
    methods:{ 
        //获取搜索列表数据
        doSearch(cnKey){
            let me=this;
            let list = [],
                records = me.$store.getters.menusList,
                hideMenuItemList = me.$store.getters.hideMenuItemList;
            let py = pinyin.getCamelChars(cnKey).toLocaleLowerCase();
            let  re = new RegExp("^[a-zA-Z]+$");
            for(let i=0,l=records.length;i<l;i++){
                let item = records[i];
                if(!(!item.isShow || hideMenuItemList.indexOf(item.parentId)!=-1)){
                    if(item.parentId==-1&&item.type=="root"){
                        continue;
                    }
                    if(re.test(cnKey)){
                        let y = pinyin.getCamelChars(item.name).toLocaleLowerCase();
                        if(y.indexOf(py)>-1 && item.type!='dir'){
                            list.push(item);
                        }  
                    }else{
                        if(item.name.indexOf(cnKey)>-1 && item.type!='dir'){
                            list.push(item);
                        }  
                    }   
                }
            }
            me.$set(me,'searchList',list);
            me.$nextTick(()=>{
                me.countHeight();
                me.$refs.listBox.scrollTo({
                    top:0,
                });
            });
        },
        //搜索时方向键及回车事件
        handleSeachKeyUp(evt){
            let colNum=4;
            let me=this;
            if(evt.keyCode==37){//左方向
                if(me.seldIndex==0){
                    me.seldIndex=me.searchList.length-1;
                }else{
                    me.seldIndex--;
                }
                me.scrollSearchList("up");
            }
            if(evt.keyCode==38){//上方向
                if(me.seldIndex-colNum<0){
                    let re1=me.searchList.length%colNum;
                    let re2=(me.seldIndex+1)%colNum;
                    let count=re2>re1 ? (colNum-re2+re1) : (re1-re2);
                    me.seldIndex=((me.searchList.length-count>0) ? me.searchList.length-count : me.searchList.length) - 1;
                }else{
                    me.seldIndex-=colNum;
                }
                me.scrollSearchList("up");
            }
            if(evt.keyCode==39){//右方向
                if(me.seldIndex<me.searchList.length-1){
                    me.seldIndex++;
                }else{
                    me.seldIndex=0;
                }
                me.scrollSearchList("down");
            }
            if(evt.keyCode==40){//下方向
                if(me.seldIndex+colNum>me.searchList.length-1){
                    me.seldIndex=(me.seldIndex+colNum)%colNum;
                }else{
                    me.seldIndex+=colNum;
                }
                me.scrollSearchList("down");
            }
            if(evt.keyCode==13){//回车
                let item = me.searchList[me.seldIndex];
                if(item.type== "link"){
                    window.open(item.resUrl,item.name);
                    return;
                }
                me.addTab(item);//inject 提供的方法只能 传一个参数
                me.searchWord = "";
                me.seldIndex = 0;
                me.$refs.listBox.scrollTo({
                    top:0,
                });
                me.hideBox();
            }
        },
        //滚动搜索菜单列表
        scrollSearchList(type){
            let me=this;
            let _scrollTop=0;
            let listDom=me.$refs.listBox;
            let listDomObj=listDom.getBoundingClientRect();
            let currItemDom=listDom.querySelector("[data-index='"+me.seldIndex+"']");
            let currItemDomObj=currItemDom.getBoundingClientRect();
            //在可视范围内不滚动
            if(currItemDomObj.top+currItemDomObj.height<(listDomObj.height+listDomObj.top) && currItemDomObj.top>listDomObj.top){
                return;
            }
            if(type=="up"){
                _scrollTop=currItemDomObj.top-listDomObj.top+listDom.scrollTop;
            }else if(type=="down"){
                _scrollTop=currItemDomObj.top+currItemDomObj.height-listDomObj.top-listDomObj.height+listDom.scrollTop;
            }
            me.$refs.listBox.scrollTo({
                top:_scrollTop,
                behavior:"smooth",
            });
        },
        //菜单功能项点击事件
        funcClick(item){
            if(item.type!="dir"&&item.resUrl){
                if(item.type== "link"){
                    window.open(item.resUrl,item.name);
                    return;
                }
                this.addTab(item);//inject 提供的方法只能 传一个参数
                this.hideBox();
            }
        },
        //显隐共用样式(设置定位)
        commonFunc(){
            let me=this;
            let btnOffset=me.triggerObj;
            let ww=window.outerWidth;
            let boxleft=btnOffset.left+me.$refs.allFuncMenu.offsetWidth;
            me.isShowAllFuncMenu=me.isShowAllFuncMenu?false:true;
            me.allFuncMenuStyle=`top:${btnOffset.top+btnOffset.height}px;`;
            if(boxleft>ww){
                me.allFuncMenuStyle+=`right:10px;`;
            }else{
                me.allFuncMenuStyle+=`left:${btnOffset.left}px;`;
            }
        },
        //计算高度
        countHeight(){
            let me=this;
            let wh=window.outerHeight;
            let listContentH=me.$refs.listBox.children[0].scrollHeight+50;
            let boxheight=listContentH > (wh/2) ? wh/2 : listContentH;
            me.allFuncMenuStyle+=`opacity:1;z-index:99;height:${boxheight+2}px;`;//2:弹窗边框
            me.listBoxStyle=`height:${boxheight-50}px;`;//50:搜索框高度
        },
        //显示弹窗
        showBox(){
            let me=this;
            me.commonFunc();
            me.countHeight();
            me.loading=true;
            clearTimeout(me.triggerTimer);
            me.triggerTimer=setTimeout(()=>{
                me.loading=false;
            },me.loadingTime);
        },
        //隐藏弹窗
        hideBox(){
            let me=this;
            me.commonFunc();
            //me.loading=true;
            me.allFuncMenuStyle+=`z-index:99;`;
            setTimeout(()=>{
                if(!me.loading){
                    me.allFuncMenuStyle='';
                    me.loading=false;
                }
            },me.loadingTime);
        },
    }
}
</script>
<style lang="less" scoped>
    .boxMain{
        position:absolute;
        top:-9999px;
        z-index:-1;
        opacity: 0;
        transition-duration: 0.2s;
        transition-property: opacity,height;
        width: 800px;
        height:0;
        background-color: #fff;
        border:1px solid #ddd;
        box-shadow: 0 2px 10px 0 #ddd;
        padding:50px 0px 0;
        box-sizing: border-box;
        overflow: auto;
        *{
            box-sizing: border-box;
        }
        ul,li{
            padding: 0;
            margin:0;
            list-style: none;
        }
        ul{
            display: flex;
            flex-wrap: wrap;
            width:100%;
        }
        li{
            flex:0 0 100%;
            color:#333;
            span{
                overflow: hidden;
                text-overflow: ellipsis;
            }
        }
        &.show{
            z-index:99;
            opacity: 1;
        }
        li.funcBtn{
            display: flex;
            align-items: center;
            flex:0 0 25%;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            padding-right:20px;
            color:#888;
            &:hover>span{
                color:#06c;
                cursor: pointer;
            }
        }
        .searchBox{
            position: absolute;
            top:0;
            left:0;
            right:0;
            margin:auto;
            width: calc(100% - 60px);
            background-color: #fff;
            input{
                border:none;
                border-bottom:1px solid #ddd;
                padding:0 10px 0 40px;
                line-height: 48px;
                width: 100%;
                outline: none;
                &::placeholder{
                    color:#ccc;
                }
            }
            i{
                position: absolute;
                top:0;
                bottom:0;
                left:10px;
                margin:auto;
                width:20px;
                height:20px;
                line-height:20px;
                text-align: center;
                font-size: 20px;
                font-weight: bold;
                color:#ccc;
            }
        }
        .listBox{
            overflow: auto;
            padding:0 30px;
        }
        .level1List{
            margin-bottom:30px;
            padding: 10px;
            &>li{
                line-height: 36px;
                font-size: 18px;
                font-weight: bold;
            }
        }
        .level2List{
            padding: 10px;
            &>li{
                line-height: 32px;
                font-size: 14px;
                font-weight: bold;
                &.funcBtn{
                    font-size: 13px;
                    font-weight: normal;
                }
            }
        }
        .level3List{
            padding:0px 0 10px;
            display:flex;
            flex-wrap: wrap;
            &>li{
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
                line-height: 32px;
                font-size: 13px;
                &.funcBtn{
                    font-weight: normal;
                }
            }
            .level3Dir{
                color:#333;
            }
        }
        .searchResultList{
            width: 100%;
            display:flex;
            flex-wrap: wrap;
            padding-bottom:30px;
            li{
                flex:0 0 25%;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
                line-height: 32px;
                font-size: 14px;
                display: flex;
                align-items: center;
                cursor: pointer;
                &:hover{
                    color:#06c;
                }
            }
            .itemSeld{
                color:#f00;
            }
        }
    }
</style>