felix-cao / Blog

A little progress a day makes you a big success!
31 stars 4 forks source link

Vue 实现同一系统中同时存在多种布局模式 #158

Open felix-cao opened 5 years ago

felix-cao commented 5 years ago

一、场景描述

image

如上图,第一种布局是上下布局,第二种是上、下左、下右布局,我们要使用 vue 在同一个系统中实现这两种风格布局的方法,如果是多种风格的布局,也可以使用这种方法。

本文使用 vue + Element UI

二、Header 组件

/src/admin/component/common/Header.vue

<template>
    <el-header class="header" height="70">
     <!-- other code -->
      <el-row>
        <el-col :span="15">
          <el-menu :default-active="activeMenu" class="header-menu" background-color="#372961" mode="horizontal" :router="routerMenu">
            <el-menu-item index="/admin">首页</el-menu-item>
            <el-menu-item index="/admin/main/monitor">舆情监测</el-menu-item>
            <el-menu-item index="/admin/main/analysis">舆情分析</el-menu-item>
          </el-menu>
        </el-col>
       </el-row>
       <!-- other code -->
    </el-header>
</template>

<script>
export default {
  name: 'Header',
  data () {
    const path = this.$route.path ? this.$route.path : '/admin'
    return {
      routerMenu: true,
      activeMenu: path,
    }
  }
}
</script>
<style  scoped>
/* -- Other Code --*/
</style>

上面的代码使用了 Element UImenuel-menu 中的 :router 表示是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转, default-active 表示默认激活的导航

三、路由及组件

3.1、路由配置

src/router/index.js

// --- other code
 { path: '/admin',
   component: Admin,
   children: [
     { path: '', component: Dashboard },
     { path: 'main',
       component: Main, // Two Column layout
       children: [
         { path: 'analysis', name: '舆情分析', component: Analysis },
         { path: 'monitor',
           name: '舆情监测',
           component: Monitor,
           props: (route) => ({ query: route.query.title })
         }
       ]
     }
   ]
  },
// --- other code

3.2、组件

/src/admin/component/Admin.vue

<template>
  <el-container direction="vertical">
    <Header></Header>
    <router-view></router-view>
</el-container>
</template>
<script>
import { Header } from './component/common'
export default {
  name: 'Admin',
  components: { Header }
}
</script>

/src/admin/component/main.vue

<template>
    <el-container>
        <left-nav></left-nav>
        <router-view></router-view>
    </el-container>
</template>

<script>
import { LeftNav } from './component'
export default {
  name: 'Main',
  components: { LeftNav }
}
</script>

现在,符合第一种上下布局的都放在路由 /adminchildren 中去配置,这样就共用了一个 Header 组件(/src/admin/component/Admin.vue),所有符合第二种上、下左、下右布局的都放在路由 /admin/main/children 中去配置,这样就共用了一个Header 组件和一个 LeftNav 组件

四、场景升级:多样化的左边次导航

到第三段结束时,我们已经可以满足在第一段中的场景需求了,现在我们要将场景升级一下了,对于第二种 上、下左、下右 的布局,在 Header 中点击不同的导航按钮,下左会显示不同的次导航内容,那么怎么来满足这样的场景需求呢?

/src/admin/component/LeftNav.vue

<template>
  <el-aside width="250px" class="leftNav">
    <h2 class="title">{{$route.name}}</h2>
    <keep-alive>
      <component :is="componentName"></component>
    </keep-alive>
  </el-aside>
</template>

<script>
import * as _ from 'lodash'
import ReportLeftNav from './ReportLeftNav'
import MonitorLeftNav from './MonitorLeftNav'
import AnalysisLeftNav from './AnalysisLeftNav'

export default {
  name: 'LeftNav',
  props: ['title'],
  components: { MonitorLeftNav, AnalysisLeftNav, ReportLeftNav },
  data () {
    return {
      componentName: this.getComponentName()
    }
  },

  methods: {
    getComponentName (path = '') {
      path = path || this.$route.path
      const reg = /\/admin\/main\/([\d\w]+)[/\d\w]*/
      const arr = reg.exec(path)
      const name = _.get(arr, '[1]', '')
      return `${_.capitalize(name)}LeftNav`
    }
  },

  watch: {
    '$route' (to, from) {
      this.componentName = this.getComponentName(to.path)
    }
  }
}
</script>

上面的代码解读:

至此我们完美实现这个场景的升级:多样化的左边次导航。