<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>