Vue3 优雅的模态框封装方案 - 实践

my-blog:https://tuimao233.gitee.io/ma...

Vue3 优雅的模态框封装方法 - 初探

Vue3 优雅的模态框封装方法 - 实践

通过前篇文章的介绍,大家已经了解了虚拟节点和瞬移组件,接下来我们利用虚拟节点与瞬移组件,封装一个模态框组件。

首先,得先明确我们目标,就是我们想要做出来的效果,就是兼容两个方式调用的模态框组件

第一种通过 template 直接使用:

  
    我是模态框文字
  

第二种是直接 JavaScript 调起:

Modal({title: '标题', content: '我是模态框文字'})
    .then(()=> {
    })
    .catch(()=> {
    })

从这两段方式可以看出,无论是通过 Modal,还是通过..,可传入参数都保持一致,由此可见,组件调用方式传参一致,所以我们首先新建components/Modal/props.ts,在外部定义 props 参数类型:

/** 模态框固定 props 参数, 用于调用模态框成功|关闭|销毁 */
export const modalProps = {
  // 是否展示组件
  modelValue: Boolean,
  // 组件消失时(移除实例)
  vanish: Function,
  // 组件调用成功事件
  resolve: Function,
  // 组件调用失败事件
  reject: Function
}

/** 组件内传入 props 参数, 用于模态框自定义功能 */
export const componentProps = {
  // 模态框标题
  title: String,
  // 模态框内容
  content: String
}

/** 组件内所有 Props 参数, 合并参数 */
export const props = {...modalProps, ...componentProps}

这一步完成之后,我们在创建components/Modal/index.vue,导入 props 类型:



到这一步后,我们在定义一个通过js代码渲染组件的方法:

// components/Modal/utils.vue
import { Component, h, render } from "vue"

/**
 * 渲染组件实例
 * @param Constructor 组件
 * @param props 组件参数
 * @returns 组件实例
 */
export const renderInstance = (Constructor: Component, props: Record) => {
  // 创建组件容器, 这一步是必须的, 在销毁组件时会使用到
  const container = document.createElement('div')

  // 在 props 添加组件消失钩子, 移除当前实例, 将销毁方法提供给组件
  // 这里不需要调用 document.body.removeChild(container.firstElementChild)
  // 因为调用 render(null, container) 为我们完成了这项工作
  props.vanish = () => {
    render(null, container)
  }

  // 创建虚拟节点, 渲染组件
  const vnode = h(Constructor, props)
  render(vnode, container)

  // 添加子元素(组件)至父元素
  document.body.appendChild(container.firstElementChild)
}

渲染方法定义完成后,我们就可以先把通过 js 调起的方法给做了:

import { ExtractPropTypes, ref } from "vue"
import Index from './index.vue'
import { componentProps } from './props'
import { renderInstance } from "./utils"

/** 组件 Props 类型, ExtractPropTypes 可将 Constructor 转换为对应值类型 */
type Props = ExtractPropTypes

/** 组件调用 resolve 返回结果 */
type Result = { path: string }[]

/**
 * 模态框调用方法
 * @param props 
 * @returns {Promise}
 */
export const Modal = (props: Props) => {
  return new Promise((resolve, reject) => {
    renderInstance(Index, {
      // 这里 modelValue, 为了使组件可修改, 需要传入 ref
      // 注意这块地方,我们将这个值设置为 true 为了调起即直接展示组件
      modelValue: ref(true),
      ...props, resolve, reject
    })
  })
}

这里需要注意的是,通过 h 函数创建的实例,其 props 在组件中,无法通过 emit 修改,修改会失效,所以为了解决这个问题,需要在调起方法传入 modelValue Ref

接下来我们进行完善components/Modal/index.vue组件的模态框逻辑:



到了这里,我们可以测试一下组件调用是否正常,例如,我们通过使用 template 组件方式调用:



image.png
image.png

在测试一下,通过 JavaScript 调用模态框:



image.png
image.png

到这里,整个模态框的基本逻辑都组成了,在这基础下,就可基于需求下完善模态框与定制内容,也可通过该方法,二次封装 el-dialog 组件,只需要将 components/Modal/index.vue 的逻辑修改一下即可,下一篇文章,我们在这基础下在进行完善,使得组件能完全胜任业务需求。

你可能感兴趣的:(前端vue.jsvue3)