zoukankan      html  css  js  c++  java
  • vue3如何编写挂载DOM的插件

    文章来源:https://www.cnblogs.com/flicat/p/15062543.html

    vue3 跟 vue2 相比,多了一个 app 的概念,vue3 项目的创建也变成了

    // main.js
    import { createApp } from 'vue' import App from './App.vue'
    import ElementPlus from 'element-plus' const app = createApp(App) app.use(ElementPlus) // 使用饿了么框架
    app.mount('#app')

    所以 Vue.extend 也没有了。

    vue2创建一个插件:

    export default function install (Vue) {
      let app = Vue.extend({
        render (h) {
          return h('div', {
            style: {
              display: this.isShow ? 'flex' : 'none'
            }
          })
        }
      })
    
      let appDom = new app({
        el: document.createElement('div'),
        data: function () {
          return {
            isShow: false
          }
        }
      })
    
      function show () {
        appDom.isShow = true
      }
    
      function hide () {
        appDom.isShow = false
      }
      Vue.prototype.$show = show
      Vue.prototype.$hide = hide
      document.body.appendChild(appDom.$el)
    }

     

    vue3创建一个插件:

    import { createApp, h } from 'vue'
    
    export default function install (App) {
      let app = createApp({
        data() {
          return {
            isShow: false,
          }
        },
        render() {
          return h('div', {
            style: {
              display: this.isShow ? 'flex' : 'none'
            }
          })
        }
      })
      
      const vNodeDom = document.createElement('div')
      document.body.appendChild(vNodeDom)
      const vm = app.mount(vNodeDom)
    
      App.config.globalProperties.$show = function () {
        vm.isShow = true
      }
    
      App.config.globalProperties.$hide = function () {
        vm.isShow = false
      }
    }

     

    对比可以发现, vue3 的 DOM挂载方式是新创建一个 app 然后调用 mount() 方法插入到页面中。

    全局方法的挂载方式也从 vue2 的 Vue.prototype 到 vue3 的 App.config.globalProperties。

    除此之外,vue3 的插件如果用 createApp 来创建新的DOM结构插入到页面的话,与 main.js 中创建的 app 是隔绝开来的,这意味着 main.js 中 use 的组件和公共方法在 这个插件中无法使用。

    // myCom.vue
    <template>
      <el-button>按钮</el-button>
    </template>


    // myCom.js
    import { createApp, h } from 'vue'
    import myCom from './myCom.vue'
    export default function install (App) {
      let app = createApp({
        data() {
          return {
            isShow: false
          }
        },
        render() {
          return h(myCom)
        }
      })
    
      const vNodeDom = document.createElement('div')
      document.body.appendChild(vNodeDom)
      app.mount(vNodeDom)
    }

     

    上面的例子中,el-button 是无法正常显示的,控制台会报错:

    [Vue warn]: Failed to resolve component: el-button

     

     所以,如果既想要新建DOM,又要使用main.js全局注册的组件和方法,那就不能用 createApp,

     在请教了 vue3 的开发大佬后,有了以下方案:(issues

     

    import { render, h } from 'vue'
    import myCom from './myCom.vue'

    export default function install (App) {
      let vNode = h({
        data() {
          return {
            isShow: false,
          }
        },
        render() {
          return h(myCom)
        }
      })
    
      const vNodeDom = document.createElement('div')
      document.body.appendChild(vNodeDom)
      vNode.appContext = App._context
      render(vNode, vNodeDom)
    
      App.config.globalProperties.$show = function () {
        vNode.component.proxy.isShow = true
      }
    
      App.config.globalProperties.$hide = function () {
        vNode.component.proxy.isShow = false
      }
    }

     

     这次没有创建新的 app,而是通过给 vNode 复制原来 app 的 context,从而达到组件和公共方法共用,

     新创建的插件属性和方法通过 vNode.component.proxy 来访问。

    el-button 也正确的解析出来了

     

  • 相关阅读:
    SpringBoot实现原理
    常见Http状态码大全
    forward(转发)和redirect(重定向)有什么区别
    1094. Car Pooling (M)
    0980. Unique Paths III (H)
    1291. Sequential Digits (M)
    0121. Best Time to Buy and Sell Stock (E)
    1041. Robot Bounded In Circle (M)
    0421. Maximum XOR of Two Numbers in an Array (M)
    0216. Combination Sum III (M)
  • 原文地址:https://www.cnblogs.com/flicat/p/15062543.html
Copyright © 2011-2022 走看看