物流公司网站建设,在哪里查商标注册信息,9951026企业邮箱,免费插画素材网站最近有项目需要使用js原生开发滑动组件#xff0c;频繁要用到dom元素的各种属性#xff0c;其中以各种类型的height和top属性居多#xff0c;名字相近#xff0c;含义也很容易搞混。因此特地总结归纳了一下常用的知识点#xff0c;在文末我们来挑战实现一个简易的移动端Sc…最近有项目需要使用js原生开发滑动组件频繁要用到dom元素的各种属性其中以各种类型的height和top属性居多名字相近含义也很容易搞混。因此特地总结归纳了一下常用的知识点在文末我们来挑战实现一个简易的移动端Scroll组件。
要理解height和top要从盒模型开始说起首先我们来认识一下css3中定义的盒模型。dom元素在页面上实际占据的面积可以由下面这张图来说明 我们可以把它想象成一枚鸡蛋从外到内依次是
橙色区域——外边距margin鸡蛋壳
黑色区域——边框border蛋壳膜
绿色区域——内边距padding蛋白
白色区域——内容content蛋黄
我们真正关心的部分是内容content也就是鸡蛋营养最丰富的部分。content外面包裹了这么多层我们在页面中才会感觉dom结构整体疏密有致不会被密密麻麻的文字和图片所困扰。为了更好地描述盒模型web规范中还定义了一些其他接口来描述他们也就是我们今天要聊到的主角们 在上面这张图中我们描述了具有嵌套关系的两层dom元素注意这里的内容区和前述一张图中有所不同这里的内容区也是一个独立的dom元素即它也有自己的margin、border、padding和content为了简化起见子元素不再具体绘制出来子元素由于整体高度很高甚至超出了父元素的高度在父元素中不能完全展示出来超出的不可见部分用灰色表示也就是两者构成了滚动关系。下面我们来尝试描述以下属性
一、clientHeight
只读属性。clientHeight实际上就是垂直滚动条的高度一般情况下垂直滚动条都是要紧贴上下border的因此clientHeight 上下padding 内容height。别忘了有个特殊情况当存在水平方向滚动条时还需要考虑水平滚动条挤占了垂直滚动条的一部分空间即clientHeight 上下padding 内容height - 水平滚动条高度。用鸡蛋来比喻的话clientHeight就是剥了壳的鸡蛋。
二、clientTop
只读属性。描述了顶部border的宽度。顶部border容易让我们联想到头发的厚度下次在镜子前可以对自己说你的clientTop变少了不过你也变强了。
三、offsetHeight
只读属性。offsetHeight和clientHeight比较类似观察可以发现比clientHeight多了border这一层offsetHeight clientHeight 上下border。现在我们把时光回退到给鸡蛋剥壳的前一刻鸡蛋从水里捞出来洗干净呈现的样子——offsetHeight。
四、offsetTop
只读属性。它返回当前元素相对于其offsetParent元素的顶部内边距的距离。这段距离是不包含自身和父元素的border宽度的实际上offsetTop自己的上margin 父元素的上padding相当于鸡蛋和鸡蛋盒之间挡板的厚度。
五、scrollHeight
只读属性。描述了元素内容高度的度量包括由于溢出导致的视图中不可见内容。我们可以hack一下把父元素中不可见的内容也展示出来子元素在垂直方向可以分为两部分外层的margin和内部的offsetHeight 对于具有滚动关系的父子元素其scrollHeight具有不同的含义
1对于子元素而言由于子元素本身不包含溢出部分其scrollHeight和clientHeight具有相同的值
2对于父元素而言由于父元素的内容实际上被子元素“撑起来”了因此其scrollHeight为把内容区域“展开”后的实际高度父元素scrollHeight 子元素的offsetHeight 子元素上下margin 自己的上下padding
六、scrollTop
读写属性可以获取或设置一个元素的内容垂直滚动的像素数。这个是目前为止咱们遇到的第一个可以支持设置的属性。
1初始状态时内容垂直方向未滚动其值为0
2当内容垂直方向滚动到底时由于内容区实际高度为scrollHeight可显示高度为clientHeight多出来的部分就是此时的scrollTop值为scrollHeight - clientHeight
因此可以得出结论0 scrollTop scrollHeight - clientHeight
七、实战
学习了以上属性和信息我们模仿京东小程序的scroll-view组件功能来实现一个H5版滑动组件的常见功能列表的下拉刷新和上拉加载。要实现这个功能大概可以分为3个核心要点
1可滚动需要有一个不可动的外壳和可滑动的内容区。
2手势识别通过移动端的touch属性我们可以对比touchend和touchstart的手指位置来简单进行手势识别。
3事件触发根据滑动位置的临界条件来判断是否应该触发刷新和加载事件。
部分实现代码如下
// scroller.jsexport default class Scroller {constructor(el, option) {this._el elthis._parent el.parentNodethis._option optionthis._pos 0this._handleScrollStart this.handleScrollStart.bind(this)this._handleScroll this.handleScroll.bind(this)this.init()}init() {this._el.addEventListener(touchstart, this._handleScrollStart)this._el.addEventListener(touchend, this._handleScroll)if(this._option.auto) {this.handleRefresh()}}destroy() {this._el.removeEventListener(touchstart, this._handleScrollStart)this._el.removeEventListener(touchend, this._handleScroll)}handleScrollStart(e) {const touch e.targetTouches[0] || e.changedTouches[0]this._pos touch.clientY}handleScroll(e) {const touch e.targetTouches[0] || e.changedTouches[0]const delta touch.clientY - this._posif(delta this._option.threhold) {// 手势向下且下行滚动距离超过判定阈值if(this._parent.scrollTop 0) {this.handleRefresh(e)}} else if(this._parent.scrollHeight this._parent.clientHeight delta -this._option.threhold){// 内容可滚动且上行滚动距离超过判定阈值if(this._parent.scrollTop this._parent.scrollHeight - this._parent.clientHeight - this._option.threhold){this.handleLoad(e)}}}handleRefresh(...params) {this._option.onRefresh this._option.onRefresh.apply(this, params)}handleLoad(...params) {this._option.onRefresh this._option.onLoad.apply(this, params)}
}调用demo
var inner document.getElementsById(inner)
var list []
var pageIndex 1
function getMockData() {const newData [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].map(i i(pageIndex-1)*10)setTimeout(() {if(pageIndex1) { list newData } else if(pageIndex 5) { list.push(...newData) } else { alert(没有更多内容了) }pageIndexinner.innerHTML list.map(i div classinner-item${i}/div).join()}, 300)
}
function onRefresh() {pageIndex 1getMockData()
}
new Scroller(inner, {threhold: 20,onRefresh: onRefresh,onLoad: getMockData,auto: true
})大家可以自己试用一下感觉效果还不错欢迎留言区讨论交流。 作者京东零售 陈震 来源京东云开发者社区