基于micro

编程入门 行业动态 更新时间:2024-10-19 17:31:42

基于<a href=https://www.elefans.com/category/jswz/34/1745460.html style=micro"/>

基于micro

简述

本文是在对之前搭建和学习micro-app的基础上的进一步研究学习。
因为我们目前项目使用的框架是vue-element-admin,所以还需要研究一下micro-app在vue-element-admin的使用方法。
关于micro-app在vue-element-admin的实现,百度什么也没找到,只能按照之前搭建的micro-app的基础模仿着搭建着自己搞。
最终实现效果如下图所示:

接下来开始搭建过程

1、创建项目目录

关于目录的创建,新增文件夹micro-app-element,文件夹中有三个vue-element-admin项目:vue-element-base(基座)、vue-element-first(子应用1)、vue-element-second(子应用2)
代码下载
具体如下图所示:

其中vue-element-base(基座)、vue-element-first(子应用1)、vue-element-second(子应用2)是创建的vue-element-admin项目,如果不会创建,可参考
我这边是之前创建好的现成的包,拿过来直接解压了三个修改了一下名称,一个基座两个个子应用,项目内容大致如下

2、基座配置

我这边按之前搭建micro-app的过程一步步来,只是把之前的创建项目的过程省略掉了,现在直接用现成的vue-element-admin,搭建参考
注:接下来的配置都是在vue-element-base中进行配置的

2-1、配置vue.config.js

之前搭建的时候配置了localhost和port端口,vue-element-admin看情况是封装好的,不用修改太多

2-2、安装micro-app

安装micro-app插件,安装在base目录下

npm install @micro-zoe/micro-app --save

安装完成后,可以在基座package.json中看到安装好的@micro-zoe/micro-app,如下图所示:

2-3、配置micro

创建micro配置文件夹,配置config和index

config.js

/**
* 子应用前缀
*/
export const CHILD_PREFIX = 'child'/**
* 子应用地址
*/
export const MICRO_APPS = [{ name: 'first-child', url: `http://localhost:9528` },{ name: 'second-child', url: `http://localhost:9529` }
]/**
* 全局资源
*/
export const GLOBAL_ASSETS = {js: [],css: []
}

index.js

import microApp from '@micro-zoe/micro-app'
import * as config from './config'/** 启用 micro */
microApp.start({preFetchApps: config.MICRO_APPS,globalAssets: config.GLOBAL_ASSETS
})

2-4、修改main.js

修改main.js。引入micro

import './micro'

2-5、修改AppMain.vue

AppMain.vue修改(这个我在项目里找了一下,找到系统主体部分是写在AppMain.vue中的。按照之前搭建时的思路进行了一些修改)
差不多对AppMain.vue进行了如下图所示修改:

完整代码:

<template><section class="app-main"><transition name="fade-transform" mode="out-in"><keep-alive :include="cachedViews"><!--element-ui视图部分,这边可以判断是不是子应用,如果子应用显示micro-app,否则直接显示router-view--><micro-appv-if="isChild"v-bind="micro"destory/><router-view v-else :key="key" /></keep-alive></transition></section>
</template><script>
import { MICRO_APPS, CHILD_PREFIX } from '../../micro/config'export default {name: 'AppMain',data() {return {isChild: false,    /** 是否为子模块 */micro: {url: '',     /** 子模块地址 */key: '',     /** vue 标签的 key 值,用于不同子模块间的切换时,组件重新渲染 */name: '',    /** 子模块名称,唯一 */data: {},    /** 子模块数据 */baseroute: ''   /** 子模块数据 */},prefix: CHILD_PREFIX /** 子模块链接前缀 */}},computed: {cachedViews() {return this.$store.state.tagsView.cachedViews},key() {return this.$route.path}},watch: {$route(val) { /** 监听路由变化修改视图显示 */this.changeChild(val)}},created() {this.changeChild(this.$route)},methods: {/*** 获取子模块 url 和 name* */getAppUrl(name) {return MICRO_APPS.find(app => app.name === name) || {}},/*** 修改子视图显示* */changeChild(route) {const path = route.path.toLowerCase()const paths = path.split('/')// 判断是否为子模块,子模块有固定的前缀,在 micro/config 设置this.isChild = paths.length > 2 && paths[1] === CHILD_PREFIXif (this.isChild) {const app = this.getAppUrl(paths[2])this.micro = {...app,data: { name: route.name },key: `${app.name}`,baseroute: `/${CHILD_PREFIX}/${paths[2]}`}}}}
}
</script><style lang="scss" scoped>
.app-main {/* 50= navbar  50  */min-height: calc(100vh - 50px);width: 100%;position: relative;overflow: hidden;
}.fixed-header+.app-main {padding-top: 50px;
}.hasTagsView {.app-main {/* 84 = navbar + tags-view = 50 + 34 */min-height: calc(100vh - 84px);}.fixed-header+.app-main {padding-top: 84px;}
}
</style><style lang="scss">
// fix css style bug in open el-dialog
.el-popup-parent--hidden {.fixed-header {padding-right: 15px;}
}
</style>

2-6、基座中配置子应用1路由

在基座中配置子应用1路由(vue-element-admin中有好多页面,随便找了两个配置子应用路由


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

vue-element-base\src\router\modules\index.js

// 1.导入
import appFirstRouter from './modules/first-child'// 2.使用
appFirstRouter,

2-7、基座中配置子应用2路由

在基座中配置子应用2路由(同样vue-element-admin中有好多页面,随便找了两个配置子应用路由,只要不和子应用1重复即可)—这边的创建差不多就是把1复制过来改改


vue-element-base\src\router\modules\second-child.js

// 子应用2路由菜单
import Layout from '@/layout'
import { CHILD_PREFIX } from '@/micro/config'const appSecondRouter = {path: `/${CHILD_PREFIX}/second-child`,component: Layout,redirect: `/${CHILD_PREFIX}/second-child`,name: 'SecondChild',meta: {title: '子应用2模块',icon: 'table'},children: [{path: 'dynamic-table',name: 'DynamicTable',meta: { title: '子应用2菜单1' }},{path: 'drag-table',name: 'DragTable',meta: { title: '子应用2菜单2' }}]
}
export default appSecondRouter

vue-element-base\src\router\modules\index.js

// 1.导入
import appSecondRouter from './modules/second-child'// 2.使用
appSecondRouter,

到此对基座的改造就结束了。

3、子应用1配置

子应用1为vue-element-first。接下来的配置都是在vue-element-first下进行的配置

3-1、修改vue.config.js

修改vue.config.js文件,设置允许跨域

headers: { // 设置本地运行的跨域权限'Access-Control-Allow-Origin': '*'
},

3-2、配置micro

和基座一样,配置micro。新建在src下新建文件夹micro。并在micro下新建index.js文件

// 设置 webpack 的公共路径
if (window.__MICRO_APP_ENVIRONMENT__) {// eslint-disable-next-line__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__ || '/'
}

3-3、修改main.js


main.js

// 引入 publicPath 设置
import './micro'import Vue from 'vue'import Cookies from 'js-cookie'import 'normalize.css/normalize.css' // a modern alternative to CSS resetsimport Element from 'element-ui'
import './styles/element-variables.scss'import '@/styles/index.scss' // global cssimport App from './App'
import store from './store'
import router from './router'import i18n from './lang' // internationalization
import './icons' // icon
import './permission' // permission control
import './utils/error-log' // error logimport * as filters from './filters' // global filters/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
* you can execute: mockXHR()
*
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {const { mockXHR } = require('../mock')mockXHR()
}Vue.use(Element, {size: Cookies.get('size') || 'medium', // set element-ui default sizei18n: (key, value) => i18n.t(key, value)
})// register global utility filters
Object.keys(filters).forEach(key => {Vue.filter(key, filters[key])
})Vue.config.productionTip = false// new Vue({
//   el: '#app',
//   router,
//   store,
//   i18n,
//   render: h => h(App)
// })
let app/**
* 挂载函数
*/
function mount() {app = new Vue({el: '#app',router,store,i18n,render: function(h) { return h(App) }})
}/**
* 卸载函数
*/
function unmount() {app.$destroy()app.$el.innerHTML = ''app = null
}/** 微前端环境下,注册mount和unmount方法 */
if (window.__MICRO_APP_ENVIRONMENT__) { window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount } } else { mount() }

3-4、修改vue文件

3-5、修改路由(子应用1)

/** 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-viewname: 'Menu1',meta: { title: '子应用菜单11' }},{path: 'menu2',name: 'Menu2',component: () => import('@/views/nested/menu2/index'),meta: { title: '子应用菜单22' }}]
}export default nestedRouter

修改完成后运行子应用1和基座,在基座中看到的子应用1效果如下图所示:

npm run dev

3-6、问题解决

原以为这种是路由配置有问题,但是改来改去要么404要么嵌套。不管改基座还是子应用。都没有任何效果。后面看到了一个react的文章。虽然语法等不一样,但是看到了和我上图一样的嵌套bug。
上图中子应用全部嵌套在了基座里,包含了基座已有的菜单栏及头部,所以要找到子应用的layout进行判断,如果是基座环境,则只显示主体内容。否则(即子应用)则可以全部显示。具体修改如下所示:

修改完成后不在有嵌套,但是在基座中点击子应用菜单,只有上方头部菜单栏变化,中间主要部分内容没有变化。要在子应用layout中对数据做一个监听。

micro-app-element\vue-element-first\src\layout\index.vue完整代码:

<template><app-main v-if="inBase" /><div v-else :class="classObj" class="app-wrapper"><div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /><sidebar class="sidebar-container" /><div :class="{hasTagsView:needTagsView}" class="main-container"><div :class="{'fixed-header':fixedHeader}"><navbar /><tags-view v-if="needTagsView" /></div><app-main /><right-panel v-if="showSettings"><settings /></right-panel></div></div>
</template><script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'export default {name: 'Layout',components: {AppMain,Navbar,RightPanel,Settings,Sidebar,TagsView},mixins: [ResizeMixin],computed: {...mapState({sidebar: state => state.app.sidebar,device: state => state.app.device,showSettings: state => state.settings.showSettings,needTagsView: state => state.settings.tagsView,fixedHeader: state => state.settings.fixedHeader}),classObj() {return {hideSidebar: !this.sidebar.opened,openSidebar: this.sidebar.opened,withoutAnimation: this.sidebar.withoutAnimation,mobile: this.device === 'mobile'}},inBase() { // 判断是不是基座console.log('inbase microApp', window.microApp)console.log('inbase', window.__MICRO_APP_BASE_APPLICATION__)return !!window.microApp}},created() {/** 绑定数据【data属性】监听事件 */window.microApp && window.microApp.addDataListener(this.dataListener)},methods: {handleClickOutside() {this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })},/** 监听路径,在基座中点击子应用菜单时,菜单正常切换,但主体部分内容不变 */dataListener(data) {if (data.name !== this.$route.name) {this.$router.push({ name: data.name })}}}
}
</script><style lang="scss" scoped>@import "~@/styles/mixin.scss";@import "~@/styles/variables.scss";.app-wrapper {@include clearfix;position: relative;height: 100%;width: 100%;&.mobile.openSidebar {position: fixed;top: 0;}}.drawer-bg {background: #000;opacity: 0.3;width: 100%;top: 0;height: 100%;position: absolute;z-index: 999;}.fixed-header {position: fixed;top: 0;right: 0;z-index: 9;width: calc(100% - #{$sideBarWidth});transition: width 0.28s;}.hideSidebar .fixed-header {width: calc(100% - 54px)}.mobile .fixed-header {width: 100%;}
</style>

修改完成后,micro-app在vue-element-admin中的效果就算实现了。效果图如下:

4、子应用2配置

子应用2配置(基本和子应用1配置一致,只需微改即可)
子应用2为vue-element-second。接下来的配置都是在vue-element- second下进行的配置。

4-1、修改vue.config.js

修改vue.config.js文件,设置允许跨域

headers: { // 设置本地运行的跨域权限'Access-Control-Allow-Origin': '*'
},

4-2、配置micro

和基座一样,配置micro。新建在src下新建文件夹micro。并在micro下新建index.js文件

// 设置 webpack 的公共路径
if (window.__MICRO_APP_ENVIRONMENT__) {// eslint-disable-next-line__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__ || '/'
}

4-3、修改main.js


main.js

// 引入 publicPath 设置
import './micro'
import Vue from 'vue'import Cookies from 'js-cookie'import 'normalize.css/normalize.css' // a modern alternative to CSS resetsimport Element from 'element-ui'
import './styles/element-variables.scss'import '@/styles/index.scss' // global cssimport App from './App'
import store from './store'
import router from './router'import i18n from './lang' // internationalization
import './icons' // icon
import './permission' // permission control
import './utils/error-log' // error logimport * as filters from './filters' // global filters/**
* If you don't want to use mock-server
* you want to use MockJs for mock api
* you can execute: mockXHR()
*
* Currently MockJs will be used in the production environment,
* please remove it before going online ! ! !
*/
if (process.env.NODE_ENV === 'production') {const { mockXHR } = require('../mock')mockXHR()
}Vue.use(Element, {size: Cookies.get('size') || 'medium', // set element-ui default sizei18n: (key, value) => i18n.t(key, value)
})// register global utility filters
Object.keys(filters).forEach(key => {Vue.filter(key, filters[key])
})Vue.config.productionTip = false// new Vue({
//   el: '#app',
//   router,
//   store,
//   i18n,
//   render: h => h(App)
// })
let app/**
* 挂载函数
*/
function mount() {app = new Vue({el: '#app',router,store,i18n,render: function(h) { return h(App) }})
}/**
* 卸载函数
*/
function unmount() {app.$destroy()app.$el.innerHTML = ''app = null
}/** 微前端环境下,注册mount和unmount方法 */
if (window.__MICRO_APP_ENVIRONMENT__) {window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount }
} else {mount()
}

4-4、修改vue文件

4-5、修改路由(子应用2)

/** When your routing table is too long, you can split it into small modules **/import Layout from '@/layout'const tableRouter = {path: window.__MICRO_APP_BASE_ROUTE__ || '/table',component: Layout,// redirect: '/table/complex-table',name: 'Table',meta: {title: '子应用2',icon: 'table'},children: [{path: 'dynamic-table',component: () => import('@/views/table/dynamic-table/index'),name: 'DynamicTable',meta: { title: '子应用2菜单111' }},{path: 'drag-table',component: () => import('@/views/table/drag-table'),name: 'DragTable',meta: { title: '子应用2菜单222' }},{path: 'inline-edit-table',component: () => import('@/views/table/inline-edit-table'),name: 'InlineEditTable',meta: { title: 'inlineEditTable' }},{path: 'complex-table',component: () => import('@/views/table/complex-table'),name: 'ComplexTable',meta: { title: 'complexTable' }}]
}
export default tableRouter

接下来浏览器效果和搭建子应用1时一样,是嵌套的,如下:

4-6、问题解决

需要对子应用的layout进行判断,如果是基座环境,则只显示主体内容。否则(即子应用)则可以全部显示。至于为什么修改,看子应用1即可,不多说了具体修改如下所示:

micro-app-element\vue-element-second\src\layout\index.vue完整代码:

<template><app-main v-if="inBase" /><div v-else :class="classObj" class="app-wrapper"><div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /><sidebar class="sidebar-container" /><div :class="{hasTagsView:needTagsView}" class="main-container"><div :class="{'fixed-header':fixedHeader}"><navbar /><tags-view v-if="needTagsView" /></div><app-main /><right-panel v-if="showSettings"><settings /></right-panel></div></div>
</template><script>
import RightPanel from '@/components/RightPanel'
import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
import ResizeMixin from './mixin/ResizeHandler'
import { mapState } from 'vuex'export default {name: 'Layout',components: {AppMain,Navbar,RightPanel,Settings,Sidebar,TagsView},mixins: [ResizeMixin],computed: {...mapState({sidebar: state => state.app.sidebar,device: state => state.app.device,showSettings: state => state.settings.showSettings,needTagsView: state => state.settings.tagsView,fixedHeader: state => state.settings.fixedHeader}),classObj() {return {hideSidebar: !this.sidebar.opened,openSidebar: this.sidebar.opened,withoutAnimation: this.sidebar.withoutAnimation,mobile: this.device === 'mobile'}},inBase() { // 判断是不是基座// console.log('inbase microApp', window.microApp)// console.log('inbase', window.__MICRO_APP_BASE_APPLICATION__)return !!window.microApp}},created() {/** 绑定数据【data属性】监听事件 */window.microApp && window.microApp.addDataListener(this.dataListener)},methods: {handleClickOutside() {this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })},/** 监听路径,在基座中点击子应用菜单时,菜单正常切换,但主体部分内容不变 */dataListener(data) {if (data.name !== this.$route.name) {this.$router.push({ name: data.name })}}}
}
</script><style lang="scss" scoped>@import "~@/styles/mixin.scss";@import "~@/styles/variables.scss";.app-wrapper {@include clearfix;position: relative;height: 100%;width: 100%;&.mobile.openSidebar {position: fixed;top: 0;}}.drawer-bg {background: #000;opacity: 0.3;width: 100%;top: 0;height: 100%;position: absolute;z-index: 999;}.fixed-header {position: fixed;top: 0;right: 0;z-index: 9;width: calc(100% - #{$sideBarWidth});transition: width 0.28s;}.hideSidebar .fixed-header {width: calc(100% - 54px)}.mobile .fixed-header {width: 100%;}
</style>

修改完成后,浏览器实现效果图如下:

到此对于micro-app在vue-element-admin中的使用就介绍完了。

5、打包

关于打包vue-element-admin貌似已经配置好了,直接打包即可

npm run build:prod

打包结果又是这样的,跟之前一样报错:

本地运行不起来,按照网上找的方法修改都没用。所以后面直接部署了,部署下来没有问题。所以打包这边注意以下两点就好了。

1、vue.config.js中的publicPath要修改。基座和子应用都要修改。如下图所示:

2、修改router/index.js。基座和子应用都要修改。修改路由方式。如下图所示:

打包结束后对应基座和子应用下都会生成对应的dist文件夹,如下图所示。单独打包单独部署就是基座和子应用都要打包。

6、部署

使用nginx部署,之前已经研究过了,部署这边就很快。如果不懂可参考部署相关内容。

6-1、dist放置

将打包好的dist文件分别放入对应好的文件夹中,当然不一定像我这样,只要后期目录地址写对即可

6-2、配置

主要是对nginx.conf的配置

主要配置代码:

server {listen       9527;server_name  localhost;#charset koi8-r;#access_log  logs/host.access.log  main;location / {root base/dist;add_header Access-Control-Allow-Origin *;if ( $request_uri ~* ^.+.(js|css|jpg|png|gif|tif|dpg|jpeg|eot|svg|ttf|woff|json|mp4|rmvb|rm|wmv|avi|3gp)$ ){add_header Cache-Control max-age=7776000;add_header Access-Control-Allow-Origin *;}try_files $uri $uri/ /index.html;}   }server {listen       9528;server_name  localhost;location / {root first-child/dist;add_header Access-Control-Allow-Origin *;if ( $request_uri ~* ^.+.(js|css|jpg|png|gif|tif|dpg|jpeg|eot|svg|ttf|woff|json|mp4|rmvb|rm|wmv|avi|3gp)$ ){add_header Cache-Control max-age=7776000;add_header Access-Control-Allow-Origin *;}try_files $uri $uri/ /index.html;}}server {listen       9529;server_name  localhost;location / {root second-child/dist;add_header Access-Control-Allow-Origin *;if ( $request_uri ~* ^.+.(js|css|jpg|png|gif|tif|dpg|jpeg|eot|svg|ttf|woff|json|mp4|rmvb|rm|wmv|avi|3gp)$ ){add_header Cache-Control max-age=7776000;add_header Access-Control-Allow-Origin *;}try_files $uri $uri/ /index.html;}}

6-3、浏览器地址

部署完之后可以在浏览器中输入:

http://127.0.0.1:9527/      // 基座地址
http://127.0.0.1:9528/    // 子应用1地址
http://127.0.0.1:9529/    // 子应用2地址

6-4、部署效果

部署后浏览器显示效果:

总结

到此micro-app在vue-element-admin中的使用框架就算搭完了,关于micro-app在vue-element-admin中的其他使用,还需后续在研究。

更多推荐

基于micro

本文发布于:2024-02-06 16:11:16,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1750619.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:micro

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!