效果图:
- 接着上次的前端微服务继续深入改造
前面的demo: 微前端demo
- 项目中安装ElemenUi框架
npm i element-ui -S
- 在app1中引入ElementUi
官网做法:引入ElementUi
main.js改造:
import Vue from 'vue'
import App from '@/layout'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';
import router from './router'
Vue.use(ElementUI);
new Vue({
router,
render: h => h(App)
}).$mount('#app')
同理改造app2中的main.js: 主要关注如何引入ElementUi
import Vue from 'vue'
import App from './App.vue'
import ElementUI from 'element-ui'
import router from './router'
import singleSpaVue from 'single-spa-vue'
Vue.config.productionTip = false
/**
* 子应用main.js
*/
Vue.use(ElementUI);
const appOptions = {
el: '#microApp',
router,
render: h => h(App)
}
// if(window.singleSpaNavigate) {
// __webpack_public_path__="http://localhost:8082/"
// }
// 支持应用独立运行、部署,不依赖于基座应用
if (!window.singleSpaNavigate) {
delete appOptions.el
new Vue(appOptions).$mount('#app')
}
// 基于基座应用,导出生命周期函数
const vueLifecycle = singleSpaVue({
Vue,
appOptions
})
export function bootstrap () {
console.log('app2 bootstrap')
return vueLifecycle.bootstrap(() => {})
}
export function mount () {
console.log('app2 mount')
return vueLifecycle.mount(() => {})
}
export function unmount () {
console.log('app2 unmount')
return vueLifecycle.unmount(() => {})
}
- 新建一个登陆页
在src目录下新建layout目录并在下面新建login目录
在layout目录下新建index.vue:
<template>
<div id="app" class="app">
<!-- <router-view /> -->
<keep-alive name="main" :include="'Operation'"><router-view /></keep-alive>
</div>
</template>
<style>
#app {
min-width: 1280px;
height: 100%;
background-color: #f0f2f5;
}
</style>
在login目录下新建index.vue:
<template>
<div id="app" >
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="用户名">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.pwd"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">登 录</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default{
data() {
return {
form: {
name: "",
pwd: "",
}
};
},
methods: {
onSubmit(){
this.$router.push({path: '/operation'})
}
}
}
</script>
- 搞个主页面
在src目录下新建operation目录并新建index.vue文件
/* eslint-disable */
<template>
<!-- <div>
<div id="nav">
<router-link to="/home">app1</router-link> |
<router-link to="/about">app1-about</router-link> |
<router-link to="app2#/home">app2</router-link> |
<router-link to="app2#/about">app2-about</router-link>
<button @click="test">测试</button>
</div>
<router-view/>
<div id="microApp">
</div>
</div> -->
<el-container style="height: 100%; border: 1px solid #eee">
<el-header style="text-align: right; font-size: 12px">
<el-dropdown>
<i class="el-icon-setting" style="margin-right: 15px"></i>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item>查看</el-dropdown-item>
<el-dropdown-item>新增</el-dropdown-item>
<el-dropdown-item>删除</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<span>王小虎</span>
</el-header>
<el-container>
<el-aside width="200px" style="background-color: #FFF;">
<el-menu :default-openeds="['1']">
<el-submenu index="1">
<template slot="title"><i class="el-icon-message"></i>导航一</template>
<el-menu-item-group>
<el-menu-item @click="test('/app2#/home')" index="1-1">打开App2-Home</el-menu-item>
<el-menu-item @click="test('/app2#/about')" index="1-2">打开App2-About</el-menu-item>
</el-menu-item-group>
<el-menu-item-group>
<el-menu-item @click="test('/operation/home')" index="1-3">打开App1-Home</el-menu-item>
</el-menu-item-group>
</el-submenu>
</el-menu>
</el-aside>
<el-main>
<router-view id="base" />
<div id="microApp"></div>
</el-main>
</el-container>
</el-container>
</template>
<script>
import { single } from "@/single-spa-config";
export default {
name: "Operation",
methods: {
test(uri){
this.$router.push({path: uri});
}
},
mounted(){
single();
}
}
</script>
<style lang="scss" scoped>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
#nav {
padding: 30px;
}
#nav a {
font-weight: bold;
color: #2c3e50;
}
#nav a.router-link-exact-active {
color: #42b983;
}
.el-header {
background-color: #B3C0D1;
color: #333;
line-height: 60px;
}
.el-aside {
color: #333;
}
#microApp {
background-color: #fff;
}
#base {
background-color: #fff;
}
/deep/ .el-main {
background-color: #fff;
padding: 20px !important;
margin: 15px !important;
}
</style>
- app1的路由改造:
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '@/views/home'
import About from '@/views/about';
// import Hello from '@/components/HelloWorld';
import APP from "@/operation";
// import MainPage from '@/components/main';
import login from '@/layout/login';
Vue.use(VueRouter)
const routes = [
{ path: '/home', component: Home },
{ path: '/about', component: About },
{ path: '*', component: APP },
{ path: '/operation', component: APP, children: [
// {
// path: '/',
// redirect: '/home'
// },
{ path: 'home', component: Home }
]},
{ path: '/operation/', component: login }
];
const router = new VueRouter({
mode: 'history',
// 通过环境变量来配置路由的 base url
// base: process.env.VUE_APP_BASE_URL,
routes
});
export default router
app2改造:
- views目录下的about.vue文件:
<!-- /views/About.vue
<template>
<div class="about">
<h1>app2 about page</h1>
</div>
</template>
-->
<template>
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="活动名称">
<el-input v-model="form.name"></el-input>
</el-form-item>
<el-form-item label="活动区域">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
<el-form-item label="活动时间">
<el-col :span="11">
<el-date-picker type="date" placeholder="选择日期" v-model="form.date1" style="width: 100%;"></el-date-picker>
</el-col>
<el-col class="line" :span="2">-</el-col>
<el-col :span="11">
<el-time-picker placeholder="选择时间" v-model="form.date2" style="width: 100%;"></el-time-picker>
</el-col>
</el-form-item>
<el-form-item label="即时配送">
<el-switch v-model="form.delivery"></el-switch>
</el-form-item>
<el-form-item label="活动性质">
<el-checkbox-group v-model="form.type">
<el-checkbox label="美食/餐厅线上活动" name="type"></el-checkbox>
<el-checkbox label="地推活动" name="type"></el-checkbox>
<el-checkbox label="线下主题活动" name="type"></el-checkbox>
<el-checkbox label="单纯品牌曝光" name="type"></el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="特殊资源">
<el-radio-group v-model="form.resource">
<el-radio label="线上品牌商赞助"></el-radio>
<el-radio label="线下场地免费"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="活动形式">
<el-input type="textarea" v-model="form.desc"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
}
}
},
methods: {
onSubmit() {
console.log('submit!');
}
}
}
</script>
- view目录下home.vue改造
<!-- /views/Home.vue
<template>
<div class="home">
<h1>app2 home page</h1>
</div>
</template>
-->
<template>
<el-table
:data="tableData"
style="width: 100%"
:row-class-name="tableRowClassName">
<el-table-column
prop="date"
label="日期"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="180">
</el-table-column>
<el-table-column
prop="address"
label="地址">
</el-table-column>
</el-table>
</template>
<style>
.el-table .warning-row {
background: oldlace;
}
.el-table .success-row {
background: #f0f9eb;
}
</style>
<script>
export default {
methods: {
// eslint-disable-next-line
tableRowClassName({row, rowIndex}) {
if (rowIndex === 1) {
return 'warning-row';
} else if (rowIndex === 3) {
return 'success-row';
}
return '';
}
},
data() {
return {
tableData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄',
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}]
}
}
}
</script>
- app2的路由不需要动以为我们只改动了组件,没有任何其他变动
整个页面展示说明:
主体页面构造在operation目录里面的组件。
整个主页面是显示在绑定在index.html的< router-view>中的
然后主页面operation/index.vue中又使用了一个< router-view>
要想保持这种显示布局就只有加的app1的组件路由都要写在/operation路由的子路由中,不然就会直接显示在绑定在index.html的< router-view>中了,也就是整个页面显示了,而不是我们定义的一块主显示区域。
遇到的问题:
app1中的子路由浏览器刷新直接空白页
app.js,chunk-vendors.js是啥啊,我们前面不是运行npm run build打包生成了dist目录吗,打开看看就大概明白了,
app.js: vue编译的项目代码
chunk-vendors.js :它是所有第三方模块的捆绑包
查看app1主应用根目录下的vue.config.js文件
改完需要重启app1主应用
再次刷新app1主应用下的子路由就没有出现资源加载不到的问题了
-----结束-----