前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue折腾记 - (1)写一个不大靠谱的二级侧边栏

Vue折腾记 - (1)写一个不大靠谱的二级侧边栏

作者头像
CRPER
发布2018-08-28 16:43:22
4520
发布2018-08-28 16:43:22
举报
文章被收录于专栏:CRPER折腾记CRPER折腾记

前言

本来想写个新手系列教程..发现这种东西一搜索一大把; 那就写点实战类的吧;这篇文章你能学点什么? 当然是一些常见内置指令的用法,组件过渡,遍历的思路等等


效果图

实现思路

  • 过渡用css -
  • 遍历循环判断(比对路由,点击的项名等)
  • 增加标记位来默认展开刷新页面当前所在项
  • 尽量减少DOM的改动,能用v-show的区域绝不用v-if
  • 自定义菜单JSON尽量格式简洁,没有一大坨标记位这些干扰物(越简单越方便后期)

代码

  • 菜单menuList.js
代码语言:javascript
复制
export const MENULIST = [
  {
    menuName: "客户管理",
    menuIcon: "fz-ad-icon-test",
    menuSubLink: [
      {
        menuName: "广告主",
        menuUrl: "/customer/adhost"
      },
      {
        menuName: "渠道",
        menuUrl: "/customer/channel"
      }
    ]
  },
  {
    menuName: "广告管理",
    menuIcon: "fz-ad-guanggao",
    menuSubLink: [
      {
        menuName: "广告新增",
        menuUrl: "/ad/add"
      },
      {
        menuName: "广告审核",
        menuUrl: "/ad/check"
      }
    ]
  },
  {
    menuName: "投放管理",
    menuIcon: "fz-ad-toufang",
    menuSubLink: [
      {
        menuName: "广告位",
        menuUrl: "/puton/area"
      },
      {
        menuName: "广告规格",
        menuUrl: "/puton/regular"
      }
    ]
  },
  {
    menuName: "数据统计",
    menuIcon: "fz-ad-statistics",
    menuSubLink: [
      {
        menuName: "广告主",
        menuUrl: "/status/adhost"
      },
      {
        menuName: "渠道",
        menuUrl: "/status/channel"
      }
    ]
  },
  {
    menuName: "管理者",
    menuIcon: "fz-ad-guanli",
    menuUrl: "/manager"
  },
  {
    menuName: "操作日志",
    menuIcon: "fz-ad-rizhi",
    menuUrl: "/logger"
  }
];
  • Sidebar.vue
代码语言:javascript
复制
<template>
  <div class="sidebar" >
    <ul class="sidebar-menu ">`
      <template v-for="(item ,index) in menulist">
        <li :class="currentUrl === item.menuUrl ? 'active':''">
          <template v-if="item.menuUrl">
            <router-link :to="item.menuUrl" @click.native="toggleName=''">
              <i :class="['fzicon',item.menuIcon]"></i>
              <span>{{item.menuName}}</span>
            </router-link>
          </template>
          <template v-else-if="item.menuSubLink">
            <a href="javascript:;" @click="isToggle(item.menuName,item.defaultActive)">
              <i :class="['fzicon',item.menuIcon]"></i>
              <span>{{item.menuName}}</span>
              <i class="trangle" :class="[config.iconfont, (item.menuName === toggleName) || item.defaultActive? config.icon_expand: config.icon_collapse]">
              </i>
            </a>
            <transition name="sliderToggle" mode="out-in">
              <ul class="tree-menu" v-show="item.menuName === toggleName || item.defaultActive">
                <li v-for="(subitem,subindex) in item.menuSubLink" :key="subitem" :class="currentUrl === subitem.menuUrl ? 'active':''">
                  <router-link :to="subitem.menuUrl">
                    <i :class="subitem.menuIcon"></i>
                    <span>{{subitem.menuName}}</span>
                  </router-link>
                </li>
              </ul>
            </transition>
          </template>
        </li>
      </template>
    </ul>
  </div>
</template>

<script>
import { MENULIST } from './menuList'; // 引入的自定义菜单数据
export default {
  name: 'layout-sidebar',
  data: function () {
    return {
      menulist: MENULIST, // 自定义菜单数据
      currentUrl: '', // 当前浏览器的url
      toggleName: '',  // 菜单子项目名称
      config: {
        'iconfont': 'fzicon', // iconfont的字体
        'icon_collapse': 'fz-ad-jiantou', // 箭头
        'icon_expand': 'fz-ad-jiantou1' // 箭头
      }
    }
  },
  props: ['toggle', 'padMode'], // 这里是用来构成布局响应传递的props,单一组件不用管他
  watch: {
    '$route'() {
      this.currentUrl = this.$route.fullPath; // 实时监测当前路由的变化并且赋值
    }

  },
  methods: {
    isToggle(name, defaultActive) {
      this.clearDefaultActive(); // 清除标记位,是否当前为默认展开
      defaultActive ? false : name !== this.toggleName ? this.toggleName = name : this.toggleName = ''; // 判断展开收缩的核心
    },
    clearDefaultActive() {
      this.menulist.forEach(item => {
        this.$delete(item, 'defaultActive')
      })
    }
  },
  created: function () {
    this.currentUrl = this.$route.fullPath;
    this.$nextTick(() => {
      this.menulist.forEach((item, index) => { // 增加标记位,判断当前url然后自动展开或者激活对应项(刷新默认展开当前url的项)
        if (!item.menuSubLink && item.menuUrl) {
          this.currentUrl === item.menuUrl ? this.$set(item, 'defaultActive', true) : '';
        } else {
          if (item.menuSubLink) {
            item.menuSubLink.forEach((subitem, index) => {
              this.currentUrl === subitem.menuUrl ? this.$set(item, 'defaultActive', true) : '';
            })
          }
        }
      })
    })
  },
  mounted: function () {
  }
}
</script>

<style scoped lang="scss">
// 自定义过渡效果
.sliderToggle-enter-active,
.sliderToggle-leave-active {
  transition: all 0.5s linear;
  height: 100%;
  height: auto;

  overflow: hidden;
}

.sliderToggle-enter,
.sliderToggle-leave-to {
  overflow: hidden;
  padding-top: 0;
  padding-bottom: 0;
  height: 0;
  opacity: 0;
}

// 侧边栏全局样式
.sidebar {
  position: absolute;
  top: 0;
  left: 0;
  padding-top: 68px;
  min-height: 100%;
  z-index: 810;
  transition: all 0.3s linear;
  background-color: #222d32;
  .sidebar-menu {
    list-style: none;
    margin: 0;
    padding: 0;
    white-space: nowrap;
    span {
      cursor: pointer;
    }
    a {
      text-decoration: none;
      color: #8aa4af;
      &:hover {
        color: #fff;
      }
    }
    ul {
      list-style: none;
      margin: 0;
      padding: 0;
      white-space: nowrap;
      overflow: hidden;
    }
    >li {
      position: relative;
      margin: 0;
      padding: 0;
      text-align: left;
      &.active {
        color: #fff;
      }
      >a {
        border-left: 3px solid transparent;
        position: relative;
        padding: 15px 5px 15px 19px;
        display: block;
        font-size: 14px;
        >i {
          padding-right: 4px;
        }
        .trangle {
          float: right;
          padding-right: 10px;
        }
      }
      &.active {
        >a {
          border-left: 3px solid #3c8dbc;
          color: #fff;
        }
      }
      >.tree-menu {
        margin: 0 1px;
        background: #2c3b41;
        list-style: none;
        padding: 0;
        margin: 0;
        .tree-menu {
          padding-left: 20px;
        }
        >li {
          margin: 0;
          &.active {
            >a {
              border-left: 3px solid #3c8dbc;
              color: #fff;
            }
          }
          >a {
            padding: 15px 10px 15px 40px;
            display: block;
            font-size: 14px;
            border-left: 3px solid transparent;
          }
        }
        &.active {
          display: block;
        }
      }
    }
  }

  &.expand {
    width: 230px;
  }

  &.collapse {
    width: 50px;
    .sidebar-menu {
      >li {
        >a {
          padding: 15px 5px 15px 15px;
          span,
          i:last-child {
            display: none;
          }
        }
        .tree-menu {
          display: none;
        }
        &:hover {
          >a {
            display: block;
            span {
              display: block;
              position: absolute;
              left: 47px;
              width: 153px;
              padding: 15px 5px 15px 19px;
              background-color: #222d32;
              color: #fff;
              width: 177px;
              top: 0;
              border-radius: 0 5px 0 0;
            }
            i:last-child {
              display: inline-block;
              position: absolute;
              right: -165px;
              top: 50%;
              transform: translateY(-50%);
              color: #fff;
            }
          }
          >.tree-menu {
            display: block;
            position: absolute;
            left: 47px;
            width: 180px;
            background-color: #222d32;
            color: #fff;
            top: 46px;
            width: 180px;
            border-radius: 0 0 5px 5px;
          }
        }
      }
    }
  }
}
</style>

总结

实际上这货就是把adminlte的风格用vue实现了... 还有变形金刚版本,,整个响应涉及几个到组件间的通讯; 就不把全部代码丢出来了,一大坨...

效果是这样的

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年07月14日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 效果图
  • 代码
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档