通过自定义组件学习Vue系列(四)【导航菜单】(附源码)

实现效果

用途:一般用于后台管理系统的导航菜单,附源码,有兴趣的朋友可以参考自行修改。

涉及到知识点:

1、flex布局,用好flex,能够解决布局的大部分问题
2、鼠标经过改变子元素样式
3、鼠标经过改变父元素样式
4、动态修改class
5、css画三角形
6、数组数据过滤

整理一下 flex 常用的样式类,了解更多可以查看源码 src/assets/css/base.css

/* flex布局 */
.flex {
    display: flex;
}

/* 竖向排列 */
.flex-col {
    flex-direction: column;
}

/* 横向排列 */
.flex-row {
    flex-direction: row;
}

/* 水平居中 */
.flex-center-sp {
    justify-content: center;
}

/* 垂直居中 */
.flex-center-cz {
    align-items: center;
}

/* 两端靠边 */
.flex-space-between {
    justify-content: space-between;
}

/* 平均分布空间 */
.flex-space-evenly {
    justify-content: space-evenly;
}

鼠标经过改变子元素样式,了解更多可以查看源码 src/assets/css/ui.css


/* 经过主菜单时左边亮块 */
.ui-menu .item :hover .left {
    display: block;
    background-color: #3dc886;
    width: 4px;
    height: 100%;
}


/* 经过主菜单时文字显示 */
.ui-menu .item .master:hover .text {
    color: #fff;
}

鼠标经过改变父元素样式,  hover 无法实现了,要用到 @mouseover(鼠标经过事件) @mouseout(鼠标离开事件)


……
                <div class="lh detail flex pointer cannotselect" :class="{'active': activeDetailItemId==detail.id}"
                     @click="dClick(detail)" @mouseover="mouseover(item.id)" @mouseout="mouseout()">
                   <div class="text">{
     
     {detail.name}}</div>
                </div>
……


        data() {
            return {
                activeMasterItemId : null,
                activeDetailItemId: null
            }
        },
        methods:{
            mouseover(mid) {
                this.activeMasterItemId = mid
            },
            mouseout() {
                this.activeMasterItemId = 0
            },
  ……


        }

动态修改class,此处的activeMasterItemId是子元素鼠标经过后进行的赋值,父元素根据此值来显示样式

……
                    <div class="left margin-right-l" :class="{'active': activeMasterItemId==item.id}" ></div>
                    <div class="text" :class="{'active-text': activeMasterItemId==item.id}" >{
      
      {item.name}}</div>  
  

css画三角形


/*  倒三角 */
.ui-menu .not-active-flag {
    display: inline-block;
    height: 0;
    width: 0;
    margin-top: 14px;
    border-top: 7px solid #babbbd;
    border-bottom: 7px solid transparent;
    border-left: 7px solid transparent;
    border-right: 7px solid transparent;
}

/*  正三角 */
.ui-menu .active-flag {
    display: inline-block;
    height: 0px;
    width: 0;
    margin-top: 7px;
    border-top: 7px solid transparent;
    border-bottom: 7px solid #fff;
    border-left: 7px solid transparent;
    border-right: 7px solid transparent;    
}

数组数据过滤

                let find = this.menuData.filter(d=>d.id==mid);
                if (find.length> 0) {
                    find[0].open = !find[0].open ;
                }

组件代码

<template>
     <div class="flex flex-col ui-menu  padding-top-s scroll">
        
        <div class="item" v-for="item in menuData">
            <div class="lh master flex flex-space-between pointer cannotselect" @click="mClick(item.id)">
                <div class="flex flex-center-cz">
                    <div class="left margin-right-l" :class="{'active': activeMasterItemId==item.id}" ></div>
                    <div class="text" :class="{'active-text': activeMasterItemId==item.id}" >{
      
      {item.name}}</div>               
                </div>
                <div class="margin-right-l"
                :class="{'not-active-flag': !item.open, 'active-flag': item.open}" ></div>
            </div>
            <div class="details" v-if="item.open" v-for="detail in item.children">
                <div class="lh detail flex pointer cannotselect" :class="{'active': activeDetailItemId==detail.id}"
                     @click="dClick(detail)" @mouseover="mouseover(item.id)" @mouseout="mouseout()">
                   <div class="text">{
      
      {detail.name}}</div>
                </div>
            </div>
        </div>
    
     </div>

</template>

<script>
    export default {
        name:'Menu',
        props:{
            menuData:{}
        },
        data() {
            return {
                activeMasterItemId : null,
                activeDetailItemId: null
            }
        },
        methods:{
            mouseover(mid) {
                this.activeMasterItemId = mid
            },
            mouseout() {
                this.activeMasterItemId = 0
            },
            mClick(mid){
                let find = this.menuData.filter(d=>d.id==mid);
                if (find.length> 0) {
                    find[0].open = !find[0].open ;
                }
            },
            dClick(item) {
                this.activeDetailItemId = item.id;
                this.$emit("menuClick", item)
            }

        }
    }
</script>

调用组件代码

<template>
    <div class="body">
      <div class="table">
        <div class="filter font-bold">组件库(四) 导肮菜单</div>
        <div class="margin-top-l margin-left-l flex flex-center-cz">
          <my-menu :menuData="menuData" @menuClick="menuClick" class="my-menu"></my-menu>
        </div>
      </div>
    </div>
</template>

<script>
/*
       名称:组件库(四) 导肮菜单
       作者:唐赢   
       时间:2023-3-12
*/

  import MyMenu from '@/components/menu/Menu'
  export default {
    name: 'MenuDemo',
    components: {
        MyMenu
    },
    data () {
      return {
        menuData : [
            {
                "id":1,
                "name":"基础资料",
                "url":"",
                "level":1,
                "open": false,
                "children":[
                    {
                        "id":2,
                        "name":"经销商",
                        "url":"",
                        "level":2
                    },
                    {
                        "id":3,
                        "name":"品牌档案",
                        "url":"",
                        "level":2
                    }
                ]
            },
            {
                "id":4,
                "name":"业务管理",
                "url":"",
                "level":1,
                "open": false,
                "children":[
                    {
                        "id":5,
                        "name":"入库单",
                        "url":"",
                        "level":2
                    },
                    {
                        "id":6,
                        "name":"出库单",
                        "url":"",
                        "level":2
                    }
                ]
            }

        ]

        
      }
    },
    methods: {
        menuClick(item) {
            console.log("click", item);
        }
    }
  }
</script>

<style scoped>
  .body {
    display: flex;
    justify-content: center;
    margin-top: 73px;
    width: 100%;    
  }
  .table {
    background-color: #fff;
    width: 1080px;
    min-height: 800px;
    box-shadow: 0px 3px 6px rgba(0, 0, 0, .1);
    margin-bottom: 10px;
  }
  .filter {
    display: flex;
    height: 60px;
    align-items:center;
    background-color: #fff;
    font-size: 18px;
    justify-content: center;
    border-bottom: 1px solid rgba(0, 0, 0, .2);;
  }
  .my-menu {
    width: 350px;
    height: 500px;
  }

</style>

  

相关文章:

通过自定义组件学习Vue系列(五)【下拉多选框】(附源码)

通过自定义组件学习Vue系列(四)【导航菜单】(附源码)

通过自定义组件学习Vue系列(三)【仿浏览器缩放比例】(附源码)

通过自定义组件学习Vue系列(二)【时间轴】(附源码)

通过自定义组件学习Vue系列(一)【开关按钮】(附源码)

猜你喜欢

转载自blog.csdn.net/gdgztt/article/details/129939500