组件之路---固钉组件

固钉组件的作用是将页面元素固定在可视区域之内。

恩!是这样

需求

固钉的基本功能就是将元素固定在页面的特定位置,即使存在滚动条的情况下,固钉元素仍然可以固定在设定的位置。

这里位置固定所指的参考有两种情况:

  1. 元素相对窗口固定位置。
  2. 元素相对于父容器固定位置。

常规情况下,我们使用的是元素相对于窗口位置固定,这里直接使用fixed布局就可以了,但是对于第二种需求就不容易实现了,这也是固钉组件主要实现的功能。

预备知识

pageYOffset pageXOffset

pageYOffset pageXOffset是window的属性,表示整个页面滚动过的值,可以使用body元素的scrollTop属性替代。

scrollTop scrollLeft

scrollTop scrollLeft是Element的属性,表示一个具有属性的元素滚动过的值。

offsetTop offsetLeft

要想解释offsetTop 以及 offsetLeft的值,需要理解offsetParent的概念。
offsetParent可以返回距离当前元素最近的采用定位(position属性值为fixed、relative或者absolute)祖先元素。
如果祖先元素中没有采用定位的元素,则返回body对象。
offsetTop/offsetLeft返回值表示当前元素上边缘/左边缘距离offsetParent返回元素的距离的数值,单位是像素。

总结:scroll是与滚动相关的属性,offset是与offsetParent相关的属性值

innerHeight

innerHeight为window的属性,指窗口的大小(不包含工具条与滚动条)。

clientHeight

clientHeight这个属性是只读属性,对于没有定义CSS或者内联布局盒子的元素为0,同时它是元素内部的高度(单位像素),包含内边距,但不包括水平滚动条、边框和外边距。
clientHeight 可以通过 CSS height + CSS padding - 水平滚动条高度.

offsetHeight

在IE6,IE7,IE8以及最新的的FF, Chrome中,在元素上都是offsetHeight = clientHeight + 滚动条 + 边框。

scrollHeight

这个高度与滚动条无关,是内容的实际高度。

计算方式 :scrollHeight = topPadding + bottomPadding + 内容margix box的高度。

总结:clientHeight与scrollHeight与滚动条有关,前者与设置的height有关,后者与元素所占据的实际高度有关

fixed布局

fixed布局是我们通常采用的实现元素固定在窗口的特定位置,如下图所示:


image

但是如果我们想实现基于任意父容器的固钉呢?即使其固定在父容器的指定位置,而不是单纯的固定在窗口的指定位置,如下图所示:


fixedToContainer.gif

实现原理

其实实现第二种需求的固钉仍然是基于fixed布局的,只不过我们这里加入的事件监听,动态的设置元素的top/bottom等值,以在视觉效果上实现相对于父元素的位置固定。

事件列表

events = [
    'resize',
    'scroll',
    'touchstart',
    'touchmove',
    'touchend',
    'pageshow',
    'load',
  ];

固钉组件组件要监听如上列表中列出的事件,由以上事件触发位置更新。

注意:这里监听事件的元素应该是固钉的容器元素target,若不指定target,会默认为body。

位置更新

以实现距离容器组件顶部为settingTop px为例,说明何时进行位置更新,以及如何位置更新。

const scrollTop = getScrollTop(targetNode);
const elemOffset = getOffset(affixNode, targetNode);
//elemOffset表示固钉的位置,包括父容器滚动过的值
const targetRect = getTargetRect(targetNode);
//targetRect是基于getBoundingClientRect得到的元素位置信息
//getBoundingClientRect方法返回元素的大小及其相对于视口的位置

if (scrollTop > elemOffset.top - settingTop) {
      // Fixed Top
      const width = elemOffset.width;
      const top = targetRect.top + settingTop;
      //即根据父容器的位置和设置的参数确定固钉的实际位置。
      this.setAffixStyle(e, {
        position: 'fixed',
        top,
        left: targetRect.left + elemOffset.left,
        width,
      });
}

这里有一个问题,即该如何去理解判断条件呢?

scrollTop > elemOffset.top - settingTop

其实可以将判断条件改写为:

elemOffset.top - scrollTop < settingTop

即页面向上滚动之后elemOffset.top - scrollTop(即固钉相对于父元素顶部的距离)小于预设值settingTop,发生位置更新。

同理,如果设置的参数是settingBottom,也可以以同样的思路分析。

总结

固钉实现的思路仍然是基于fixed布局,只不过我们为了实现相对于任意父元素的位置固定,引入了事件监听以及位置更新。理解位置更新的机制,关键是理解本文中涉及到的各种距离到底指的是什么。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Element对象对应网页的HTML标签元素。每一个HTML标签元素,在DOM树上都会转化成一个Element节点...
    许先生__阅读 5,832评论 0 2
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 14,683评论 1 92
  • 前言 CSSOM全称CSS对象模型,涉及两部分内容,第一部分和操作样式表相关,第二部分和元素尺寸相关,本文介绍第二...
    江枫阅读 8,105评论 1 10
  • 个人博客:https://yeaseonzhang.github.io 花了半个多月的时间,终于又把“JS红宝书”...
    Yeaseon阅读 13,963评论 9 52
  • 小A是一名客服,工作内容除了正常解答业务知识,还需要处理各种投诉。 年初,小A得知公司年终评选客服标兵,...
    积极向上的桃子阅读 3,073评论 0 0