Vue中多个页面结构相同处理为共用一个入口页面组件,以及根据后台返回的页面的uniId处理不同页面的相关逻辑。

图一.png

图二.png
大致效果.gif

根据上面的图片可以看到,左侧的十三个页面大体上结构都是相同的,除了右侧的不同的按钮以及不同的按钮个数,这种情况下,就可以考虑使用动态路由传参以及slot具名插槽等技术去处理简化达到最优解。

1、使用到的技术方向
  • 动态路由传参
  • slot具名插槽
  • watch侦听器
  • 组件的封装
    ..等
2、开始对路由进行处理

体系建设是我这个项目的一个大的模块,下面13个页面结构类似,因此,直接写一个主入口targetManagement组件,这个模块所有的页面都跳转到这个页面,通过不同的页面的id实现获取不同的接口数据,由于我这个项目还有个打开文件夹的功能,因此,需要使用/targetManagement/:id/:fidid以及fid拼接到后面作为参数传入路由。

      // 体系建设
      {
        path: '/targetManagement/:id',
        name: 'targetManagement',
        component: () => import('@/views/pages/systemConstruction/targetManagement.vue'),
        meta: {
          title: [{
            name: '体系建设',
            url: ''
          }]
        }
      },
      // 文件夹查看
      {
        path: '/targetManagement/:id/:fid',
        name: 'targetManagement',
        component: () => import('@/views/pages/systemConstruction/components/foldersView.vue'),
        meta: {
          title: [{
            name: '体系建设',
            url: ''
          }, {
            name: '目标管理',
            url: ''
          }]
        }
      },
3、对页面进行唯一性处理

router-view是指的页面内容占位区域,也就是显示的部分,这里将路由路径进行唯一的key值绑定

<template>
  <div class="box">
    <navTop />
    <div class="content">
      <transition name="myfade" mode="out-in">
        <router-view :key="key" />
      </transition>
    </div>
  </div>
</template>
<script>
import navTop from "./navTop";

export default {
  name: "viewBox",
  components: {
    navTop,
  },
  computed: {
    key() {
      return this.$route.fullPath;
    },
  },
};
</script>
4、左侧导航栏菜单根据后台接口返回动态渲染

这部分获取接口返回过来的左侧菜单栏进行渲染操作

        <!-- 左侧菜单 -->
        <div class="menu-box">
          <div class="menu-wrap" :style="styleProps">
            <div class="logo-img">
              <!-- <img src="../assets/logo.png" alt /> -->
              <span>******平台</span>
            </div>
            <Menu
              :style="styleProps"
              :active-name="$route.menuUrl"
              :open-names="['home']"
              :theme="menuTheme"
              width="auto"
              :class="menuitemClasses"
              accordion
            >
              <template v-for="(item, componentIndex) in menu">
                <!-- 展开并且有子菜单 -->
                <Submenu
                  v-if="!isCollapsed && item.children && item.children.length"
                  v-bind:key="componentIndex"
                  :name="componentIndex"
                >
                  <template slot="title">
                    <Icon :type="item.menuIcon" />
                    <span>{{ item.menuName }}</span>
                  </template>
                  <MenuItem
                    v-for="children in item.children"
                    :key="children.menuUrl"
                    :name="children.menuUrl"
                    @click="handleRouter(children)"
                    :to="children.menuUrl"
                  >
                    {{ children.menuName }}
                  </MenuItem>
                </Submenu>

                <!-- 展开但没有子菜单 -->
                <MenuItem
                  v-else-if="!isCollapsed"
                  :name="item.menuUrl"
                  :to="item.menuUrl"
                  v-bind:key="componentIndex"
                >
                  <Icon :type="item.menuIcon" />
                  <span>{{ item.menuName }}</span>
                </MenuItem>

                <!-- 不展开有子菜单 -->
                <Dropdown
                  v-else-if="
                    isCollapsed && item.children && item.children.length
                  "
                  v-bind:key="componentIndex"
                  placement="right-start"
                  class="menu-dropdown"
                >
                  <MenuItem :name="item.menuUrl" :to="item.menuUrl">
                    <Icon :type="item.menuIcon" />
                    <span>{{ item.menuName }}</span>
                  </MenuItem>
                  <DropdownMenu slot="list">
                    <DropdownItem
                      v-for="(children, index) in item.children"
                      :key="index"
                      style="padding: 0 0; background-color: #515a6e"
                    >
                      <MenuItem :name="children.menuUrl" :to="children.menuUrl">
                        {{ children.menuName }}
                      </MenuItem>
                    </DropdownItem>
                  </DropdownMenu>
                </Dropdown>
                <!-- 不展开无子菜单 -->
                <Tooltip
                  v-else-if="isCollapsed"
                  :content="item.name"
                  placement="right"
                  v-bind:key="componentIndex"
                >
                  <MenuItem :name="item.menuUrl" :to="item.menuUrl">
                    <Icon :type="item.menuIcon" />
                    <span>{{ item.menuName }}</span>
                  </MenuItem>
                </Tooltip>
              </template>
            </Menu>
          </div>
        </div>
图三.png
5、模块处理过程
创建一个主入口页面.png
5.1、公共页面组件的搭建

创建一个BasicSystem组件为一个子组件,也就是去负责一些公共的部分,而右侧的不同内容的按钮需要根据item.btnId == key.split('/')[2]判断对应的内容去显示出来,uniId也就是监听到的拼接在路径末尾不同的id值。

    <transition-group name="fade" mode="out-in">
      <BasicSystem
        :key="uniId"
        :ps="ps"
        :pn="pn"
        :total="total"
        @handleSearch="handleSearch"
        @changePage="changePage"
        @handleSuccess="handleSuccess"
        @handleUpload="handleUpload"
        :dataList="dataList"
      >
        <template v-for="item in btns">
          <Button
            v-if="item.btnId == key.split('/')[2]"
            :key="item.id"
            type="primary"
            slot="fn-btn"
            @click="handleAll(item.handleName, item.row)"
            >{{ item.text }}
          </Button>
        </template>
      </BasicSystem>
    </transition-group>
5.2、主入口监听路由以及存储

监听路由获取uniId存储在会话中有一个好处,就是在这个页面下去频繁使用到uniId处理逻辑的时候可以去直接获取而不用频繁的使用params或者query去传参。
存储btnsLength是因为按钮的个数是不确定的,因此页面的 header布局也是动态的,无法固定死,需要去计算。

  computed: {
    key() {
      this.handleSession();
      this.handleTypeList();
      return this.$route.fullPath;
    },
  },
  watch: {
    $route: {
      handler(to, from) {
        this.btnsLength = 0;
        this.uniId = to.params.id;
        btns.forEach((item) => {
          if (item.btnId == this.uniId) {
            this.btnsLength++;
          }
        });
        sessionStorage.setItem("uniId", this.uniId);
        sessionStorage.setItem("btnsLength", this.btnsLength);
      },
      immediate: true,
    },
  },
5.3、子组件的头部动态布局处理

子组件中因为头部的按钮可以是一个也可以是三个,因此需要btnsLength=sessionStorage.getItem("btnsLength")?sessionStorage.getItem("btnsLength"): 0去处理头部的占位问题。

      <div class="basic-header">
        <Row class="row">
          <Col span="12">
            <Input
              v-model="keyWord"
              clearable
              placeholder="请输入文件名称查询"
              style="width: 300px"
            ></Input>
            <Button class="basic-btn" type="primary" @click="handleSearch"
              >查询</Button
            >

            <Button
              class="basic-btn secondary"
              type="success"
              @click="handleDown"
              >批量下载</Button
            >
          </Col>
          <Col :span="12 - 2 * btnsLength" class="basic-btn-upload right-btn">
            <Button type="success" @click="handleUpload">文档上传</Button>
          </Col>
          <Col :span="2 * btnsLength" class="basic-btn-operator">
            <slot name="fn-btn"></slot>
          </Col>
        </Row>
      </div>
5.4、右侧按钮的统一化处理

在处理右侧按钮时,也就是在targetManagement组件的过程中,使用:

        <template v-for="item in btns">
          <Button
            v-if="item.btnId == key.split('/')[2]"
            :key="item.id"
            type="primary"
            slot="fn-btn"
            @click="handleAll(item.handleName, item.row)"
            >{{ item.text }}
          </Button>
        </template>
图四.png

将所有的按钮放在一个js文件中,然后用上述的方法去遍历,获取的到方法的第一个参数就是按钮的事件名,第二个参数就是按钮的一些id等数据用于去判断。

5.5、右侧按钮的统一化处理(二)

将事件写出去,但是当点击主入口上的不同的按钮时,依旧是可以执行方法的。

 // 右侧的操作按钮
    handleAll(handleName, row) {
      switch (handleName) {
        // 目标管理签署列表
        case "handleSignListManage":
          this.handleSignListManage();
          break;
        // 组织结构文件签署
        case "handleSignListOrigin":
          this.handleSignListOrigin();
          break;
        // 安全生产费用
        case "handleSafetyCost":
          this.handleSafetyCost();
          break;
        // 年产总值
        case "handleTotalProduction":
          this.handleTotalProduction();
          break;
        // 培训列表
        case "handleTrainList":
          this.handleTrainList();
          break;
        // 演练列表
        case "handleDrillList":
          this.handleDrillList();
          break;
        // 设备清单
        case "handleEquipment":
          this.handleEquipment();
          break;
        default:
          break;
      }
    },

这样,大概总共几十甚至近百的页面,简单的优化处理,至少省去了几十个页面的重复绘制以及写一些重复的逻辑过程,在后期项目维护中,也是大大节省了成本,只需修改一个主入口即可。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容