likes
comments
collection
share

布局: 左侧栏折叠与面包屑

作者站长头像
站长
· 阅读数 81

前言

前一段时间, 写了强盛集团管理系统(基于 BPMN 引擎的工作流系统), 打算使用 qiankun 改造下项目架构, 迈向微前端。在上一章的基础上, 搭建基座应用的布局, 此章为折叠左侧栏和面包屑。

先来看下效果图吧!

布局: 左侧栏折叠与面包屑

布局: 左侧栏折叠与面包屑

简单实现下

考虑到左侧栏的折叠功能会影响后续(例如单独抽离主题设置面板)等工作, 以及在布局中, 折叠图标一般防置在<LayoutHeader>组件中, 而实际控制的则是左侧栏</LayoutAside>组件。

那我暂时选择将左侧栏折叠状态放在 Vuex 中,接下来则是实现部分

Vuex app 模块

  1. 设置全局标识, 新建store/modules/app.js
export default {
  namespaced: true,
  state: {
    sidebar: {
      opened: true,
    },
  },
  mutations: {
    set_sidebar(state, { key, value }) {
      state[key] = value;
    },
  },
  actions: {
    setSidebar({ commit }, { key, value }) {
      commit("set_sidebar", { key, value });
    },
  },
  getters: {
    sidebar: (state) => state.sidebar,
  },
};

设置左侧栏sidebar折叠状态opened, 同时sidebar下可能会有较多状态值需要记录, 设置值时为单独设置, 取值时则是返回全部

  1. 引入app 模块
import Vue from "vue";
import Vuex from "vuex";
import app from "./modules/app";

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    app,
  },
  state: {},
  getters: {},
  mutations: {},
  actions: {},
});

头部增加折叠图标

  1. 新增icon
<!-- 头部栏 -->
<template>
  <div class="layout-header">
    <div @click="toggle" class="fold-btn">
      <icon :name="sidebar.opened ? 's-fold' : 's-unfold'" scale="0.4"></icon>
    </div>
  </div>
</template>

<script>
  import { mapGetters, mapActions } from "vuex";
  export default {
    name: "",
    data() {
      return {};
    },
    computed: {
      ...mapGetters("app", ["sidebar"]),
    },
    methods: {
      ...mapActions("app", ["toggleCollapse"]),
      toggle() {
        this.toggleCollapse(!this.sidebar.opened);
      },
    },
    created() {},
    mounted() {},
  };
</script>
<style lang="less" scoped>
  .layout-header {
    display: flex;
    align-items: center;
    height: 40px;
    .fold-btn {
      width: 24px;
      height: 24px;
      color: black;
      margin: 0 5px;
    }
  }
</style>

通过 Vuex 的 mapGettersmapActions 可以比较方便的调用 app 模块的方法

s-folds-unfold为阿里矢量库的图标, 上一章是怎样制作图标

此时折叠栏的效果已经出来了。

样式变量

左侧栏<LayoutAside>头部防止 logo 和顶部栏<LayoutHeader>一般为同高度, 系统中还会有一些默认样式等。

那我选择将样式变量统一放置, 先来浅浅的实现一下

  1. 新建src/assets/css/common-variables.less
/* 布局 */
@layout-header-height: 40px;
  1. <LayoutAside> 组件中将头部高度设置下
<style lang="less" scoped>
@import url('@/assets/css/common-variables.less');
.layout-aside-logo {
  height: @layout-header-height;
  line-height: @layout-header-height;
  ...
}

.layout-aside-scrollbar {
  height: calc(100vh - @layout-header-height);
  ...
}
</style>

调整左侧栏顶部 logo 的高和行高, 及左侧栏的滚动高度

  1. <LayoutHeader> 组件中将高度调整
<style lang="less" scoped>
@import url('@/assets/css/common-variables.less');
.layout-header {
  height: @layout-header-height;
  box-shadow: 0 0 4px 0px #999;
  ...
}
</style>

增加了底部阴影

此时就可以通过变量统一设置顶栏的高度了。

布局: 左侧栏折叠与面包屑

面包屑

效果展示

布局: 左侧栏折叠与面包屑

布局: 左侧栏折叠与面包屑

  1. 新建公共组件Breadcrumb.vue
<!-- 面包屑 -->
<template>
  <el-breadcrumb separator="/" class="breadcrumb">
    <transition-group name="breadcrumb">
      <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
        <span
          v-if="item.redirect === 'noRedirect' || index == levelList.length - 1"
          class="no-redirect"
          >{{ item.meta.title }}</span
        >
        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
      </el-breadcrumb-item>
    </transition-group>
  </el-breadcrumb>
</template>

直接使用 elementel-breadcrumb即可, transition-group则为方便设置转场动画

<script>
export default {
  name: "Breadcrumb",
  data() {
    return {
      levelList: null,
    };
  },
  watch: {
    $route(route) {
      if (route.path.startsWith("/redirect/")) {
        return;
      }
      this.getBreadcrumb();
    },
  },
  methods: {
    getBreadcrumb() {
      let matched = this.$route.matched.filter(
        (item) => item.meta && item.meta.title
      );
      const first = matched[0];
      if (!this.isDashboard(first)) {
        matched = [{ path: "/", meta: { title: "基座" } }].concat(matched);
      }

      this.levelList = matched.filter(
        (item) => item.meta && item.meta.title && item.meta.breadcrumb !== false
      );
      console.log(this.levelList);
    },
    isDashboard(route) {
      const name = route && route.name;
      if (!name) {
        return false;
      }
      return name.trim().toLocaleLowerCase() === "Base".toLocaleLowerCase();
    },

    handleLink(record) {
      const { redirect, path } = record;
      if (redirect) {
        return this.$router.push(redirect);
      }
      this.$router.push(path);
    },
  },
  created() {
    console.log(this.$route);
    this.getBreadcrumb();
  },
  mounted() {},
};
</script>

watch 监听$route 切换, 更新面包屑

handleLink 为跳转处理

<style lang="less" scoped>
@import url("@/assets/css/common-variables.less");
.breadcrumb {
  line-height: @layout-header-height;
  margin-left: 10px;
  .no-redirect {
    color: #97a8be;
    cursor: text;
  }
}
</style>
  1. 引入面包屑
<!-- 头部栏 -->
<template>
  <breadcrumb/>
</template>

<script>
import Breadcrumb from "@/components/Breadcrumb.vue";
export default{
  components: { Breadcrumb },
}
<script>

此时面包屑已实现, 可以为面包屑转场添加动画

  1. 新建 assets/css/element.css, 在 main.js 引入
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.28s;
}

.fade-enter,
.fade-leave-active {
  opacity: 0;
}

/* fade-transform */
.fade-transform-leave-active,
.fade-transform-enter-active {
  transition: all 0.5s;
}

.fade-transform-enter {
  opacity: 0;
  transform: translateX(-30px);
}

.fade-transform-leave-to {
  opacity: 0;
  transform: translateX(30px);
}

/* breadcrumb transition */
.breadcrumb-enter-active,
.breadcrumb-leave-active {
  transition: all 0.5s;
}

.breadcrumb-enter,
.breadcrumb-leave-active {
  opacity: 0;
  transform: translateX(20px);
}

.breadcrumb-move {
  transition: all 0.5s;
}

.breadcrumb-leave-active {
  position: absolute;
}

总结

本篇简单实现了左侧栏的折叠和面包屑,接下来会实现个人中心,然后实现设置面板,之后会正式接入原有项目。

而本专栏就是打算将Vue2.x的老项目完成技术架构升级,从而达到技术栈更新、迁移、重构、重写等架构演进。

转载自:https://juejin.cn/post/7243609307857174587
评论
请登录