CustomEvent-微前端应用间通信原理&应用💡

662 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情

本文主要介绍CustomEvent及其在微前端应用间通信中的应用。

1 CustomEvent

MDN中对CustomEvent的介绍如下:

CustomEvent 事件是由程序创建的,可以有任意自定义功能的事件。

可以利用构造函数CustomEvent()来创建自定义功能的事件。

栗子如下:

<script type="text/javascript">

  /* 创建一个事件对象,名字为newEvent,类型为build */

  var newEvent = new CustomEvent('build', { bubbles:true,cancelable:true,composed:true });



  /* 给这个事件对象创建一个属性并赋值,这里绑定的事件要和我们创建的事件类型相同,不然无法触发 */

  newEvent.name = "新的事件!";



  /* 将自定义事件绑定在document对象上 */

  document.addEventListener("build",function(){

      alert("你触发了使用CustomEvent创建的自定义事件!" + newEvent.name);

  },false)



  /* 触发自定义事件 */

  document.dispatchEvent(newEvent);

</script>

在caniuse.com上搜索CustomEvent发现

在IE中可做如下polyfill

/**

 * CustomEvent constructor polyfill for IE

 */

(function () {

    if (typeof window.CustomEvent === 'function') {

        // 如果不是IE

        return false;

    }



    var CustomEvent = function (event, params) {

        params = params || {

            bubbles: false,

            cancelable: false,

            detail: undefined

        };

        var evt = document.createEvent('CustomEvent');

        evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);

        return evt;

    };



    CustomEvent.prototype = window.Event.prototype;



    window.CustomEvent = CustomEvent;

})();

2 CustomEvent的应用

CustomEvent可应用于微前端中应用间的通信。为进行实操,从GitHub上clone了一份qiankun(github.com/umijs/qiank…)的源码。主要做了如下改造:

examples/main/multiple.js

import { loadMicroApp } from '../../es';



let app;



document.addEventListener("qiankun", function(){

  // alert("你触发了使用CustomEvent创建的自定义事件!" + qiankunEvent.name);

  alert("你触发了使用CustomEvent创建的自定义事件!");

},false)



function mount() {

  app = loadMicroApp(

    { name: 'react15', entry: '//localhost:7102', container: '#react15' },

    { sandbox: { experimentalStyleIsolation: true } },

  );

}



function unmount() {

  app.unmount();

}



document.querySelector('#mount').addEventListener('click', mount);

document.querySelector('#unmount').addEventListener('click', unmount);



loadMicroApp({ name: 'vue', entry: '//localhost:7101', container: '#vue' });

examples/vue/src/views/About.vue

<template>

  <div class="about">

    <h1>This is about page</h1>

    <el-button type="primary" @click="onClick">Click Main</el-button>

    <el-button type="primary" @click="onCall">Call React15</el-button>

    <p>{{message}}</p>

  </div>

</template>



<script>

export default {

  data() {

    return {

      message: 'vue'

    }

  },

  methods: {

    onClick(){

      document.dispatchEvent(new CustomEvent('qiankun', { bubbles:true,cancelable:true,composed:true }))

    },

    onCall(){

      document.dispatchEvent(new CustomEvent('qiankun:react15', { bubbles:true,cancelable:true,composed:true }))

    }

  },

  mounted () {

    const _this = this

    document.addEventListener("qiankun:vue", function(){

      // alert("你触发了使用CustomEvent创建的自定义事件!" + qiankunEvent.name);

      alert("你触发了使用CustomEvent创建的自定义事件!vue");

      _this.message = 'React15 call Vue'

    },false)

  },

}

</script>



<style scoped>

  .about {

    color: #7265e6;

  }

</style>

examples/react15/App.jsx

import React, { version as reactVersion } from 'react';

import { version as antdVersion, Button } from 'antd';



import Logo from './components/Logo'

import HelloModal from './components/HelloModal'

// import { message } from 'vfile/node_modules/vfile-message';



export default class App extends React.Component {

  constructor(props){

    super(props)

    this.state = {

      message: 'React15'

    }

    this.setCall = message => {

      console.log('message', message)

      document.dispatchEvent(new CustomEvent('qiankun:vue', { bubbles:true,cancelable:true,composed:true }))

    }

  }

  componentDidMount(){

    const _this = this

    document.addEventListener("qiankun:react15", function(){

      // alert("你触发了使用CustomEvent创建的自定义事件!" + qiankunEvent.name);

      alert("你触发了使用CustomEvent创建的自定义事件!React15");

      _this.setState({

        message: 'Vue call React15'

      })

    },false)

  }

  render() {

    return (

      <div className="react15-main">

        <Logo />

        <p className="react15-lib">

          React version: {reactVersion}, AntD version: {antdVersion}

        </p>

        <HelloModal />

        <p>{this.state.message}</p>

        <Button onClick={() => this.setCall('call vue')}>Call Vue</Button>

      </div>

    );

  }

}

启动跟路径下package.json中的

examples:start-multiple可以在浏览器中看到如下页面。

通过上述实践可知,基于CustomEvent的微前端应用通信机制具有浏览器原生支持、应用间弱耦合等优点,也具有全局命名冲突、缺乏规范等缺点。

3 总结

本文主要介绍了CustomEvent及其在微前端应用间通信中的应用。CustomEvent是浏览器原生支持的API,但存在兼容性问题,可以polyfill。CustomEvent可以应用于微前端应用间的通信。

参考文献

[1] www.cnblogs.com/cwsb/p/1038…

[2] developer.mozilla.org/zh-CN/docs/…

[3] developer.mozilla.org/zh-CN/docs/…

[4] www.mifengjc.com/api/CustomE…

[5] www.jianshu.com/p/1cf1c80c0…

[6] juejin.cn/post/684668…

[7] qiankun.umijs.org/zh/faq

[8] github.com/lijiakof/fr…

53875b26-8251-4ccc-ad02-70badf65d662.gif