build-out-components是打包的入口文件,webpack.out-components.prod.conf.js是webpack打包的配置文件,out-components-tools.js是工具库,这边是打包的entry自动获取(默认为src/out-components),还有自动删除之前打包的文件。
目前的文件目录为
通过打包生产文件:
在static下outComponents文件夹内的js文件。(最终打包需要打包到dist下面,这边做测试先打包在static文件下,方便后续动态组件ajax获取组件使用)
门户的小部件是通过配置url,和调整布局来生产的。因此业务组件至此已经完成了。只需要提供对门户暴露的url即可。
接下来就是门户这边加载动态组件的实现了。门户这边就相对简单了。看如下图配置:
门户通过component的动态组件来实现加载异步组件,通过ajax请求刚才打包的url,然后实例化函数new Function来赋值给mode(new Function之所以分成2部,是因此效验规则的问题,可忽略)。这样就实现了动态加载异步组件了。门户和业务组件可以各个开发,任何业务开发数据概览,门户都不需要改代码,只需要界面上配置url即可。这个异步加载组件已经结束了。这边门户需要封装一封实现异步组件。父级只需要传入url即可。这边还有个可以优化的是,可以把mode优先缓存,那么不需要每次都去加载请求。如下:
我们可以看到在门户的一个数据概览页面上加载了多个异步组件,那么异步组件之间也是可能存在通信的,这样该如何做呢?因为现在已经不是iframe嵌套了,可以通过监听一个组件,然调用另一个组件的方法,这样确实可以实现平级组件间的通信,但这样势必不可取的,因为一旦这样做了门户必须要根据业务来辅助,修改代码来实现功能。因此这边借用门户来生成vue事件总线(空的vue实例)来实现。
门户代码如下: 在this.$root上挂在一个事件总线:
created () { if (!this.$root.eventBus) { this.$root.eventBus = new Vue() } }
然后业务组件之间就可以根据自己的业务实现通信:
组件一和组件二代码如下:
<template> <div> 这是一个外部组件a1 <hello-word></hello-word> </div> </template> <script> import helloWord from '../components/HelloWorld' export default { data () { return { i: 0 } }, components: { helloWord }, mounted () { setInterval(() => { this.i++ if (this.i < 10) { this.test() } }, 1000) }, methods: { test () { this.$root.eventBus.$emit('childEvent', this.i) } } } </script>
<template> <div> 这也是外部组件哦 <div > 这是a1传来的{{a1}} </div> </div> </template> <script> export default { data () { return { a1: 0 } }, created () { this.$root.eventBus.$on('childEvent', this.change) }, methods: { change (i) { this.a1 = i } } } </script>
业务组件就可以根据this.$root.eventBus和vue上的事件传递($emit, $on)来实现相互的通信。
总结:本篇主要借助vue的动态组件和webpack打包单文件来实现动态加载异步组件,通过vue的事件总线挂载在this.$root上来实现平级组件之间的通信。
拓展方向:这个方式不仅仅可以应用在门户单个页面上的小部件上,同样如果某个项目中的页面文件需要复用时,不想通过代码的复制,同样可以再那个文件配置打包单文件配置,打包出的文件在领一个项目中动态加载出来即可。这种模式与通用组件的install模式是有点类似的,只是这个单文件vue不是通用的,但同样可以达到打包复用页面。