vue-element-admin layout组件解析【Sidebar】

> index.vue

<template>
<!-- 判断是否显示logo -->
  <div :class="{'has-logo':showLogo}">
    <!-- 判断是否隐藏侧边栏 -->
    <logo v-if="showLogo" :collapse="isCollapse" />
    <!-- 主侧边栏标签 -->
    <el-scrollbar wrap-class="scrollbar-wrapper">
      <!--
        default-active:活动菜单颜色
        collapse:侧边栏隐藏
        background-color: 背景颜色
        text-color:菜单中文本颜色
        unique-opened: 是否唯一打开
        active-text-colo: 活动文本颜色
        collapse-transition: 隐藏过渡
        mode="vertical":绑定变量
       -->
      <el-menu
        :default-active="activeMenu"
        :collapse="isCollapse"
        :background-color="variables.menuBg"
        :text-color="variables.menuText"
        :unique-opened="false"
        :active-text-color="variables.menuActiveText"
        :collapse-transition="false"
        mode="vertical"
      >
        <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
      </el-menu>
    </el-scrollbar>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import Logo from './Logo'
import SidebarItem from './SidebarItem'
import variables from '@/styles/variables.scss'

export default {
  components: { SidebarItem, Logo },
  computed: {
    // 获取vuex中getter中的属性的值
    ...mapGetters([
      'permission_routes',
      'sidebar'
    ]),
    // 活动菜单
    activeMenu() {
      // 获取当前路由对象
      const route = this.$route
      // 获取meta对象 和路径对象
      const { meta, path } = route
      // 如果设置路径,侧边栏将突出显示您设置的路径
      if (meta.activeMenu) {
        return meta.activeMenu
      }
      return path
    },
    // 显示logo
    showLogo() {
      return this.$store.state.settings.sidebarLogo
    },
    // scss颜色变量
    variables() {
      return variables
    },
    // 是否关闭侧边栏
    isCollapse() {
      return !this.sidebar.opened
    }
  }
}
</script>

> Item.vue

<script>
export default {
  name: 'MenuItem',
  functional: true,
  props: {
    // 图标
    icon: {
      type: String,
      default: ''
    },
    // 标题头
    title: {
      type: String,
      default: ''
    }
  },
  render(h, context) {
    // 获取参数对象
    const { icon, title } = context.props
    const vnodes = []

    if (icon) {
      // 判断图标是否element-ui中的图标
      if (icon.includes('el-icon')) {
        // 使用i标签添加图标
        vnodes.push(<i class={[icon, 'sub-el-icon']} />)
      } else {
        // 不是element-ui直接添加外部icon路径
        vnodes.push(<svg-icon icon-class={icon}/>)
      }
    }
    // 判断是否存在标题头
    if (title) {
      // 添加标题头
      vnodes.push(<span slot='title'>{(title)}</span>)
    }
    // 返回拼接后的数组标签
    return vnodes
  }
}
</script>

<style scoped>
.sub-el-icon {
  color: currentColor;
  width: 1em;
  height: 1em;
}
</style>

> SidebarItem.vue

<template>
  <div v-if="!item.hidden">
    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
          <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
        </el-menu-item>
      </app-link>
    </template>

    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
      <template slot="title">
        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
      </template>
      <sidebar-item
        v-for="child in item.children"
        :key="child.path"
        :is-nest="true"
        :item="child"
        :base-path="resolvePath(child.path)"
        class="nest-menu"
      />
    </el-submenu>
  </div>
</template>

<script>
import path from 'path' // 导入路径
import { isExternal } from '@/utils/validate' // 用于判断是外部的路径
import Item from './Item' // 迭代icon与title
import AppLink from './Link' // 应用关联 用于切换外部链接显示方法
import FixiOSBug from './FixiOSBug' // 用于修复IOS设备鼠标离开bug

export default {
  name: 'SidebarItem',
  components: { Item, AppLink },
  mixins: [FixiOSBug],
  props: {
    // route object 路由对象
    item: {
      type: Object,
      required: true
    },
    // 是否嵌套
    isNest: {
      type: Boolean,
      default: false
    },
    // 基本路径
    basePath: {
      type: String,
      default: ''
    }
  },
  data() {
    // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
    // TODO: 渲染函数重构
    this.onlyOneChild = null
    return {}
  },
  methods: {
    // 有一个子路由
    hasOneShowingChild(children = [], parent) {
      const showingChildren = children.filter(item => {
        if (item.hidden) {
          return false
        } else {
          // Temp set(will be used if only has one showing child)
          // 临时设置(如果只有一个子路显示子路由并使用)
          this.onlyOneChild = item
          return true
        }
      })

      // 当只有一个子路由器时,默认显示子路由器
      if (showingChildren.length === 1) {
        return true
      }

      // 如果没有要显示的子路由器,则显示父级
      if (showingChildren.length === 0) {
        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
        return true
      }

      return false
    },
    // 解析路径
    resolvePath(routePath) {
      // 判断是否是外部的路径
      if (isExternal(routePath)) {
        return routePath
      }
      if (isExternal(this.basePath)) {
        return this.basePath
      }
      // 返回当前也解析好的路径
      return path.resolve(this.basePath, routePath)
    }
  }
}
</script>

> Link.vue

<template>
  <!-- is指定这个component渲染成为指定的标签类型  -->
  <!-- 绑定链接地址 -->
  <component :is="type" v-bind="linkProps(to)">
    <slot />
  </component>
</template>

<script>
import { isExternal } from '@/utils/validate' // 判断是否是外部path

export default {
  props: {
    to: {
      type: String,
      required: true
    }
  },
  computed: {
    // 判断是否是外部路径https
    isExternal() {
      return isExternal(this.to)
    },
    type() {
      // 是外部HTTPS返回a标签
      if (this.isExternal) {
        return 'a'
      }
      // 是本地路径返回一个router-link,它最终会被渲染成一个a标签
      return 'router-link'
    }
  },
  methods: {
    // 链接方法
    linkProps(to) {
      // 判断是否是外部HTTPS路径
      if (this.isExternal) {
        return {
          // 链接地址
          href: to,
          target: '_blank',
          rel: 'noopener'
        }
      }
      // 不是外部路径直接返回
      return {
        to: to
      }
    }
  }
}
</script>

> FixiOSBug.js

export default {
  computed: {
    // 获取应用设备
    device() {
      return this.$store.state.app.device
    }
  },
  mounted() {
    // In order to fix the click on menu on the ios device will trigger the mouseleave bug
    // 为了修复ios设备上点击菜单会触发鼠标离开的bug
    // https://github.com/PanJiaChen/vue-element-admin/issues/1135
    this.fixBugIniOS()
  },
  methods: {
    // 修复IOSbug函数
    fixBugIniOS() {
      // 获取子菜单对象
      const $subMenu = this.$refs.subMenu
      if ($subMenu) {
        // 处理鼠标离开
        const handleMouseleave = $subMenu.handleMouseleave
        $subMenu.handleMouseleave = (e) => {
          if (this.device === 'mobile') {
            return
          }
          handleMouseleave(e)
        }
      }
    }
  }
}

上一篇:layui table 中 templet 判断


下一篇:python:deepdiff断言使用