[微前端实战]---041 框架初建(中央控制器, 子应用注册)

框架初建(中央控制器, 子应用注册)


回顾:

  1. 对子应用改造,然子应用在微前端环境启动起来,

  2. 入口做render,函数,暴露三个生命周期

  3. 配置vue.config.js/webpack.config.js +main.js/ index.js

实现微前端框架基础功能,包括:应用注册、路由拦截、主应用生命周期添加、微前端生命周期添加、加载和解析html、加载和解析js、渲染、执行脚本文件等内容。

修改各项目启动路径为9080,9081,9082,9083

15.refact:修改各项目启动路径为908x

一. 中央控制器

主应用: 中央控制器

主应用通过vue3构建

$	npm install @vue/cli@4.5.0 -g
$	vue create main

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPhWF4v9-1661697368731)(img/image-20220828193856000.png)]

<template>
  <Header/>
  <MainNav />
  <div class="sub-container">
    <Loading v-show="loading"/>
    <div v-show="!loading" id="sub-container">子应用内容</div>
  </div>
  <Footer/>
</template>

App.vue

<template>
  <Header />
  <MainNav />
  <div class="sub-container">
    <Loading v-show="loading" />
    <div v-show="!loading" id="sub-body">子应用内容</div>
  </div>
  <Footer />
</template>

<script>
import { ref } from 'vue'

import Header from "./components/Header";
import MainNav from "./components/MainNav";
import Loading from "./components/Loading";
import Footer from "./components/Footer";


export default {
  name: 'App',
  components: {
    Header,
    MainNav,
    Loading,
    Footer
  },
  setup() {
    // 声明双向数据ref
    const loading = ref(true)

    setTimeout(()=>{// 3s 后关闭 loding
      loading.value = false
    },3000)

    return {
      loading,
    }
  }
}
</script>

<style>
html,
body,
#micro_web_main_app {
  width: 100%;
height: 100%;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.sub-container {
  min-height: 100%;
  position: relative;
}

#micro-container {
  min-height: 100%;
  width: 100%;
}
</style>

通过一个v-show, loading变量, 控制显示隐藏

components/MainNav.vue

导航部分

<template>
  <div class="main-nav-container">
    <div class="main-nav-content">
      <!-- logo内容 -->
      <div class="main-nav-logo">
        <img src="" alt="">
      </div>

      <!-- 导航列表详情 -->
      <div class="main-nav-list">
        <div v-for="(item, index) in NAV_LIST" :class="{ 'main-nav-active': currentIndex === index }" :key="index"
          @click="setCurrentIndex(item, index)">
          {{ item.name }}
        </div>
      </div>

      <!-- 搜索 -->
      <div class="main-nav-search">
        <div class="main-nav-search-icon">
          <img src="../assets/blue-search.png" alt="">
        </div>
        <div class="main-nav-search-input">
          <input type="text" id="main-nav-search" v-if="searchStatus" @blur="setSearchStatus(false)">
          <div class="main-nav-search-input-fake" v-else @click="setSearchStatus(true)">
            快速搜索
          </div>
        </div>
        <div class="main-nav-search-button">
          搜索
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { ref, watch } from 'vue'
export default {
  name: 'MainNav',
  setup() {
    const NAV_LIST = [
    {
      name: '首页',
      status: true,
      value: 0,
      url: '/vue3/index',
      hash: '',
    },
    {
      name: '资讯',
      status: false,
      value: 1,
      url: '/react15/information',
    },
    {
      name: '视频',
      status: false,
      value: 2,
      url: '/react15/video',
      hash: '',
    },
    {
      name: '选车',
      status: false,
      value: 3,
      url: '/vue3/select',
      hash: '',
    },
    {
      name: '新能源',
      status: false,
      value: 4,
      url: '/vue2/energy',
      hash: '',
    },
    {
      name: '新车',
      status: false,
      value: 5,
      url: '/react17/new-car',
      hash: '',
    },
    {
      name: '排行',
      status: false,
      value: 6,
      url: '/react17/rank',
      hash: '',
    },
  ]

    const currentIndex = ref(0) // 创建响应式变量
    const setCurrentIndex = (data, index) => {
      currentIndex.value = index
    }

    const searchStatus = ref(true)
    const setSearchStatus = (type) => {
      searchStatus.value = type
    }
    return {
      NAV_LIST,
      currentIndex,
      setCurrentIndex,
      searchStatus,
      setSearchStatus,

    }
  }
}
</script>
<style lang="scss" scoped>
...
</style>

public/index.html

    <div id="micro_web_main_app"></div>

main.js

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#micro_web_main_app')

注入到这个micro_web_main_app节点

16.中央控制器-主应用开发

二. 子应用注册

2.1. 抽离导航

抽离导航–>src/const/nav.js

export const NAV_LIST = [...]

components/MainNav.vue

+ import { NAV_LIST } from '../const/nav'

vue3使用路由进行跳转:

  • import {useRouter, useRoute} from ‘vue-router’

  • router.push(data.url)

router/index.js

import { createRouter, createWebHistory,createWebHashHistory } from 'vue-router';

const routes = [
  {
    path: '/',
    component: () => import('../App.vue'),
  },
  {
    path: '/react15',
    component: () => import('../App.vue'),
  },
  {
    path: '/react16',
    component: () => import('../App.vue'),
  },
  {
    path: '/vue2',
    component: () => import('../App.vue'),
  },
  {
    path: '/vue3',
    component: () => import('../App.vue'),
  },
];

const router =  (basename='')=>createRouter({
//   history: createWebHashHistory(),
  history: createWebHistory(basename),
  routes,
});

export default router();

main.js

createApp(App).use(router).mount('#micro_web_main_app')

components/MainNav.vue

<script>
import { ref, watch } from 'vue'
import { NAV_LIST } from '../const/nav'
import {useRouter, useRoute} from 'vue-router'
export default {
  name: 'MainNav',
  setup() {
    const router = useRouter()
    const route = useRoute() // 获取当前路由对象

    // 刷新时候,在当前路由
    watch(route,(val)=>{
      console.log(val);
      // console.log(val.fullPath) // 当前路由
      for (let i = 0; i < NAV_LIST.length; i++) {
        if (val.fullPath.indexOf(NAV_LIST[i].url)!==-1) { // 如果当前路由与路由匹配上
           currentIndex.value = i  // 设置active
        }
      }
    }, {deep: true})    // 深度监听

    const currentIndex = ref(0) // 创建响应式变量
    
    const setCurrentIndex = (data, index) => {
      // 优化:如果当前路由就是当前的路由,就不要触发set
      if (data.url === route.fullPath) {
        return ;
      }

      currentIndex.value = index
      router.push(data.url)
    }

    const searchStatus = ref(true)
    const setSearchStatus = (type) => {
      searchStatus.value = type
    }
    return {
      NAV_LIST,
      currentIndex,
      setCurrentIndex,
      searchStatus,
      setSearchStatus,

    }
  }
}
</script>
  1. 刷新时候,在当前路由
  2. 优化:如果当前路由就是当前的路由,就不要触发set
2.2 创建store,激活规则

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LKKjgkki-1661697368735)(img/image-20220828223044842.png)]

/store/sub.js

// vue2
// - http://:localhost:9080/#/
//     - energy

// vue3
// - http://:localhost:9081/#/
//     - index
//     - select
// react15
// - http://:localhost:9082/#/
//    -/information
//    -/information-last
//    -/video
//    -/video-last
// react17
// - http://:localhost:9083/#/
//     -/login
//     -/new-car
//     -/rank

// ```

// 子应用列表
export const subNavList = [
    {
        name:'react15', //子应用名称
        activeRule:'/react15', // 激活规则
        container:'#micro-container' ,// 显示的容器,唯一标识
        entry:'//localhost:9082/' // 启动的入口
    },
    {
        name:'react17', 
        activeRule:'/react17', 
        container:'#micro-container',
        entry:'//localhost:9083/' // 启动的入口

    },
    {
        name:'vue2', 
        activeRule:'/vue2', 
        container:'#micro-container',
        entry:'//localhost:9080/'
    },
    {
        name:'vue3', 
        activeRule:'/vue3', 
        container:'#micro-container',
        entry:'//localhost:9081/'
    }
]

/store/utils.js

import { MicroStart } from '../../micro'

const { registerMicroApps }= MicroStart
// 注册子应用
export const registerApp=(list)=>{
    // 注册到微前端框架
    registerMicroApps(list)
}

main.js注册

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { subNavList } from './store/sub'
// 主应用引入 util 方法
import { registerApp } from './store/utils'

+ registerApp(subNavList)

createApp(App).use(router).mount('#micro_web_main_app')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0oKF1Gbv-1661697368737)(img/image-20220828223022963.png)]

micro/start.js

// start 文件
const registerMicroApps = (appList)=>{
    // 注册到window上
    window.appList = appList
}


export default {
    registerMicroApps
}

micro/index.js

// 引入文件
export {default as MicroStart } from './start'

输入window.appList,将其注册到主应用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x9BbhMiK-1661697368738)(img/image-20220828221553817.png)]

一般不能将其放到全局,所以进行优化,后续通过getList方法获取整体内容

新建const/subApps.js

let list = []

export const getList = () => list

export const setList = (appList) => list = appList

优化: 将其保存在内部变量中, 通过getList方法获取整体内容

micro/start.js

import { setList } from './const/subApps'
// start 文件
const registerMicroApps = (appList)=>{
    // 注册到window上
    // window.appList = appList
   + setList(appList)
}


export default {
    registerMicroApps
}

17.中央控制器-注册子应用

回顾:

  1. 通过useRouter(路由跳转方法, push,…), 与useRoute(路由信息)
  2. 子应用列表subList, (name, activeRule, container, entry)
  3. 注册到主应用registerApp

这里可以选择其他的变量保存策略

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小李科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值