Vue3 has been released for some time now. There are a lot of articles about Vue3, including the composite API, Typescript, source code, etc., but there are a lot of articles about global API components, so let’s share how to develop and use global API components

Let’s first review the implementation in VUe2

Take an alert component as an example

<template> <transition name="alert-fade" @after-leave="destroyElement"> <div class="alert" v-if="show"> <div class="ht-modal" @click="close"></div> <div class="alert-box" :style="'width:'+ width"> <div class="alert-header"> <i class="iconfont icon-error alert-close" @click="close"></i> </div> <div class="alert-body"> {{ message }} </div> <div Class ="alert-footer"> <slot name="footer"> <div class="alert-btn" @click="close"> Set </div> </slot> </div> </transition> </template> <script> export default { name: 'Alert', props: { width: { type: String, required: false, default: '30%', }, msg: { type: String, required: false, default: () => 'some message' }, handleClose: { type: Function, required: false, default: null } }, data () { return { show: true, message: this.msg } }, methods: { close($event) { this.show = false this.$emit('close', $event) }, destroyElement() { this.handleClose && this.handleClose() } }, } </script>Copy the code

The file name is alert.vue. Create the alert.js file in the same directory

import Main from './alert.vue'

const Alert = {}
Alert.install = Vue => {
  let instance
  let show = false
  let AlertConstructor = Vue.extend(Main)

  const loadAlert = options => {
    if ( show ) return
    let { handleClose } = options
    options.handleClose = () => {
      handleClose && handleClose()
      show = false
    }

    instance = new AlertConstructor({
      propsData: options
    })
    const component = instance.$mount()

    document.body.appendChild(component.$el)
  }


  Vue.prototype.$alert = loadAlert
}

export default Alert
Copy the code

The key here is to invoke the extend method on Vue to inherit the Alert component property. Of course, you can also create a new Vue example to achieve the same effect, because the example is created by instantiating the Vue constructor, so binding the API methods to the constructor’s prototype object can achieve inheritance

import Alert from 'alert.js' import Vue from 'vue' Vue.use(Alert) new Vue(...) .$mount(el)Copy the code

Once registered, we can call this method from anywhere to render the component through this

This.$alert({width: '50%', MSG: 'this is a global API component ', handleClose: function() {console.log(' I was shut down!! ')}})Copy the code

So that’s a brief review of how to develop and use an API component in Vue2. What’s the difference in Vue3 implementation

In Vue3, the createApp method is used to return the instance object, and the extend method is cancelled. We mentioned above that we can create a new instance object to implement this method

import { createApp } from 'vue' import Main from './alert.vue' const Alert = {} Alert.install = app => { let instance let container = null const loadAlert = options => { if (container) return let { handleClose } = options options.handleClose = () => { handleClose && handleClose() document.body.removeChild(container) instance.unmount() container = null } container = document.createElement('div') instance = createApp(Main, options) instance.mount(container) document.body.appendChild(container) } app.config.globalProperties.$alert = loadAlert  } export default AlertCopy the code

$mount (dom) = $mount (dom) $mount (dom) = $mount (dom) $mount (dom) = $mount (dom) 3 is added to the global properties of the Config object of the instance application, and the following registration and use methods are completely the same

Further down the line, one of the most important features of Vue3 is the composite API, which gives us great flexibility to write code, The main reason for using the Vue component is to take advantage of its ability to render the DOM in a responsive manner so that rendering operations can be done easily and efficiently. The main apis are createVnode, H and Render, and we can use these apis to achieve the same effect

import { h, createVNode, render } from 'vue'
Copy the code

The h and createVnode methods both return a VNode object, which has the same effect or can be used interchangeably

const vnode = h(Main, options)
const vnode = createApp(Main, options)
Copy the code

Finally we need to call the Render method to pass in the vNode and the parent element to mount

render(vnode, container)
Copy the code

And finally our code can be changed to

import { h, createVNode, render } from 'vue' import Main from './alert.vue' const Alert = {} Alert.install = app => { let container = null const loadAlert = options => { if (container) return let { handleClose } = options options.handleClose = () => { handleClose && handleClose() document.body.removeChild(container) container = null } container = document.createElement('div') const  vnode = h(Main, options) //const vnode = createVNode(Main, Options) / / can also use createVnode method replacing h render (vnode, container) document. The body. The appendChild (container)} app.config.globalProperties.$alert = loadAlert } export default AlertCopy the code

Create a VNode, call render, and mount it to the container. Create a vNode, call render, and mount it to the container. So that’s one of the advantages of a composite API, where I import whatever I need to do to avoid code redundancy, right

Finally, we analyze the implementation of global call mode of 2 and 3. In 2, through the inheritance of prototype chain, API methods are exposed on the prototype object of the Vue constructor, and singleton is applied for global call. 3, the Proxy agent, by rewriting reading behavior, enclosing $alert access to is in fact the app. Config. GlobalProperties. $alert method