插件 + teleport

Vue2 - Vue.extend

const Title = Vue.extend({
	template: `<h1>Vue.extend</h1>`
});

const titleComponent = new Title();

console.log(titleComponent); // vue 组件实例
titleComponent.$mount('title'); // 把 上边 template Title 挂载到 html 的 #id title 上去

Untitled

MessageBox 组件案例

// 1. 引入对话框组件
import _MessageBox from "./MessageBox.vue";

export default {
  // 2. 利用 插件 来完成功能
  install(Vue) {
    let instance = null;
    // 注册 我们创建好的 MessageBox.vue 组件
    Vue.component(_MessageBox.name, _MessageBox);

    // 在Vue的原型上定义一个全局对象 放置展开 和 关闭 的方法
    Vue.prototype.$messageBox = {
      show,
      hide,
      info,
      success,
    };

    // 挂载组件到dom上
    function show(props, callback) {
      if (!instance) {
        // 我们利用 extend 方法拿到组件的 构造器
        const MessageBox = Vue.extend({
          // 使用 render 函数 将我们 MessageBox.vue 渲染到 instance 里 (虚拟DOM)
          render: (h) =>
            h("message-box", {
              props,
            }),
        });

        // new 构造器 将返回来的实例 放到instance身上, 创建子类的实例 就相当于在视图中基于 <kebab-case> 模式调用了组件
        instance = new MessageBox();
        // 组件这个组件, 将实例对象 转成 组件 保存到 this.vm 上
        this.vm = instance.$mount();
        // 当我们渲染了这个组件后就可以拿到 $el. 它就是我们渲染后的真实dom
        document.body.appendChild(this.vm.$el);

        callback && callback();
      }
    }
    // 销毁挂载到dom上的组件
    function hide(callback) {
      document.body.removeChild(this.vm.$el);
      instance.$destroy();
      instance = null;
      this.vm = null;

      callback && callback();
    }
    function info(props, callback) {
      this.show({ ...props, type: "primary" }, callback);
    }
    function success(props, callback) {
      this.show({ ...props, type: "success" }, callback);
    }
  },
};
<template>
  <div :class="['message-box', type]">
    <div class="inner">
      <header class="header">
        <h1 class="title">{{ title }}</h1>
        <span class="close-btn" @click="hideMessageBox">x</span>
      </header>
      <div class="content">{{ content }}</div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'MessageBox',
  props: {
    title: {
      type: String,
      default: "标题默认值"
    },
    content: {
      type: String,
      default: "内容默认值"
    },
    type: {
      type: String,
      default: "primary",
      validator(value) {
        return [
          'primary',
          'success',
          'warning',
          'danger'
        ].includes(value);
      }
    },
  },
  methods: {
    hideMessageBox() {
      this.$messageBox.hide(() => {
        console.log('关闭');
      });
    }
  }
}
</script>

Vue3 - Vue.createApp

const app = createApp(App);

const app2 = createApp({
  template: `<h1>Vue3 createApp</h1>`,
  data() {
    return {
      title: "Lance",
    };
  },
});

app2.mount("#title");

app.mount("#app");

Vue3 + Teleport 案例

MyModal 组件

MyModal/MyModal.vue

<template>
  <teleport to="body" :disabled="false">
    <div :class="['modal', type]" v-show="isShow">
      <div class="inner">
        <header class="hd">
          <h1>{{ title }}</h1>
          <span @click="isShow = false">x</span>
        </header>
        <section class="wrap">
          <p>{{ content }}</p>
        </section>
      </div>
    </div>
  </teleport>
</template>

<script>
export default {
  name: "Modal",
  props: {
    
  },
  data() {
    return {
      isShow: false,
      type: 'primary',
      title: 'Default Title',
      content: 'Default CONTENT'
    };
  },
  methods: {
    openModal() {
      this.isShow = true;
    },
    init({ show, type, title, content }) {
      this.isShow = show;
      this.setOptions({ type, title, content });
    },
    open(options) {
      this.isShow = true;
      this.setOptions(options);
    },
    setOptions({ type, title, content }) {
      this.type = ['primary', 'success', 'warning', 'danger'].includes(type) ? type : this.type;
      title && (this.title = title);
      content && (this.content = content);
    },
    primary(options) {
      this.isShow = true;
      this.setOptions({
        ...options,
        type: 'primary',
      });
    },
    success(options) {
      this.isShow = true;
      this.setOptions({
        ...options,
        type: 'success',
      });
    },
    ...
  },
};
</script>

MyModal/index.js

实现 install 方法,挂载组件实例到 app 上

import Modal from "./MyModal.vue";
import { createApp } from "vue";

export default {
  install(app) {
    const modal = createApp(Modal);
    const oFrag = document.createDocumentFragment();
    const $modal = modal.mount(oFrag);
    app.config.globalProperties.$modal = $modal;
    console.log({ modal, $modal }); // 组件实例,应用实例
  },
};

index.js