vue3 中如何像 vue2 的 extend 一样挂载未挂载的组件,拿到标签本身($el)

简介:最近在用 vue3 写个新项目,需要挂载自定义的组件,但是发现 vue3 中不再支持 extend 方法了,于是查看了 vant 最新的源码,发现里面有类似实现,特此提炼总结出来。

1.vue2 写法

1
<!DOCTYPE html>
2
<html lang="en">
3
  <head>
4
    <meta charset="UTF-8" />
5
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
    <title>Document</title>
7
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
8
  </head>
9
10
  <body>
11
    <div id="app"></div>
12
  </body>
13
14
  <script>
15
    // 创建构造器
16
    const DemoConstructor = Vue.extend({
17
      render(h, props) {
18
        return h('div', { style: { fontSize: '24px' } }, '你好' + this.name)
19
      }
20
    })
21
    // 创建 DemoConstructor 实例
22
    const instance = new DemoConstructor({ data: { name: '小米' } })
23
    // 手动地挂载一个未挂载的实例。
24
    instance.$mount()
25
    console.log(instance.$el)
26
  </script>
27
</html>

2.vue3 写法

1
<!DOCTYPE html>
2
<html lang="en">
3
  <head>
4
    <meta charset="UTF-8" />
5
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
    <title>Document</title>
7
    <script src="https://unpkg.com/vue@3.0.2"></script>
8
  </head>
9
10
  <body></body>
11
12
  <script>
13
    const { createApp, h, ref } = Vue
14
    // vant  源码中是直接用的setup返回的jsx,我这里用的是vue的cdn用法,没有环境支持
15
    const app = createApp({
16
      setup(props) {
17
        const name = ref('小米')
18
        return { name }
19
      },
20
      render() {
21
        return h('div', { style: { fontSize: '24px' } }, '你好' + this.name)
22
      }
23
    })
24
    // 提供一个父元素
25
    const parent = document.createElement('div')
26
    //mount方法不再像vue2一样支持未挂载的实例,必须得挂载,即必须得给参数
27
    const instance = app.mount(parent)
28
    console.log(instance)
29
    console.log(instance.$el)
30
  </script>
31
</html>

3.(补充) 在应用之间共享配置

JS 用户把里面的类型删除就可以了

1
import { createApp as createBaseApp, Component } from 'vue'
2
import router from './router'
3
import store from './store'
4
import ElementPlus from 'element-plus'
5
import 'element-plus/dist/index.css'
6
import { createI18n } from 'vue-i18n'
7
8
import Foo from './Foo.vue'
9
import Bar from './Bar.vue'
10
11
const messages = {
12
  en: {
13
    message: {
14
      message1: 'hello world -1',
15
      message2: 'hello world -2'
16
    }
17
  },
18
  zh: {
19
    message: {
20
      message1: '你好,世界 -1',
21
      message2: '你好,世界 -2'
22
    }
23
  }
24
}
25
26
const i18n = createI18n({
27
  locale: 'en',
28
  fallbackLocale: 'en',
29
  messages
30
})
31
32
export const createApp = (
33
  options: Component,
34
  rootProps?: Record<string, unknown> | null
35
) => {
36
  const app = createBaseApp(options, rootProps)
37
  app.use(ElementPlus).use(i18n).use(router).use(store)
38
  return app
39
}
40
41
const app2 = createApp(Foo).mount('#foo')
42
const app3 = createApp(Bar).mount('#bar')

参考链接

1.https://github.com/youzan/vant/blob/v3.0.0-beta.10/src/dialog/index.js

2.https://github.com/youzan/vant/blob/v3.0.0-beta.10/src/utils/mount-component.ts

3.https://v3.cn.vuejs.org/guide/migration/global-api.html#%E5%9C%A8%E5%BA%94%E7%94%A8%E4%B9%8B%E9%97%B4%E5%85%B1%E4%BA%AB%E9%85%8D%E7%BD%AE