关于弹窗:如何打造实时性的弹窗

1. 前言在 App 的经营流动中,对用户进行弹窗提醒,是一种常见的经营形式。例如:用户曾经下单但未付款的时候,能够给用户一个优惠券的弹窗提醒。 神策 Android 弹窗 SDK[1] 次要针对的就是上述经营场景,经营人员能够在神策智能经营中配置弹窗的 UI 以及触发弹窗的一些条件,当用户满足配置的条件时,集成了弹窗 SDK 的 App 会展现弹窗。UI 成果如图 1-1 所示: 图 1-1 弹窗 UI 效果图 2. 弹窗的实时性在很多场景下,弹窗须要很高的实时性。如果弹窗的计算规定通过后端解决,符合条件时再下发给客户端,实时性将得不到保障。 为了解决这一问题,把计算逻辑等放在了客户端。简略来说,就是触发埋点事件之后会判断是否触发弹窗。 此外,弹窗 SDK 为了保障实时性,也做了很多工作,上面就逐个为大家进行介绍。 3. 计划演进3.1. 计划一:共用埋点数据采集线程触发弹窗的机会,取决于经营同学在神策智能经营中的配置,那弹窗 SDK 如何来决定是否弹窗呢? 举个例子,经营同学的配置条件是:有商品页面的浏览数据就弹窗。因而,在 App 端监控到有商品页面浏览的埋点数据产生就会弹窗。 埋点数据采集工作是在埋点数据采集线程中执行的。因而,最后的想法是在埋点数据采集线程中监控埋点数据,如果有合乎弹窗条件的数据,那么就展现弹窗。示例代码如下: //判断是否弹窗PlanManager.ensureShowDialog(data);//数据缓存到数据库enqueueEventMessage(data);这种做法很简略,也能满足需要。它的长处如下: 从代码上来看,逻辑比拟清晰;判断是否弹窗和埋点数据采集都是在一个线程,不便保护。然而,它的毛病也很显著: 如果在判断是否弹窗这一步,有阻塞或者异样,那么会影响埋点数据缓存到数据库;耦合度十分高。当初是弹窗的业务须要监控数据,如果未来其余业务也须要监控数据,那么在埋点数据缓存之前,还须要减少更多的业务逻辑。为了解决上述问题,咱们拆分了埋点数据采集线程和弹窗判断线程。 3.2. 计划二:拆分埋点数据采集线程和弹窗判断线程思考到共用埋点数据采集线程的毛病,咱们做了线程的拆分,如图 3-1 所示:图 3-1 线程拆分示意图 此时,埋点数据采集线程和弹窗判断线程,是两个独立的线程。当埋点数据采集线程有新的数据时,会被动告诉弹窗判断线程,让其解决弹窗业务。 这样做不仅升高了耦合度,并且弹窗业务不会影响到埋点数据采集。即便最极其的状况,比方弹窗判断线程因为某些起因呈现了异样,埋点数据采集线程依然能失常工作。 埋点数据采集线程只须要依据接口,回调给数据接收端就行,示例代码如下: // 监控数据,并传给注册接口的中央DataMonitorInterface.trackEvent(data);// 数据缓存到数据库mMessages.enqueueEventMessage(eventType.getEventType(), dataObj);在弹窗判断线程中,收到数据后会缓存在队列,示例代码如下: public class SFDataMonitorImpl{ public void trackEvent(String data){ mSFPlanTaskManager.addTriggerTask(new Runnable() { //判断是否弹窗 PlanManager.ensureShowDialog(data) } }}在新的线程中去执行此队列的工作,示例代码如下: public class SFPlanTriggerRunnable implements Runnable { @Override public void run() { Runnable downloadTask = mSFPlanTaskManager.getTriggerTask(); mPool.execute(downloadTask); }}这种计划看上去曾经很完满了,升高了埋点数据缓存和弹窗业务之间的耦合,并且代码上也做了拆分,相互之间的影响很小,同时也能满足各种业务场景。 ...

November 2, 2021 · 1 min · jiezi

使用React手写一个对话框或模态框

打算用React写对话框已经很长一段时间,现在是时候兑现承诺了。实际上,写起来相当简单。 核心在于使用React的接口React.createPortal(element, domContainer)。该接口将element渲染后的DOM节点嵌入domContainer(通常是document.body),并保证只嵌入一次。 欢迎订阅我的博客。所以,我们可以这样写一个对话框或模态框: function Dialog() { return React.createPortal( <div>Dialog contents</div>, document.body )}一个新的div会出现在body内部: 一个完整DEMO: 点击运行DEMO class Modal extends React.Component { render() { const { visible, onClose } = this.props return visible && ReactDOM.createPortal(<StyledModalRoot> <div className="box"> Content <br/> <button onClick={onClose}>Close</button> </div> </StyledModalRoot>, document.body) }}class App extends React.Component { state = { visibleModal: false } showModal = () => this.setState( { visibleModal: true } ) handleCloseModal = () => this.setState( { visibleModal: false } ) render() { const { visibleModal } = this.state return <div style={{padding: '20px'}}> <button onClick={ this.showModal }>Show Modal</button> <Modal visible={visibleModal} onClose={ this.handleCloseModal } /> </div> }}const StyledModalRoot = styled.div` position: fixed; z-index: 1001; left: 0; top: 0; display: grid; place-items: center; width: 100%; height: 100%; background: rgba( 0, 0, 0, 0.2 ); >.box { position: relative; display: grid; place-items: center; width: 80%; height: 80%; background: white; border-radius: 10px; box-shadow: 0px 3px 5px -1px rgba(0,0,0,0.2), 0px 5px 8px 0px rgba(0,0,0,0.14), 0px 1px 14px 0px rgba(0,0,0,0.12); }`感谢你花时间阅读这篇文章。如果你喜欢这篇文章,欢迎点赞、收藏和分享,让更多的人看到这篇文章,这也是对我最大的鼓励和支持! 欢迎在Star和订阅我的原创前端技术博客。 ...

April 24, 2019 · 1 min · jiezi

chrome弹窗在双屏情况下left居中定位异常分析

背景使用 window.open 进行弹窗显示,实现微信二维码弹窗功能在双屏情况下,chrome浏览器位于副屏弹窗时,会存在弹窗位置异常问题。目前网上相关解析及解决方案几乎没有,故写此文章以作分享。文章重点双屏情况下,chrome浏览器弹窗位置问题多屏幕时,chrome浏览器位于非主屏进行弹窗显示时,设置弹窗的left,top将会异常本文将分析其显示异常的原因,并给出解决方案解决该问题的分析过程这是本文分享的另一个重点除了解决方案,希望能通过本文和大家分享笔者解决该问题时的思路和方法。这些方法可能不是最优的,但希望能给大家带来一点触动或者启示。在解决到其他问题的时候也用得上。window.open的第三个参数及其兼容性介绍window.open方法相信大家都不会陌生,通常用于传递一个地址参数,新建一个浏览器tab页面。但除了第一个地址参数,window.open还另外接收两个参数,分别是「strWindowName(新窗口的名称)」,「strWindowFeatures(新窗口特性)」这强调的是第三个参数,当设置了第三个参数后,新开的弹窗将会在原页面的基础上,已非tab页面的形式进行显示,有以下几个特点在原页面上进行弹窗显示,而不是新起浏览器tab页面进行跳转。其显示方式类似alert弹窗,属于原页面的一个功能模块,而不是跳转至新页面。非tab页面,这意味着它不像其他tab页面那样可以放在浏览器tab栏中,它是折叠不进去了,是以弹窗的形式呈现。第三个参数「strWindowFeatures」可以设置新窗口特性,例如宽度,高度,距顶,距左,是否显示滚动条等等。本文不做详细介绍,参数详情可以参考这篇文章需要注意的是,strWindowFeatures里的特效并不是每个浏览器都支持的,不同于「dom」,这属于「bom(borwser Object Model)」的内容。具体兼容性这里也不讲了,网上也有相关文章chrome的兼容性与坑(重点一)异常的显示即使看完上面的兼容性文章,当你使用chrome浏览器,位于非主屏进行弹窗时,依然会存在位置设置异常的问题。实现居中显示弹窗,一般代码会这样写const windowWidth = window.screen.width // 屏幕宽度const windowHeight = window.screen.height // 屏幕高度const pageWidth = 600 // 弹出窗口的宽度const pageHeight = 550 // 弹出窗口的高度let pageTop = (windowHeight - pageHeight) / 2 // 窗口的垂直位置let pageLeft = (windowWidth - pageWidth) / 2 // 窗口的水平位置;window.open(‘xxx’, ‘xxx’, width=${pageWidth},height=${pageHeight},top=${pageTop},left=${pageLeft}) // 实现居中弹窗这段代码在主屏幕显示没有问题,可以居中显示,但如果将页面移换到副屏幕进行弹窗时。你会发现,无论参数怎么设置,弹窗都会在屏幕最左侧或屏幕最右侧进行显示,并不是水平居中。点击这里查看示例异常的原因及其解决方案原因可能很多同学都难以想到,这是因为弹窗的left和top参数,并不是基于当前页面作为原点进行计算的,而是以主屏幕作为原点进行计算所以进行位置设置时,需要计算其基于主屏幕的偏移值。那怎么知道当前是否处于主屏幕上呢?可以通过window.screen.availLeft参数来解决,该参数返回浏览器可用空间左边距离屏幕(系统桌面)左边界的距离。通过该参数,甚至不需要知道目前处于哪个屏幕上,直接加上该参数即可基于当前屏幕进行定位。修改后的代码如下const { availLeft, // 返回浏览器可用空间左边距离屏幕(系统桌面)左边界的距离。 availHeight, // 浏览器在显示屏上的可用高度,即当前屏幕高度 availWidth, // 浏览器在显示屏上的可用宽度,即当前屏幕宽度} = window.screenconst pageWidth = 600 // 弹出窗口的宽度const pageHeight = 550 // 弹出窗口的高度let pageTop = (availHeight - pageHeight) / 2 // 窗口的垂直位置let pageLeft = (availWidth - pageWidth) / 2 // 窗口的水平位置;left += availLeft // 加上屏幕偏移值window.open(‘xxx’, ‘xxx’, width=${pageWidth},height=${pageHeight},top=${pageTop},left=${pageLeft}) // 实现居中弹窗「top」参数的设置同样存在这个问题如果主屏幕和副屏幕并不是处于相同的高度,「top」值的设置同样会由于距系统主屏幕定位,而发生定位异常的显示。看下面这张图可能更好地理解另外目前笔者发现,这个兼容性问题,仅会在chrome内核的浏览器存在,safari上运行是不存在该问题的。综上所述,得出最终的解决方案为const { availTop, // 返回浏览器可用空间左边距离屏幕(系统桌面)左边界的距离。 availLeft, // 返回浏览器可用空间左边距离屏幕(系统桌面)左边界的距离。 availHeight, // 浏览器在显示屏上的可用高度,即当前屏幕高度 availWidth, // 浏览器在显示屏上的可用宽度,即当前屏幕宽度} = window.screenconst pageWidth = 600 // 弹出窗口的宽度const pageHeight = 550 // 弹出窗口的高度let pageTop = (availHeight - pageHeight) / 2 // 窗口的垂直位置let pageLeft = (availWidth - pageWidth) / 2 // 窗口的水平位置;if (navigator.userAgent.indexOf(‘Chrome’) !== -1) { // 兼容chrome的bug top += availTop // 距顶偏移值 left += availLeft // 距左偏移值}window.open(‘xxx’, ‘xxx’, width=${pageWidth},height=${pageHeight},top=${pageTop},left=${pageLeft}) // 实现居中弹窗问题解决过程(重点二)笔者遇到该问题是通过如下方式一一寻找解决方案百度最基础,成本最低的一步,笔者进行过以下关键字的搜索(这里主要突出关键字提取)window.open 居中显示window.open left chromewindow.open left 异常window.open 定位 异常window.open chrome 兼容性window.open 双屏显示异常搜索结果,找到了相关的问题,但未能找到真正有效的解决方案。问答论坛stackoverflow,国外著名的编程问答网站,纯英文,内容全。segmentfault,国内的stackoverflow,内容也不错。MDN官网维基百科:MDN Web Docs(旧称Mozilla Developer Network、Mozilla Developer Center,简称MDN)是一个汇集众多Mozilla基金会产品和网络技术开发文档的免费网站。一般可以看作前端基础函数的官方说明文档,具有一定的权威性,当然一定程度上会更为难懂其他页面代码分析寻找网上实现了该功能的网站,下载其页面代码进行分析。网上的代码都是加密过的,虽然不直观,但能推测或猜出一些端倪各关键词搜索首先,通过chrome调试工具,找到触发弹窗的按钮ctrl+s,下载整个页面,通过IDE全局搜索整个页面中关于该按钮的信息,如class,id,及其他属性值,能定位到该按钮的属性都全局搜索一遍逐文件查看,有无相关配置window.open 函数名搜索打开弹窗肯定需要通过该语句,全局搜索,如果window没被覆盖的话应该能找到第三个参数搜索根据 strWindowFeatures 可配置项目进行全局搜索,提取其特点,如「scrollbars」,「titlebar」这些变量以及其字符串形式传参的特点,搜索「,left=」「,height=」重置函数终极大招,函数重置,及通过在chrome控制台重置该函数,来观察其传参情况打开chrome控制台,找到Console栏,拷贝如下代码window.open = function () { console.log(arguments)}再此进行登录弹窗操作,触发函数执行笔者是在前三个方法都失败的情况下,通过第四个方法找到的问题所在。发现其left值传参为负数,在自己项目中设置为负数也能实现居中效果从而推测出原因感谢阅读,祝好 ...

January 23, 2019 · 1 min · jiezi