micro-app在vue-element-admin中一些使用研究

2023-11-07

1、简述

本文承接上一篇micro-app在vue-element-admi中的搭建,对micro-app在vue-element-admin中的一些平时开发中常用的功能做了一些研究。本文代码

2、路由

关于路由,这边从两方面进行研究,一方面是对菜单的配置,另一方面是页面之间的跳转。下面分别介绍一下:

2-1、路由菜单配置

关于路由的配置,之前搭建vue-element-admin项目时,将子应用嵌入到基座时已经对路由的配置进行了搭建,子应用1为例具体如下:
在这里插入图片描述
如果是配置菜单的话,以上配置就可以了。配置代码如下:
micro-app-element\vue-element-base\src\router\modules\first-child.js

// 子应用1路由菜单
import Layout from '@/layout'
import { CHILD_PREFIX } from '@/micro/config'


const appFirstRouter = {
  path: `/${CHILD_PREFIX}/first-child`,
  component: Layout,
  redirect: `/${CHILD_PREFIX}/first-child`,
  name: 'FirstChild',
  meta: {
    title: '子应用模块',
    icon: 'nested'
  },
  children: [
    {
      path: 'menu1',
      name: 'Menu1',
      meta: { title: '子应用菜单1' }
    },
    {
      path: 'menu2',
      name: 'Menu2',
      meta: { title: '子应用菜单2' }
    }
  ]
}
export default appFirstRouter

micro-app-element\vue-element-first\src\router\modules\nested.js

/** When your routing table is too long, you can split it into small modules **/


import Layout from '@/layout'


console.log(' window.__MICRO_APP_BASE_ROUTE__', window.__MICRO_APP_BASE_ROUTE__)
const nestedRouter = {
  path: window.__MICRO_APP_BASE_ROUTE__ || '/nested',
  component: Layout,
  // redirect: '/nested/menu1/menu1-1',
  name: 'Nested',
  meta: {
    title: '子应用',
    icon: 'nested'
  },
  children: [
    {
      path: 'menu1',
      component: () => import('@/views/nested/menu1/index'), // Parent router-view
      name: 'Menu1',
      meta: { title: '子应用菜单11' }
    },
    {
      path: 'menu2',
      name: 'Menu2',
      component: () => import('@/views/nested/menu2/index'),
      meta: { title: '子应用菜单22' }
    }
  ]
}


export default nestedRouter

2-2、页面之间跳转

我们代码开发中,有很多场景都是一个菜单中有一个标签或按钮,点击可以直接跳转到另一个菜单。因为之前都是在同一个应用里,跳转肯定是没问题的。但是使用微前端后,可能会从基座菜单跳转到子应用菜单,也可能会从子应用菜单跳转到基座菜单,还有可能是子应用直接互相跳转,下面对这些跳转都做了尝试

2-2-1、子应用之间的互相跳转

举例:从子应用1的菜单1跳转到子应用2的菜单1,实现效果如下图所示:
子应用之间跳转
对于应用之间的跳转,有如下两个地方要修改:
(1)基座:在一开始搭建路由的时候,在基座中调用了子应用,如果要实现应用之间互相跳转,基座部分需要获取子路由传递的信息,具体实现如下:
在这里插入图片描述
micro-app-element\vue-element-base\src\layout\components\AppMain.vue

<micro-app
  v-if="isChild"
  v-bind="micro"
  destory
  @datachange="handleDataChange"
/>
/**
* 获取子路由传递的信息
* */
handleDataChange(event) {
  const data = event.detail.data
  if (data.route) this.$router.push({ name: data.route.name })
},

(2)子应用点击部分的设置
在这里插入图片描述
micro-app-element\vue-element-first\src\views\nested\menu1\index.vue

<div style="height: 50px;">
  <el-button type="primary" @click="jumpApp2('DynamicTable')">我想从子应用1菜单1跳转到子应用2菜单1</el-button>
</div>
methods: {
  /**
   * 点击跳转到页面
   * @param name
   */
  jumpApp2(name) {
    // 向基项目发送数据
    window.microApp && window.microApp.dispatch({ route: { name }})
  }
}
2-2-2、子应用跳转到基座

举例:从子应用1的菜单2跳转到基座图标页,实现效果如下图所示:
在这里插入图片描述
有了2-2-1的基础后,接下来的操作就方便很多,不需要再去修改基座了,之间在子应用里面实现跳转即可
在这里插入图片描述
micro-app-element\vue-element-first\src\views\nested\menu2\index.vue

<template>
  <div style="padding:30px;">
    我是子应用菜单2
    <div style="height: 50px;">
      <el-button type="primary" @click="jumpAppBase('Icons')">我想从子应用1菜单2跳转到基座图标页</el-button>
    </div>
    <el-alert :closable="false" title="menu 2" />
  </div>
</template>
<script>
export default {
  name: 'Menu2',
  methods: {
    /**
       * 点击跳转到页面
       * @param name
       */
    jumpAppBase(name) {
      // 向基项目发送数据
      window.microApp && window.microApp.dispatch({ route: { name }})
    }
  }
}
</script>
2-2-3、基座跳转到子应用

举例:从基座引导页跳转到子应用1菜单2,实现效果如下图所示:
在这里插入图片描述
基座跳转到子应用与上面2-2-1和2-2-2方法不同,需要注意
首先从官网中可以看出,跳转的时候路由方式不一样,url也有所不用,如果是哈希需要加“#”,如果不知道自己的路由方式,可以在router/index.js下去找mode,默认是哈希。我这边就是哈希

在这里插入图片描述
接下来按照官网介绍进行配置即可
在这里插入图片描述
在这里插入图片描述
micro-app-element\vue-element-base\src\views\guide\index.vue

<template>
  <div class="app-container">
    <aside>
      {{ $t('guide.description') }}
      <a href="https://github.com/kamranahmedse/driver.js" target="_blank">driver.js.</a>
    </aside>
    <el-button icon="el-icon-question" type="primary" @click.prevent.stop="guide">
      {{ $t('guide.button') }}
    </el-button>
    <div style="height: 50px;">
      <el-button type="primary" @click="jumpApp1()">我想从基座跳转到子应用1菜单2</el-button>
    </div>
  </div>
</template>


<script>
import Driver from 'driver.js' // import driver.js
import 'driver.js/dist/driver.min.css' // import driver.js css
import steps from './steps'
import { CHILD_PREFIX } from '../../micro/config'


export default {
  name: 'Guide',
  data() {
    return {
      driver: null
    }
  },
  mounted() {
    this.driver = new Driver()
  },
  methods: {
    guide() {
      this.driver.defineSteps(steps)
      this.driver.start()
    },
    /**
     * 基座跳转到子应用
     */
    jumpApp1() {
      window.history.pushState(null, '', `/#/${CHILD_PREFIX}/first-child/menu2`)
      // 主动触发一次popstate事件
      window.dispatchEvent(new PopStateEvent('popstate', { state: null }))
    }
  }
}
</script>

3、数据通信

关于这个数据通信,官网里讲了如下四点,感觉看着蛮不舒服的。其实按我们正常的思维,传值与取值是一起使用的
(1)子应用获取来自基座应用的数据
(2)子应用向基座应用发送数据
(3)基座应用向子应用发送数据
(4)基座应用获取来自子应用的数据
所以将以上(1)(3)和(2)(4)合并起来作为两点进行研究

3-1、基座发送数据,子应用获取数据

基座向子应用传值有两种方式:

3-1-1、data属性发送数据

在这里插入图片描述
基座发送数据:

<micro-app
  v-if="isChild"
  v-bind="micro"
  destory
  :data="dataForChild"
  @datachange="handleDataChange"
/>

dataForChild: { type: 'data属性发送数据给子应用' },

子应用获取数据:

created() {
  const data = window.microApp.getData() // 返回基座下发的data数据
  console.log('子应用获取父应用数据', data)
},
3-1-2、基座手动发送数据

在这里插入图片描述
基座

import microApp from '@micro-zoe/micro-app'
microApp.setData('first-child', { type: '基座手动发送新的数据' })

子应用

<template>
  <div style="padding:30px;">
    我是子应用菜单2
    <div style="height: 50px;">
      <el-button type="primary" @click="jumpAppBase('Icons')">我想从子应用1菜单2跳转到基座图标页</el-button>
    </div>
    <el-alert :closable="false" title="menu 2" />
  </div>
</template>
<script>
export default {
  name: 'Menu2',
  created() {
    // const data = window.microApp.getData() // 返回基座下发的data数据
    // console.log('子应用获取父应用数据', data)
    /** 绑定数据【data属性】监听事件 */
    window.microApp && window.microApp.addDataListener(this.dataListener, true)
  },
  destroyed() {
    /** 移除数据【data属性】监听事件 */
    window.microApp && window.microApp.removeDataListener(this.dataListener)
  },
  methods: {
    dataListener(data) {
      console.log('来自基座应用的数据', data)
    },
    /**
       * 点击跳转到页面
       * @param name
       */
    jumpAppBase(name) {
      // 向基项目发送数据
      window.microApp && window.microApp.dispatch({ route: { name }})
    }
  }
}
</script>

3-2、子应用发送数据,基座获取数据

关于子应用发送数据,基座获取数据的,我们在前面写跳转的时候就遇到了
在这里插入图片描述
子应用

// 向基项目发送数据
  window.microApp && window.microApp.dispatch({ route: { name }})

基座

<micro-app
  v-if="isChild"
  v-bind="micro"
  destory
  :data="dataForChild"
  @datachange="handleDataChange"
/>
/**
* 获取子路由传递的信息
* */
handleDataChange(event) {
  const data = event.detail.data
  if (data.route) this.$router.push({ name: data.route.name })
},

4、隔离

4-1、样式隔离

micro-app有默认的样式隔离,我简单试了一下
(1)修改子应用的颜色,子应用发生变化,但是不会影响到基座的样式
在这里插入图片描述
(2)修改基座颜色,基座会发生变化,不会影响到子应用
在这里插入图片描述

4-2、元素隔离

micro-app也有默认的元素隔离,元素不会逃离元素边界,子应用只能对自身的元素进行增、删、改、查的操作。

5、资源共享

官网描述:当多个子应用拥有相同的js或css资源时,可以指定这些资源在多个子应用之间共享,在子应用加载时直接从缓存中提取数据,从而提高渲染效率和性能。我大概可以理解为在基座中配置资源共享,这样子应用就可以直接用这个资源了。那我好奇要是子应用单独运行呢?这个资源还存在吗?或者是就直接没有这些共享的资源了?
因此自己亲自试了一下,将子应用1引入的样式注释掉,在基座中引入,基座是没看出来有什么问题,但是子应用1因为失去了样式就变的乱七八糟,关于这一点网上也没有找到太多的内容

在这里插入图片描述
在这里插入图片描述
但是在下面6、组件共享实现后,可以用同一方式实现样式共享,具体可看6中介绍。

6、组件共享

在目前微前端搭建的基础上,可以发现一些问题,公共组件。如果一个组件在基座和子应用中都需要用到,目前的状态是每个项目都写一遍,这样很麻烦。所以要想个办法实现组件共享
关于共享,我这边看到一个 monorepo(单一代码库) ,差不多意思是单个代码库里包含了许多项目的代码,但是后面没用该方法,所以也不知道好不好实现。
我这边用的是后台大佬分享的这篇文章中的方法三,大体参考,但是实际还需要修改一番,接下来看看我的实现步骤:
注:我这边把通用组件都放在基座base中,如果你想单独建一个项目来放通用组件也行,具体看个人想法。

6-1、项目目录结构

如下图所示目录结构。基座和子应用都放在一个大的文件夹micro-app-element下,假装base中的组件是通用组件,我现在在子应用1vue-element-first中进行一些操作,来实现组件的共享
在这里插入图片描述

6-2、修改vue.config.js

参考文章中是修改webpack.js配置。我们项目是vue-element-admin。webpack的相关配置我这边找到是在vue.config.js中配置的,所以路径相关在vue.config.js中配置即可。
在这里插入图片描述

// 注:根据自己的项目结果及项目名称修改

console.log('__dirname', __dirname, typeof __dirname, path.join(path.parse(__dirname).dir, 'vue-element-base/src'), '\r\n', path.parse(__dirname))
// 注:只需要添加baseComponent那一行即可,如果想调用子应用2,可以在或其它可以在重新配置一条

resolve: {
  alias: {
    '@': resolve('src'),
    'baseComponent': path.join(path.parse(__dirname).dir, 'vue-element-base/src')
  }
}

6-3、配置路由共享组件

这边在子应用1的路由中随便改一下首页的路径,让子应用1去访问基座中的首页页面
在这里插入图片描述

{
  path: '/',
  component: Layout,
  redirect: '/dashboard',
  children: [
    {
      path: 'dashboard',
      // component: () => import('@/views/dashboard/index'),
      component: () => import('baseComponent/views/dashboard/index'),
      name: 'Dashboard',
      meta: { title: 'dashboard', icon: 'dashboard', affix: true }
    }
  ]
},

然后因为三个应用内容都差不多,去基座改一下首页
在这里插入图片描述
接下来看效果:
在这里插入图片描述

6-4、import导入共享组件

在6-3中尝试了在路由中直接修改路径共享到基座菜单的方法,接下来在尝试一下在页面中通过import导入基座组件的方法吧。同样在基座中随便找了个组件Dropzone,照着抄抄就好了
在这里插入图片描述
micro-app-element\vue-element-first\src\views\nested\menu1\index.vue

<template>
  <div style="padding:30px;">
    <div style="height: 50px;">
      <el-button type="primary" @click="jumpApp2('DynamicTable')">我想从子应用1菜单1跳转到子应用2菜单1</el-button>
    </div>
    <el-alert :closable="false" title="menu 1">
      我是子应用菜单1
      <div class="editor-container">
        <dropzone id="myVueDropzone" url="https://httpbin.org/post" @dropzone-removedFile="dropzoneR" @dropzone-success="dropzoneS" />
      </div>
      <router-view />
    </el-alert>
  </div>
</template>
<script>
import Dropzone from 'baseComponent/components/Dropzone'
export default {
  name: 'Menu1',
  components: { Dropzone },
  methods: {
    dropzoneS(file) {
      console.log(file)
      this.$message({ message: 'Upload success', type: 'success' })
    },
    dropzoneR(file) {
      console.log(file)
      this.$message({ message: 'Delete success', type: 'success' })
    },
    /**
     * 点击跳转到页面
     * @param name
     */
    jumpApp2(name) {
      // 向基项目发送数据d
      window.microApp && window.microApp.dispatch({ route: { name }})
    }
  }
}
</script>

然后同样为了明显的看清楚我这边子应用1嵌入了base组件,我同样在代码里加了一点描述用来区分

<div style="color: #ff4949;font-size: 18px;">我是基座的公共组件</div>

在这里插入图片描述
实现效果如下图所示:
在这里插入图片描述

7、总结

到这里,对micro-app在vue-element-admin中的使用就研究的差不多了,因为初学,可能也存在一些问题,所以欢迎搭建评论区留言纠正。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

micro-app在vue-element-admin中一些使用研究 的相关文章

  • xgboost 安装问题(xgboost library (xgboost.dll) could not be loaded)win10+ anaconda3.8+pycharm最新社区版

    最近打算使用XGBOOST跑跑数据 奈何换了电脑 安装过程一把泪 1 搜索大部分安装办法 https blog csdn net qazplm155357 article details 107313915 utm medium distr
  • Spring Boot 性能优化几点

    点击下方 IT牧场 选择 设为星标 程序员大目 IT牧场公众号 BAT 技术专家分享开发 架构 运维相关干货 159篇原创内容 公众号 文章来源 http a nxw so 1biCvy 目录 异步执行 增加内嵌 Tomcat 的最大连接数
  • Bert的NSP任务的loss原理

    Bert的NSP任务是预测上句和下句的关系 对一个句子的表征可以用CLS的embedding bert的NSP任务 NSP 是一个预测两段文本是否在原文本中连续出现的二元分类损失 NSP 是一种二进制分类损失 用于预测原始文本中是否有两个片
  • 彻底理解Linux下动态替换.so的方法

    0x00 背景 hdfs增加了一个native方法 打成了libhadoop so这个动态库 需要分发到线上的各个Datanode上以便升级 在灰度分发到datanode时遇到了可复现的问题 即datanode进程肯定会core dump
  • scipy.sparse稀疏矩阵内积点乘--效率优化!

    在使用scipy和numpy做数据计算时 感觉运行速度较慢 但是程序已经到了使用多数计算使用内积运算地步了 真的不知道该如何优化 如果能够优化下内积运算该有多好啊 奔着这个目标 希望能够写一篇文章盘点各种内积优化方法 也算是贡献自己的微薄之
  • Java RMI 解析

    1 什么是RMI Java RMI 即 远程方法调用 Remote Method Invocation 一种用于实现远程过程调用 RPC Remote procedure call 的Java API 能直接传输序列化后的Java对象和分布
  • GD32替换STM32后 写片上闪存(flash)失败的解决方法

    目录 型号 问题 解决办法 下载gd的fmc操作库 修改fmc文件 使用 擦除一页 写一页 型号 使用的GD32C103CB等引脚替换STM32F103CB 问题 使用hal库的flash操作接口 片上flash可以正常擦除 但是无法写入
  • Flash Player 10 中的RTMFP协议(实现P2P技术)

    RTMFP是Adobe公司开发的一套新的通信协议 该协议可以让使用Adobe Flash Player的终端用户之间进行直接通信 用Adobe AIR框架开发的程序也可以用此协议来发布直播 实时信息 通过使用RTMFP 那些以来直播 实时通
  • 03多线程之间通讯

    线程之间的通信 一 为什么要线程通信 1 多个线程并发执行时 在默认情况下CPU是随机切换线程的 当我们需要多个线程来共同完成一件任务 并且我们希望他们有规律的执行 那么多线程之间需要一些协调通信 以此来帮我们达到多线程共同操作一份数据 2
  • linux内存文件系统

    写文件时 太耗内存的话 可以使用dma拷贝 或者使用内存文件系统的方式 但首先要搞清楚一点 正常的文件操作 多久会真正保存到磁盘中去呢 参考 浅谈Linux系统写磁盘机制 http blog sina com cn s blog 96757
  • mybatis通用mapper的Example查询

    mybatis的通用mapper 多用于单表查询 接口内部为我们提供了单表查询的基础查询语法 可以极大地帮助我们简化编程 接下来让我们动手试一试 我建的是springboot项目 先导依赖
  • 词云下载jieba成功后仍然报错

    下载jieba终端 pip install i https pypi tuna tsinghua edu cn simple jieba 成功下载后仍然报错 TransposedFont object has no attribute ge

随机推荐