封面图
中午在公司楼顶平台上晒太阳,不知不觉睡着了
背景
上次开发了一个类似popConfirm的二次确认弹框,如下面两个图:
- 图一
- 图二
完成开发后,准备集成到项目中时忽然发现无法集成到公司内部的组件库中,因为公司的组件库
表格的操作项按钮是通过传参的方式进行配置
,无法直接使用popConfirm包裹操作按钮的方式进行Dom的书写。
所以又对二次弹框进行了一次简单的开发,采用modal的方式进行开发。好处是除了可以以之前的方式,直接在组件上传入props使用,如:
<HConfirmModal
title="测试标题"
modalType="TextConfirm"
paperWork="hello-word"
:width="300"
v-model:visible="visible">
</HConfirmModal>
也可以采用注册的方式,注册组件后,调用组件的api进行使用,如:
<HConfirmModal @register="register" @ok="testOK" ></HConfirmModal>
const [register, { openConfirmModal: openModifyModal,setConfirmModalProps}] = useConfirmModal()
function handleShow() {
setConfirmModalProps({
title:'测试标题',
modalType:'TimeConfirm',
desc:'注意危险'
})
openModifyModal(true)
}
这样就可以比较方便的集成到现有的组件库中,也不需要改动现有组件库中的table相关的代码,相对来说效果也稍微好一些。
开发前想法
最早的实操方案打算借助于
antd
中的modal组件,对modal组件重新进行封装,但是发现:当我在modal组件中写入相应的dom结构后,如图:
- 图一
- 图二
modal组件中写入表单相关的dom后,需要我点击确认按钮时,对表单进行校验,这时候就需要能够直接获取Modal组件中的click事件。
那么,如何获取这个事件呢?
最开始的时候,也没想到很好的方法,后来想是否可以用ref来获取Modal的实例,然后调用这个实例上注册的事件呢?
也许可以,但是这样操作起来似乎有点舍近求远,毕竟除了表单校验的逻辑还有一个倒计时的罗需要进行判断,写起来似乎有些麻烦。
所以最终还是觉得借鉴Modal的样式,重新开发一个比较好,写起来比较舒服,效率也会高一点。
两种调用方式的实现思路
第一,使用props进行控制。这种组件实现起来比较简单,定义好组件需要的属性作为props,传递给组件,组件按照不同的属性进行渲染,点击时触发不同的
emit
事件即可。
其流程为:
props和emit事件
--->
渲染组件
--->
触发emit事件
。
这种方式实现起来比较简单,但是场景稍微有些局限,如:组件的行为,如
显示、隐藏
必须在外部定义,需要外部书写相应的函数进行控制。
第二种方式,定义组件内部的方法,组件的行为通过组件本身的方法进行控制,同时将组件自身的方式通过hooks的方式暴露给外部。
其流程为:
props和emit事件
--->
组件定义自身需要的函数,同时将传入的props属性转化为内部属性
--->
组件的行为根据自身的属性和方法进行控制
--->
将组件本身的方法以hooks的形式暴露出来
。
这样一来,组件即可以以传统props的方式使用,也可以通过hooks的注册方法及组件本身的其他方法进行控制,使用的场景相对来说更广泛一些。
核心方法
传统的组件开发方式这里就不做过多的解释了,主要讲一下第二种方式的实现方式。
使用第二种方式开发组件的关键点有两处:
第一, 如何将外部传入的props转化为组件内部的属性 ?
第二,如何才能够获取到组件自身所定义的方法 ?
将外部传入的props转为组件内部属性其实很简单,我们只需要使用
computed
方式将转化一下即可,如:
const getMergeProps = computed((): Recordable => {
return {
...props,
...(unref(propsRef) as any)
}
})
这样我们就可以使用组件内部的属性
getMergeProps
对组件的dom进行渲染,实现不同的属性展示不同的内容。
那么,如何才能获取组件内部的方法呢?其实也很简单,这里需要用到一个
vue
提供的一个方法:
getCurrentInstance
。
getCurrentInstance
可以获取到当前组件的实例,既然可以获取到当前的实例,那么比必然可以操作实例上的方法。
然后,我们在组件实例化的时候触发一个注册函数
register
,将组件内部需要对外暴露的方法传给
register
方法,然后在对应的hooks中可以扩展实例的方法,这样我们就可以实现使用hooks的方式,注册、然后控制组件的各种行为。
这个触发的代码也很简单:
const instance = getCurrentInstance()
if (instance) {
emit('register', modalMethods, instance.uid)
}
最后,我们在hooks函数中可以获取组件的实例,拿到组件实例对象后,我们就可以为所欲为了。