弹窗层次关系【转载】

时间:2022-05-10 20:39:12

【单页应用】我们该如何处理框架弹出层层级关系?

前言

最近总结不多,一方面是之前的知识点多比较基础,所以学习总结起来比较快

但是基础知识只有那么一点,现在当然可以从新知识点着手拓宽视野(这个当然要继续),但是基础积累,再深入学习是成为优秀前端必不可少的阶段

所以这块地方还得死扛,所幸现在是个优秀的团队,身边高手前辈较多,有时候请教是很有方向的,这个很是幸运啊!

其次年后来到公司后,总有点浮浮沉沉的事情发生,而每年的3月又是各个公司“变化”的集中期,所以心境受到了一些影响,此点不可不慎啊!

搞技术的不可浮躁!如果心思过多的花在了“人事”上,那么就真有点背道而驰了,技术人员的核心竞争还是应当在技术上

当然,年后会为年前干的一些事情擦屁股,一般每个团队年前都会有一些烂事没有做完,刚好一些事情就落到了我的头上,于是进入今日的主题

因为边思考便行文,有问题请提出。

弹出层层次关系

以我现有视野来说,单页应用应该是移动端的一个趋势,很多公司或多或少的会要求HTML5的站点表现与APP趋于一致

而好的前端团队的话就会要求HTML5不逊色与APP,当然这块不是不可能发生(在一两年后,应该逐渐明显)

对于非单页应用来说,弹出层的层次关系比较简单,但是依旧会遇到一个弹出层弹出,另一个弹出层也需要弹出的场景

而上述比较“少见”的场景在单页应用中就时常发生了,如果一开始没有对自己框架的层级做设计的话,后面的发展会让你觉得头疼

弹出层的问题

这里先稍微借鉴一点这里的弹出层做说明:http://sentsin.com/jquery/layer/

PS:贤心弹出层是比较全面的,可以少写很多代码说明问题

小议层次关系

弹窗层次关系【转载】

通过查看样式我们发现其z-index为:

element.style {
background-color: rgb(255, 255, 255);
z-index: 19891015;
height: 132px;
}

那么,我这里就会产生一个疑问,如果再弹出一个alert框呢,当然这里会有以下场景:

① 由于蒙版的存在,只允许一个alert框弹出

② 框架本身做了处理,同一类型的alert框只能有一个

③ 框架对z-index做了处理,第二次弹出的层会遮住第一个(这里还会有其它情况我们稍后再说)

④ 未做特殊处理

现在,我们干一件很2B的事情,将蒙版去掉再点击试试:

通过实验发现,该作者的处理方式如下:

① 只允许一个alert弹出层的出现,与上面②方案类似

② 不同类型的弹出层需要同时出现时候,只会保留最新的一个

弹窗层次关系【转载】弹窗层次关系【转载】

比如我们这里点击询问类的弹出层时候,再点击信息框,于是询问类的弹出层就被关闭了,再点击确定就没有了弹出层了

交叉层次处理

当遇到多个层次时候,也是需要处理的,继续以这里的弹出层为例:我们连续弹出两个层

弹窗层次关系【转载】 弹窗层次关系【转载】

后出来的层会在先出来的层次之前,意思是其z-index的值比较高,这个时候再加上一个loading框的话就比较齐全了

弹窗层次关系【转载】

所以,这里我们可以得出一个结论:

作者是以先后出现顺序设计层次结构的(未读源码,具体情况不明)

而,这个还只是第一种层次关系,比较细心的朋友会发现,左边有一个fixed元素:

弹窗层次关系【转载】 弹窗层次关系【转载】

而fixed元素在单页应用中多用作view的头尾,那么alert类的弹出层与fixed头尾又是什么关系呢??

fixed头尾与弹出层

这里footer的样式如下:

弹窗层次关系【转载】
.fixnav {
position: fixed;
bottom: 0;
width: 100%; z-index: 9999;
transition: all .8s;
background: #206F96;
}
弹窗层次关系【转载】

与上千万的弹出层来说就比较渺小了

弹窗层次关系【转载】 弹窗层次关系【转载】

所以弹出层应该遮盖头尾(fixed),这个处理也是有道理的,但是这里也会有一个问题

头部是否应该被遮盖

对于单页应用来说,头部是否应该被遮盖呢?

这个不同的人会有不同的想法:

① 不应该被遮盖

如果一个loading框加载失败,而代码又未做处理的话,用户除了刷新页面或者退出程序别无他法

现在很多html5代码会同时用于app中,而app的头部是不可遮盖的

② 应该被遮盖

简单而言,弹出层出现时不遮盖头部会引起很多BUG,对代码的健壮性要求更高

比如,弹出层出现时候,点击后退,如果业务代码未对弹出层作出处理的话,这个弹出层不会消失

另外,如果view切换过程中会有动画效果的话,view的会被设置为absolute,那么此时alert与页面view会有层级关系

所以,保险的方案,应该是遮盖头部

出现次数问题

我们看到该作者的处理是相同的控件只能出现一次,这个处理方法对于单页应用来说可能就有一定麻烦了:

① 我们当然可以在控制器中设置一些经常出现的弹出层插件:

alert类,弹出层类,让他们只能出现一次,但是实际项目中,极有可能出现各个view对弹出层的需求不一样的需求

这个时候我们的弹出层应该被控制么?

② 弹出层会自带蒙版(mask),这个蒙版又该出现几次呢

③ 全屏覆盖层(广告类,或者其他)又该处于什么层次呢???

让我们带着这些问题一一学习今日的知识

全局唯一的弹出层

由设计的角度来说,无论是出现蒙版还是其它因素,我们对一些弹出层是只要求单独存在的,比如,我们不会希望同时存在两个alert

所以,我们先整理哪些弹出层只会出现一次:

① alert 类警告层

② confirm 类确认层

③ toast类消息层

④ loading类加载层

⑤ 其它类似弹出层

以上弹出层事实上全局只应该有一个,dom一旦存在就不会销毁,但是这里也会有其它问题,比如我们这个confirm吧

统一控件不同行为

我们现在在demo01时候希望点击确定时候弹出个确定的提示,而提示相关有所不同的话......

弹窗层次关系【转载】 弹窗层次关系【转载】

弹窗层次关系【转载】 弹窗层次关系【转载】

就需要每次show的时候传递参数复写上一次的事件等相关数据:

弹窗层次关系【转载】
showConfirm: function (message, title, okFn, cancelFn, okTxt, cancelTxt) {
  //如果传入的是对象的话,直接用作初始化
  if (typeof message == 'object' && message.message) {
    this.confirm.setViewData(message);
  } else {
    this.confirm.setViewData({
      message: message,
      title: title,
      buttons: [
      { text: (cancelTxt || '取消'), click: function () {
        if (typeof cancelFn == 'function') { cancelFn(); }
        this.hide();
      }, type: Alert.STYLE_CANCEL
      },
      {
        text: (okTxt || '确定'),
        click: function () {
          if (typeof okFn == 'function') { okFn(); }
          this.hide();
        },
        type: Alert.STYLE_CONFIRM
      }
    ]
    });
  }
  this.confirm.show();
},
弹窗层次关系【转载】

这块的结论是:

同一控件需要在show时候动态改变事件句柄相关参数,以达到dom结构重复利用的目的

这个操作是很简单的,有问题的是我们的mask控件,如果我们的mask控件具有点击mask关闭alert控件功能的话,情况就有所不同了

需要几个mask

我们的框架到底需要几个mask,这个问题其实比较关键

全局只有一个mask,dom代码清晰,这个想法非常合理,但不易操作

怎么说呢,如果存在两个弹出层同时存在的情况,A弹出层出来后,B弹出层再出来,这个时候A的蒙版应该比A高比B低

这个时候关掉B,mask又应该比A低,于是我们需要去动态调整蒙版的zindex

以上场景已经比较烦了,如果我们有点击蒙版关闭插件的需求的话,我们点击蒙版时候该关闭B还是该关闭A呢???

情况又变得复杂起来,实现起来容易照成BUG,所以简单的方案还是,每个弹出层为其配置一个mask,是否具有点击关闭特性由插件决定

比如loading框就不具有关闭特性,所以结论是:

为每一个弹出层配置单独mask是比较简单的处理方案

阻止弹出层层次

弹出层出现次数确定后,第二个问题就是其出现时候的层级关系,我们这里采用:

按弹出层出现先后顺序确定其层级

比如我们几个层同时出现时候,我们就按照其出现顺序定义谁在钱谁在后,在后面的会被蒙版遮住(这里可能会导致蒙版愈来愈黑)

弹窗层次关系【转载】 弹窗层次关系【转载】

那么这个时候层次关系应该怎么确定呢,或者说,我怎么知道我每次取得的z-index都会最大,这个其实就和我们前面的uuid是一个道理了

base.getBiggerzIndex = (function () {
  var diviso =  1000;
  return function () {
    return ++diviso;
  };
})();

每次设置index时候都在这里来获取z-index即可

header与footer

header与footer根据我们前面的想法,应该是被遮住的,所以,我们直接将其z-index设置为500即可

但是这个时候依旧会有一些特殊的情况,比如warning404等情况

404提示

一般来说,404页面应该比一般弹出层低,并且比header低,但是比footer高,为什么这么说呢

因为header可能全局只有一个,而footer来说属于单个view,比如提交订单的按钮

这个时候404提示应该遮盖所有的页面,但是不能遮盖头部

页面层级

页面切换来说,会将view转化为absolute,这个时候也会有一定层级的,这个时候又会有许多问题,比如footer栏为fixed元素,整个view切换时候他并不会跟着移动

所以,我们应该将footer栏做成组件,在切换时候将之隐藏

页面切换时候的层级应该比header低,但是比一般的弹出层要高,所以我们最后可以形成以下规则

弹窗层次关系【转载】
第一级别:(0)
文档流元素

第二级别:(500)
footer类组件,需要在文档流之上,依旧属于view内部

第三级别:(1000)
404提示类,需要覆盖view内的所有元素,但不能遮盖头部,属于遮盖view内部的弹出层

第四级别:(1500)
view切换时候的层级
此时view的层级会比404等层级高
框架切换时候需要对弹出层进行hide

第五级别:(2000)
header类,头部

第六级别:(3000+)
一般类弹出层,根据弹出先后顺序计算
弹窗层次关系【转载】

结语

今天正好在整理框架的层级关系,将思考到的东西做了一定记录,如果各位对此有研究请不吝赐教