首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

极致舒适的 Vue 弹窗使用方案

作者:youth君

一个让你体验极致舒适的使用方式!

image.pngDialog地狱

为啥是地狱?

因为凡是有出现的页面,其代码绝对优雅不起来!因为一旦你在也个组件中引入,就最少需要额外维护一个变量。如果只是额外维护一个变量这也不是不能接受,可是当同样的组件,即需要在父组件控制它的展示与隐藏,又需要在子组件中控制。

为了演示我们先实现一个组件,代码来自ElementPlus的Dialog示例

演示场景

就像下面这样:

Kapture 2023-07-07 at 22.44.55.gif

示例代码如下:

这里的会被父组件和两个组件都会触发,如果父组件并不关心子组件的事件,那么这里的在父组件里唯一的作用就是处理的展示!!!这样真的好吗?不好!

来分析一下,到底哪里不好!

本来是动作的后续动作,所以理论上应该将写在组件中。但是这里为了管理方便,将挂在父组件上,子组件通过事件来控制。

再者,这里的和函数除了处理外,对于父组件完全没有意义却写在父组件里。

如果这里的多的情况下,简直就是地狱啊!

理想的父组件代码应该是这样:

在函数中处理弹窗的相关逻辑才更合理。

解决之道

朕观之,是书之文或不雅,致使人之心有所厌,何得无妙方可解决?

依史记之辞曰:“天下苦久矣,苦楚深深,望有解脱之道。”于是,诸位贤哲纷纷举起讨伐之旌旗,终“”逐渐突破困境之境地。

image.png

没错现在网上对于的困境,给出的解决方案基本上就“”看起来比较优雅!这里给出几个网上现有的实现。

命令式一

codeimg-facebook-shared-image (5).png

吐槽一下~,这种是能在函数中处理弹窗逻辑,但是缺点是组件与是两个文件,增加了维护的成本。

命令式二

基于第一种实现的问题,不就是想让和文件合体吗?于是诸位贤者想到了。于是进一步的实现是这样:

codeimg-facebook-shared-image (7).png

嗯,这下完美了!

doutub_img.png

完美?还是要吐槽一下~

如果我的系统中有很多弹窗,难道要给每个弹窗都写成这样吗?

这种兼容的方式,需要引入支持的依赖!

如果工程中不想即用又用呢?

如果已经存在使用的弹窗了,难道推翻重写吗?

...

思考

首先承认一点命令式的封装的确可以解决问题,但是现在的封装都存一定的槽点。

如果有一种方式,即保持原来对话框的编写方式不变,又不需要关心和的问题,还保存了命令式封装的特点。这样是不是就完美了?

那真的可以同时做到这些吗?

doutub_img (2).png

如果存在一个这样的Hook可以将状态驱动的Dialog,转换为命令式的Dialog吗,那不就行了?

它来了:useCommandComponent

image.png

父组件这样写:

组件这样写:

对于无需任何改变,保持原来的样子就可以了!

真的做到了,即保持原来组件的编写方式,又可以实现命令式调用

使用效果:

Kapture 2023-07-07 at 23.44.25.gif

是不是感受到了莫名的舒适?

不过别急,要想体验这种极致的舒适,你的还需要遵循两个约定!

两个约定

如果想要极致舒适的使用,那么弹窗组件的编写就需要遵循一些约定(_其实这些约定应该是弹窗组件的最佳实践_)。

约定如下:

弹窗组件的需要有一个名为的属性,用于驱动弹窗的打开和关闭。

弹窗组件需要一个事件,用于弹窗关闭时处理命令式弹窗。

如果你的弹窗组件满足上面两个约定,那么就可以通过极致舒适的使用了!!

这两项约定虽然不是强制的,但是这确实是最佳实践!不信你去翻所有的UI框看看他们的实现。我一直认为学习和生产中多学习优秀框架的实现思路很重要!

如果不遵循约定

这时候有的同学可能会说:哎嘿,我就不遵循这两项约定呢?我的弹窗就是要标新立异的不用属性来控制打开和关闭,我起名为呢?我的弹窗就是没有事件呢?我的事件是具有业务意义的、呢?...

doutub_img.png

得得得,如果真的没有遵循上面的两个约定,依然可以舒适的使用,只不过在我看来没那么极致舒适!虽然不是极致舒适,但也要比其他方案舒适的多!

如果你的弹窗真的没有遵循“两个约定”,那么你可以试试这样做:

如上,只需要在调用函数时在中将驱动弹窗的状态设置为,在需要关闭弹窗的事件中调用即可!

这样是不是看着虽然没有上面的极致舒适,但是也还是挺舒适的?

源码与实现

实现思路

对于的实现思路,依然是命令式封装。相比于上面的那两个实现方式,是将组件作为参数传入,这样保持组件的编写习惯不变。并且遵循单一职责原则,只做好组件的挂载和卸载工作,提供足够的兼容性

其实有点像中的高阶组件的概念

源码

源码不长,也很好理解!在实现的时候参考了ElementPlus的MessageBox。

源码如下:

除了命令式的封装外,我加入了。这样做的目的是,传入的组件在这里其实已经独立于应用的Vue上下文了。为了让组件依然保持和调用方相同的Vue上下文,我这里加入了获取上下文的操作!

基于这个情况,在使用时需要保证它在中被调用,而不是在某个点击事件的处理函数中哦~

源码补丁

非常感谢@bluryar关于命令式组件无法获取当前组件树的 injection 的指出!!

image.png

趁着热乎,我想到一个解决获取当前injection的解决办法。那就是将当前组件树的与合并,这样传入的弹窗组件就可以顺利的获取到和当前组件树的了!

image.png最后

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OmwoKMdmXKRR07lVP9Atvodw0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券