六. 神奇的 h 函数
目前我们的 dialog
已经可以出现到我们的页面了,但是现在它的内容都是写死的,不灵活,我们需要按照不同的场景传递不同的文字该如何实现呢?这里又需要请出我们的老朋友,h
函数。
h
函数是可以接收第二个参数的,并且第二个参数的值将被转换成 props 传递给我们的组件。
让我们回到 dialogCreator.ts
文件。我们声明一个类型,准备作为 DialogCreator
内部 constructor
参数的类型。这里我先抛出概念,等等我们一步一步验证。
并且声明两个类的属性 title
和 content
来准备做为 props
传递给我们的 Dialog.vue
组件。
我们现在还缺少一个关键的东西,就是取消按钮和确定按钮的函数,我们一并声明。(这里需要注意,一般取消按钮就是关闭 dialog 对话框的功能,也就是类本身的 dismiss 方法,所以我们不需要用户额外提供取按钮的函数,只需要提供确定时的回调函数即可。)
这里需要读者仔细品味上图代码的含义。
接下来我们就需要传递 this.option
给 h
函数即可。
报错了没关系,是因为我们还没有在 Dialog.vue
组件内部定义 Props
。
让我们分别从 dialogCreator.ts
文件导出这个 DialogPropsType
类型,再从 Dialog.vue
引入这个类型用来定义 props 即可。
随即可以看到我们刚刚到报错消失了,说明我们的思路是没问题的。
七. 改造 Dialog.vue 组件
我们先将之前固定写死的,title
部分和 content
部分替换成我们声明的 props 里的 title
和
然后别忘了我们 props
还存放着《确定》和《取消》的的方法。取出来分别放置在这两个按钮身上。
随便找一个其它页面,测试刚刚的 DialogCreator
类,内容我就随便自己写了
我们测试一下:
八. 遮罩的关闭效果
现在我们点击遮罩是没办法关闭 dialog 的,效果如下:
造成这种情况的原因也很简单,因为我们的遮罩没有点击事件,怎么办呢?非常非常简单,给遮罩添加取消 cancelBtn
,也就是 dismiss 方法不就可以了吗?
测试一下,现在点击遮罩已经可以正常关闭 dialog 了。
九. 修复冒泡造成的 Bug
目前看起来功能已经很棒了,但是目前的代码会造成一个严重的 bug
,我们在点击 dialog
本身的时候,由于事件冒泡,会错误的触发遮罩层的方法。
我们验证一下,我们随便编写一个函数,然后绑定到 dialog
组件上。
注意:这里的 dialog
指的是中间的那个实实在在的对话框本身,不是指整个组件。
然后给 cancelBtn
也加一行 console.log
测试一下。
效果如下:
解决方法简单的出乎你的意料,让我们回到中间的 diaolog
身上,仅仅只需要绑定一个空的 click
函数,然后加上修饰符 stop
即可。
效果如下,可以看到,现在点击 dialog
已经不会错误的关闭整个 对话框了。
- 至此我们的
dialog
组件已经可以在绝大部分场景下使用了。🎁~
总结
目前的代码只是一个很粗糙的实现,更加具体实用的功能还需读者根据自己项目的需求自行完成。下面是 DialogCreator.ts
文件的代码。读者可根据需要自行查阅。
import Dialog from "./Dialog.vue"; import { h, render } from "vue"; interface DialogType { title: string; content: string; confirmBtn: () => void; } export interface DialogPropsType extends DialogType { closeBtn: () => void; } export class DialogCreator { containerEl: HTMLDivElement; option: DialogPropsType; constructor(option: DialogType) { this.containerEl = document.createElement("div"); this.option = { ...option, closeBtn: this.disMiss.bind(this) }; } present() { const vnode = h(Dialog, this.option); render(vnode, this.containerEl); document.body.insertBefore(this.containerEl, document.body.firstChild); } disMiss() { render(null, this.containerEl); document.body.removeChild(this.containerEl); } //dialog 消失的方法 }