当前位置: 首页 > 科技观察

精通React-Vue系列,带你实现强大的通知提醒框(Notification)

时间:2023-03-20 23:34:39 科技观察

前言本文是作者撰写的关于组件设计的第十篇文章。今天,就带大家实现一个特殊的组件——Notification提醒框(Notification)。该组件也出现在Antd或elementUI等第三方组件库中,主要用于为用户提供系统通知信息。我们在调用的时候,并不像其他组件那样通过引入组件标签来调用。比如Modal组件,我们通常这样称呼:

我是弹窗内容window

我是弹窗Window内容

我是弹窗内容

我是弹窗内容

但通知框(Notification)大部分场景使用jsAPI调用方式:notification.open({message:'趣谈前端React',description:'学前端,学React/vue/Node,快加入我们'});我们看到的组件效果可能是这样的:那么我们如何实现这样的调用方法呢?别着急,笔者会一步步教你如何实现。我们先整理一下以下组件的分类:通用组件:如Button、Icon等;布局类组件:如Grid、Layout布局等;导航类组件:如面包屑Breadcrumb、下拉菜单Dropdown、menu等;数据录入类组件:如form表单、Switch开关、Upload文件上传等;数据展示组件:如Avator头像、Table表格、List列表等;反馈组件:如Progressbar、Drawer抽屉、Modal对话框等;其他业务类型。熟悉上述分类法是设计任何组件系统的先决条件。无论你是前端团队的UI库从零到一个开发,还是基于已有的组件库重新开发业务组件,以上分类法同样适用。本文将使用React来开发这个组件,同时也会使用一些Javascript中常用的设计模式,比如单例模式,但是不管你用什么框架来实现,原理都是通用的。如果有兴趣,可以使用vue也实现如下。正文在开始组件设计之前,希望大家有一定的css3和js基础,了解基本的react/vue语法。我们先来解构Notification组件。一个Notification分为以下几个部分:每个block都可以自定义配置,也可以组合其他组件。而我们可以配置提醒框出现的位置,就像antd的组件一样,我们有左上、左下、右上、右下的位置可以配置,或者根据这些位置的偏移量。而我们都知道antd或者element等组件库都会有一些主题状态来提高用户的使用效率,比如success(成功状态)、warning(警告状态)、error(错误状态)、info(通知状态)等,那么我们自己实现的组件也应该具备这些功能。下面是笔者使用React实现的Notification组件的效果:下面我们来看看通知提醒框(Notification)的具体设计思路。一、Notification组件的设计思路根据笔者之前总结的组件设计原则,我们第一步就是确认需求。通知提醒框(Notification)组件一般有以下需求:可以控制Notification自动关闭的时间,配置Notification渲染节点,可以控制Notification的弹出位置。您可以自定义关闭图标。您可以手动选择通知窗口类型。您可以自定义通知框的偏移量。您可以设置通知框的信息和提示文字。您可以自定义通知框的图标,并在单击通知框时提供。回调函数通知框关闭时,可以提供回调函数,手动销毁通知框。收集完需求后,作为一个有追求的程序员,你会得到如下的线框图:其实通知框里面要考虑的东西很多,所以在设计组件之前,一定要明确需求和功能划分,这样才能我们可以有条不紊地去实现它,就像实现一个复杂的系统一样,一个组件就是一个小系统。2、基于react实现一个通知提醒框(Notification)。通知框的API调用实现思路其实就是通过jsx动态渲染约定的标签,然后通过ReactDom的RenderAPI将dom渲染到指定的容器中挂载到页面上。如果要实现Notification.info,还需要考虑创建实例的问题。我们应该使用单例模式来控制创建实例的数量。伪代码如下:constxNotification=(function(){letnotification=null;if(notification){return{render(dom){},config(config){},info(config){},error(config){}//...}}else{notification=newNotification({})return{render(dom){},config(config){},info(config){},error(config){}//...}}})()//使用xNotification.info({...})xNotification.error({...})但是要真正实现上面需求中讨论的通知框的功能,在其实我们还是要写很多代码来处理不同的情况,所以为了方便大家理解,我们使用第三方库ReactNotification来帮我们处理基本的逻辑。基于它,作者将实现我们上面讨论的功能。2.1构建通知框(Notification)的基本骨架首先根据笔者的代码风格,大致考虑组件设计的框架,然后一步步填充内容和逻辑。通过这种递进的设计思路,可以让我们的逻辑更加严谨和清晰。具体代码如下:importNotificationfrom'rc-notification'import'./index.less'constxNotification=(function(){letnotification=null/***通知类型弹窗*@param{config}对象通知框配置属性*@param{type}string通知窗口类型*@param{btn}ReactNode自定义关闭按钮*@param{bottom}number当消息从底部弹出时,距离底部的距离,单位像素*@param{className}string自定义CSS类*@param{description}string|ReactNode通知提醒内容,必填*@param{duration}number默认4.5秒后自动关闭,如果设置为null,不会自动关闭*@param{getContainer}HTMLNode配置渲染节点输出位置*@param{icon}ReactNode自定义图标*@param{key}string当前通知的唯一符号*@param{message}string|ReactNode通知提醒标题,必填*@param{onClose}func当默认关闭按钮被点击时触发的回调函数*@param{onClick}func通知被点击时触发的回调函数*@param{top}number当消息从顶部弹出时,距离顶部的距离,以像素为单位*@param{closeIcon}ReactNode自定义关闭图标*/constpop=(config)=>{const{type,bottom,className,description,duration=4.5,getContainer=()=>document.body,icon,key,message,onClose,onClick,top,closable=true,closeIcon}=confignotification.notice({内容:
{消息}
{description}
})}/***Notification提示组件,全局参数*@param{bottom}来自消息的号码bottom弹出时,距离底部的位置,单位像素,默认24*@param{duration}number默认自动关闭延迟,单位秒*@param{getContainer}HTMLNode配置渲染节点的输出位置,默认todocument.body*@param{placement}字符串弹出位置,可选topLefttopRightbottomLeftbottomRight*@param{top}number消息从顶部弹出时距离顶部的距离,单位为像素*@param{closeIcon}HTMLNode自定义关闭图标*/constconfig=(config)=>{const{duration,getContainer,placement,closeIcon}=configNotification.newInstance({getContainer:getContainer,duration:duration||4.5,closeIcon},(notice)=>notification=notice)}if(notification){return{config,pop}}//如果不创建实例,创建默认实例Notification.newInstance({},(notice)=>notification=notice)return{config,pop}})()exportdefaultxNotification首先,我们根据需求列出一个item的属性。我们全局使用的配置方式是xNotification.config(config)。在通知框实例中,我们使用xNotification.pop(config)。这与antd的使用方式有点不同。作者将通知框类型放在popconfig中进行处理。例如,要渲染一个成功的通知框,我们可以这样做:xNotification.pop({type:'success'})antd将以相同的方式调用://antdNotification.info({//...})笔者之所以会这样做,是因为info、success、warning的状态其实在dom结构中是可以复用的,所以通过配置的方式可以大大减少冗余代码。2.2实现通知框类型type和自定义图标笔者在构建组件框架时已经完成了部分属性的配置,这里不再一一介绍。笔者将介绍一些比较重要的方法的实现。通过观察我们可以知道,如果我们要实现不同的通知框类型,只需要根据类型动态更换图标即可。图标部分使用了作者自己实现的Icon组件。具体用法类似于antd的Icon组件。如果想学习如何封装自己的Icon组件,可以参考作者的源码。首先我们定义一个type和一个icon的映射关系:consticonType={success:'FaRegCheckCircle',warning:'FaRegMeh',info:'FaRegLightbulb',error:'FaRegTimesCircle'}这四种类型分别对应不同的icon图标type,那么我们就可以根据用户传入的type显示不同的icon图标:但是,我们还需要考虑的一点是,如果用户传入自定义图标,理论上应该显示自定义图标,所以type应该和icon的两个属性相关。另一种情况是,如果用户没有配置type和是否传入icon,那么实际上是不需要展示icon的。综合考虑,我们的代码如下:{(icon||['info','success','error','warning'].indexOf(type)>-1)&&{图标?icon:}实现效果如下图所示:2.3通知框放置的位置通知框的位置要根据全局配置针对业务场景,所以我们在config方法中设置,如何根据用户传入的位置信息来控制Notification显示的位置,我们也可以先定义一个枚举类:constadapterPos={topLeft:{top:'24px',left:'24px'},topRight:{top:'24px',right:'24px'},bottomLeft:{bottom:'24px',left:'24px'},bottomRight:{bottom:'24px',right:'24px'}}从上面的代码可以看出我们会定义四个基本位置,默认的offset都是24px,然后我们就可以根据传过来的placement来匹配我们的位置信息in:Notification.newInstance({style:{...adapterPos[placement]},//...上面的代码可以知道位置信息我们通过s来设置风格。具体效果如下:2.4实现通知框的动画效果Animation我们实现一个类似antd的从右到左进入的动画。让我们重写样式如下:.rc-notification-fade-enter{animation:moveLeft.3s;}。rc-notification-fade-leave{动画:moveOutLeft.3s;}.rc-notification-fade-enter.rc-notification-fade-enter-active{动画:moveLeft.3s;}.rc-notification-fade-leave。rc-notification-fade-leave-active{animation-name:moveOutLeft.3s;}@keyframesmoveOutLeft{0%{}100%{right:-200%;}}@keyframesmoveLeft{0%{右:-200%;}100%{右:0;}}通过以上步骤,一个功能强大的通知提醒框(Notification)就完成了。Notification组件是组件库中一个比较复杂的组件。有不懂的可以在评论区提问。我看到会第一时间回复。2.5使用Notification组件我们可以这样使用:{xNotification.pop({type:'成功',message:'有趣的前端学习标志-in',description:'前端基础,中级进阶,进阶签到,一起玩前端,996离你远'})}}>点我显示通知配置全局属性:import{xNotification}来自'@alex_xu/xui'xNotification。config({placement:'topRight'})作者已经将实现的组件发布到npm。有兴趣的可以直接用npm安装使用。方法如下;pmi@alex_xu/xui//importxuiimport{Button,Skeleton,Empty,Progress,Tag,Switch,Drawer,Badge,Alert}from'@alex_xu/xui'这个组件库支持按需导入,我们只需要配置项目中的babel-plugin-import,具体配置如下:/.babelrc"plugins":[["import",{"libraryName":"@alex_xu/xui","style":true}]]npm库截图如下: