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

前言

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


效果图

实现思路

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

代码

  • 菜单menuList.js
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
<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实现了... 还有变形金刚版本,,整个响应涉及几个到组件间的通讯; 就不把全部代码丢出来了,一大坨...

效果是这样的

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏游戏开发那些事

【Unity3d游戏开发】UGUI插件入门之游戏菜单

  ugui是unity4.6开始加入的一个新的ui系统,非常强大,下面我们将通过一系列博客的方式一起来学习一下ugui的使用。本篇博客会介绍如何使用ugui制...

39520
来自专栏lgp20151222

Java引用外部字体(路径引用)的一些坑

然后,一路踩了jvm关于字体的坑,重点是,java的报错很随意,甚至不报错,建议直接看最后面.

27510
来自专栏非著名程序员

最能解决你的痛点问题,也是你最需要的,尽在Material Design 系列这篇

这篇文章其实我一直在想,是写还是不写,因为关于讲 CoordinatorLayout,AppBarLayout,CollapsingToolbarLayout,...

20580
来自专栏HTML5学堂

HTML5视音频代码实例 & WEBM格式转换器

HTML5视音频代码实例&WEBM格式转换器 HTML5学堂:WebM由Google提出,是一个开放、免费的媒体文件格式。WebM 影片格式其实是以 Matro...

87180
来自专栏JackieZheng

AngularJS in Action读书笔记5(实战篇)——在directive中引入D3饼状图显示

前言:   "宁肯像种子一样等待    也不愿像疲惫的陀螺    旋转得那样勉强"   这是前几天在查资料无意间看到的一位园友的签名,看完后又读了两遍,觉得很有...

29860
来自专栏DannyHoo的专栏

iOS开发中在swift项目中使用Kingfisher下载图片

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010105969/article/details...

26040
来自专栏wOw的Android小站

[Python]写给Dr.Wu的简单爬虫例子

这次要爬的数据来自网站:http://www.qlaee.com/zhuanlist.jsp?flag=3&p=1&columnumber=302&codemy...

12320
来自专栏liuchengxu

如何使用 Vim 的 help

实际上,无论是 Vim 的基础知识还是进阶知识,大都可以从 help 中找到指引。但是我想很多人并没有意识到这一点,或者并没有重视这一点。RTFM (read ...

8420
来自专栏ionic3+

【组件篇】ionic3分组索引及锚点滚动列表

好久没有写文章了,趁着吃完饭消化的时候打算写一篇。先前一篇文章提到并关注的capacitor终于出到1.0.0-alpha.5了,本想写它,但是内容比较多,所以...

20320
来自专栏我杨某人的青春满是悔恨

开源项目——『看知乎』iOS 版

前段时间无意中发现了看知乎,一个知乎答案和用户的精选站。网站开发者是知乎用户苏莉安,他写了个爬虫从知乎抓取数据,而且还提供了 API 文档。我大致看了下文档,感...

35350

扫码关注云+社区

领取腾讯云代金券