Vue动态创建组件实例并挂载到body

方式一

import Vue from 'vue'

/**
 * @param Component 组件实例的选项对象
 * @param props 组件实例中的prop
 */
export function create(Component, props) {
  const comp = new (Vue.extend(Component))({ propsData: props }).$mount()
  
  document.body.appendChild(comp.$el)

  comp.remove = () => {
    document.body.removeChild(comp.$el)

    comp.$destroy()
  }

  return comp
}

方式二

import Vue from 'vue'

export function create(Component, props) {
  // 借鸡生蛋new Vue({render() {}}),在render中把Component作为根组件
  const vm = new Vue({
    // h是createElement函数,它可以返回虚拟dom
    render(h) {
      console.log(h(Component,{ props }));
      
      // 将Component作为根组件渲染出来
      // h(标签名称或组件配置对象,传递属性、事件等,孩子元素)
      return h(Component, { props })
    }
  }).$mount() // 挂载是为了把虚拟dom变成真实dom
  // 不挂载就没有真实dom
  // 手动追加至body
  // 挂载之后$el可以访问到真实dom
  document.body.appendChild(vm.$el)

  console.log(vm.$children);
  
  // 实例
  const comp = vm.$children[0]

  // 淘汰机制
  comp.remove = () => {
    // 删除dom
    document.body.removeChild(vm.$el)

    // 销毁组件
    vm.$destroy()
  }

  // 返回Component组件实例
  return comp
}

使用

  • A组件(要动态创建的组件)
<template>
  <div class="a">
    <h2>{{ title }}</h2>
    <p>{{ data }}</p>
  </div>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      default: "hello world!"
    },
    message: {
      type: String,
      default: "o(∩_∩)o 哈哈"
    },
    duration: {
      type: Number,
      default: 1000
    }
  },
  data() {
    return {
      data: "我是a组件",
    };
  },
  created() {
    let num = 1
    
    const timer = setInterval(() => {
      this.data = num++
    }, this.duration)

    this.$once("hook: beforeDestroy", () => clearInterval(timer))
  }
};
</script>

<style>
.a {
  position: fixed;
  width: 100%;
  top: 16px;
  left: 0;
  text-align: center;
  pointer-events: none;
  background-color: #fff;
  border: grey 3px solid;
  box-sizing: border-box;
}
</style>
  • B组件(操作动态创建组件的地方)
<template>
  <div class="b">
    <button @click="createA">创建</button>
  </div>
</template>

<script>
import A from "@/components/A.vue"
import { create } from "@/utils/create.js"
export default {

  components: {
    A,
  },
  methods: {
    createA() {
      // 创建A组件,并挂载到body上
      create(A, { title: "vue", message: "么么哒😙" })
    }
  },
};
</script>

 

posted @ 2023-08-24 19:27  front-gl  阅读(499)  评论(0编辑  收藏  举报