Vue3 release is imminent, first to a wave of private Vue3 preliminary trample pit

As we all know, UI component is one of the core concepts of modern front-end framework. With the booming development of community, more and more ways to create components have been developed, bringing great convenience to developers. A plethora of concepts, especially the React community’s exploration of components, developers went through Mixin, HOC, render props, hooks; With the Vue3 Composition API, both front-end frameworks (libraries) chose hooks as the best way to abstract components. So going back to the components themselves, a component goes from generation to rendering to destruction in a similar way

In the ERA of Vue2.0, front-end components are created and mounted on a page in two ways:

  • Create the component normally, and register the child component in the parent component, template declaration is ok

    export default {
      components: {
        childComponent,
      }
    }
    Copy the code
  • Extend to create a Vue subclass, then $mount to instantiate the component, get the generated Dom node to insert the body or any parent component (see elemental-ui this.$loading for instantiation); It is worth mentioning that vue-create-API takes a similar but slightly different approach. Vue-create-api directly instantiates a VUE and binds the caller’s lifecycle to make logical destruction more intuitive.

    import loadingVue from './loading.vue'
    const LoadingConstructor = Vue.extend(loadingVue)
    
    let instance = new LoadingConstructor({
      el: document.createElement('div'),
      data: options
    })
    Copy the code

Modern front-end frame-building components are just plain unpretentious and efficient.

With the Custom Renderer API, you can theoretically customize the rendering functions for any platform and render VNode to different platforms, such as applets. You can make a copy of the @vue/ Runtime-dom at @vue/ Runtime-miniProgram. Also, @vue/ Runtime-dom gives developers a new way to create components, so let’s give it a try.

Prepare a load.vue component first

<template>
  <transition name="v">
    <div v-show="isShow" class="loading">
      <span>{{ msg }}</span>
    </div>
  </transition>
</template>

<script lang="tsx">
import { defineComponent, ref } from 'vue'
export default defineComponent({
  name: 'Loading'.props: {
    msg: {
      type: String
    },
  },
  setup(props, context) {
    const isShow = ref(false)
    return {
      isShow
    }
  },
  methods: {
    show() {
      this.isShow = true
      this.$emit('show')
    },
    hide() {
      this.isShow = false
    },
  },
  mounted() {
    console.log('mount')
  },
  unmounted() {
    console.log('uninstall')}})</script>
<style lang="stylus">.loading position fixed top 0 left 0 right 0 bottom 0 display flex flex-direction column // justify-content center align-items center transition all .3s ease span position relative top -20px font-size 32px font-family Helvetica Neue For Number,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif color #333 .v-enter-from, .v-leave-to { opacity: 0; } .v-leave-from, .v-enter-to { opacity: 1; }</style>
Copy the code

Next, write a factory function to render the component (see vue-create-API).

// create-api.ts
import { App, createVNode, render, mergeProps, ComponentOptions } from 'vue'
// Obviously we need a singleton
let _instance: any = null

export const useCreate = function(Component: ComponentOptions, app? : App, options? :any.) {
  if(! _instance) {/** * The default render function does not support the DocumentFragment argument  * // vue-shim.d.ts * import * as vue from 'vue' * declare moudle 'vue' { * export declare const render: vue.RootRenderFunction
      
        * } * declare module '@vue/runtime-core' { * interface ComponentCustomProperties { * $createLoading: () => any * } * } */
      
    const container = document.createDocumentFragment()
    // Generate vNodes directly from components
    _instance = createVNode(Component)
    // Vue3 props is flat, so events can be onMethods directly; Similar to React props, merging properties is easier
    _instance.props = mergeProps(_instance.props, {
      // Test the code
      msg: 'it\'s a prop msg'.// Test the code
      onShow() {
        console.log('emit handler')},... options, })// Render the component and insert it into the body
    render(_instance, container)
    document.body.appendChild(container)
    // Add a remove method to the component to destroy the component
    _instance.component.ctx.remove = function() {
      render(null, container)
      _instance = null
    }
    // Expose a method for updateprops
    _instance.component.ctx.$updateProps = function(props: any) {
      props && Object.keys(props).forEach(k= > {
        _instance.component.props[k] = props[k]
      })
    }
  }
  // Expose the component directly
  return _instance.component.ctx
}
// Expose a plug-in API
const install = (app: App, Component: ComponentOptions) = > {
  // Mount a traversal method on this, or use provider
   app.config.globalProperties[`$create${Component.name}`] = useCreate(Component, app)
}
export default install
Copy the code

How do you use it? Is also very simple

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import Loading from 'path/to/Loading.vue'
import { useCreate } from 'path/to/create-api.ts'

const app = createApp(App)
app.mount('#app')

const loading = useCreate(Loading, app)
loading.show()

setTimeout((a)= > {
  loading.$updateProps({
    msg: A 'test message',}}),1000)

setTimeout((a)= > {
  loading.remove()
}, 5000)
Copy the code

At this point, with a little polish, developers are happy to create components.

I wish you all a happy life.

Limited by the author’s development ability, the code in this paper may have some bugs, welcome to contact the author to discuss FAQ:

  • Q: What’s the use of writing code like this? A: Hahaha, I don’t know
  • Q: When will Vue3 be released? A: Around August 2020
  • Q: Vue or React? A: Please wipe the keyboard for me

This post was originally posted on my blog