Vue3设计方案-使用服务方式来调用vue组件

本文介绍了如何在Vue3中,无需引入Message组件,直接通过JavaScript调用的方式来显示和管理全局提示,包括组件实例化、挂载与卸载的API实现,并展示了如何在模板中使用这些自定义API来调用TestComp组件。
摘要由CSDN通过智能技术生成

在用 elementUI、antdUI 等 ui 框架的时候,都会用到 Message 全局的提示方法,而平时常用的 Vue 组件都是写成 tag 来使用,而 Message 等组件的使用方式则不同,不用引入 Message 的 vue 组件,用 js 就能

接下来将上面组件改写成用 js 调用的方式:

在改写之前,还需要了解 vue3 的几个全局 API:

  • defineComponent: 将函数或者对象转换成对象返回
  • h: 将组件对象转换成 vnode
  • render:将 vnode 挂载到节点或者移除节点

另建一个 ts / js 文件,然后将 TestComp 组件进行转换:

首先实现一个 vnode 挂载节点函数和一个移除节点函数:

import { defineComponent, h, render } from 'vue'

// 生成一个唯一的key
const COMPONENT_CONTAINER_SYMBOL = Symbol('component_container')

/**
 * 创建组件实例对象
 * 返回的实例和调用 getCurrentComponent() 返回的一致
 * @param {*} Component
 */
function createComponent(Component: any, props: any, children: any) {
  // 创建vnode
  const vnode = h(Component, { ...props }, children)
  // 创建组件容器
  const container = document.createElement('div')
  // @ts-ignore 将组件容器挂载到vnode上,方便后续移除
  vnode[COMPONENT_CONTAINER_SYMBOL] = container
  // 将vnode渲染到组件容器内, 在 vue2 的版本中,父级元素是可以传 null 的,但是 vue3 不支持
  render(vnode, container)
  // 返回组件实例
  return vnode.component
}

/**
 * 销毁组件实例对象
 * @param {*} ComponnetInstance 通过createComponent方法得到的组件实例对象
 */
export function unmountComponent(ComponnetInstance: any) {
  // 移除组件节点,render函数的第一个传null,表示为移除动作,会执行unmount方法
  render(null, ComponnetInstance.vnode[COMPONENT_CONTAINER_SYMBOL])
}

引入组件进行挂载节点

import TestComp from './testComp.vue'

// ......
// ......

// 当前场景下是可以省略这一步转换,但是,就类型而言,defineComponent 返回的值有一个合成类型的构造函数
const componentConstructor = defineComponent(TestComp)

// 创建一个变量接收创建的组件实例
let instance: any;

// 创建节点
const showTestComponent = (options: any) => {
  // 创建组件实例对象
  instance = createComponent(componentConstructor, options, null)
  // 添加到body
  document.body.appendChild(instance.vnode.el)
}

// options为组件的props
export const testComp = function (options: any) {
  const close = options.onClose
  // 重新封装close,添加移除元素操作
  options.onClose = () => {
    close && close.call()
    unmountComponent(instance)
  }
  showTestComponent(options)
}

最后在父组件调用

<template>
  <div>js 调用 vue 组件</div>
  <button @click="show">调用测试组件</button>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { testComp } from '../components/testComp'

export default defineComponent({
  setup() {
    const show = () => {
      testComp({
        title: '这是传进来的title',
        onClose() {
          console.log('close')
        }
      })
    }

    return {
      show
    }
  },
})
</script>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值