问题描述
最近做项目的时候,有这么一个问题:用了brix组件dropdown做了一个下拉框,而这个下拉框有一个默认值,想让下拉框展开的时候直接定位到当前所选值,即:
希望原来的
变为
其html组织结构为:
ul中的各个选项为js手动生成。
一、最初的想法
直接在js中给默认的开始值添加选中样式,再用js将下拉框定位到所选中值。具体是:在'.dropdown-hd'上加click事件,当展开dropdown的时候获取被选中项的scrollTop值,然后将ul的scrollTop设置为被选中项的scrollTop值。
未果,下拉框的位置还是丝毫不动。
二、求助网络
发现理解scrollTop有误,网上答案为:
也就是说组件初始化时内层元素上边界和外层元素上边界重合,没有任何内容超过外层元素的上边界,此时被选中项的scrollTop值为0,无法起作用。
再查scrollTop的时候,发现总是把scrollTop和offsetTop联系在一起,故又看了一下offsetTop,发现这个属性挺符合要求的,因为offsetTop获取对象相对于版面或由offsetTop属性指定的父坐标的计算顶端位置。故改为:
但是发现还是不行,定位不准确,结果如下所示。
三、求助同事
非常感谢我旁边的外号哥GG和牙套姐MM,他们向我伸出了援助之手。牙套姐MM听了我的思路之后,皱起了眉头,觉得我这种做法是不对的,不应该人为的给这个组件默认值添加选中样式,再定位,而应该从组件入手,应用组件默认的选中item方法。所以又开始了探索组件的道路。
(1)组件自身方法select
组件有选中item的方法select,直接运用select方法让组件自动去完成。而我终于也知道了如何从brix中获取一个组件了,Brix.pagelet.getBrick("dropdown-start");其中参数为组件的id,通过这个可以获取一个组件,Brix.pagelet.getBricks("dropdown");其中参数为组件的name,可以获取组件名为参数的一系列组件。真的,非常感谢牙套姐的热心帮助,要不然我真不知道是这样获取已经初始化的组件的。
因为有两个组件名为dropdown的组件,不知道是先初始化哪一个,所以给这两个组件都加上了id,然后:
发现确实是选中了默认值,但是郁闷的是组件并没有定位到默认值的地方。
(2)监听组件事件selected
(1)无果后,牙套姐MM建议监听组件选中事件selected,使组件选中选项后立马定位到该位置。于是,
发现还是不行,定位不准确,结果为:
(3)是不是监听错了事件?
牙套姐MM说,可能选中完选项之后,整个下拉框就缩起来不可见了,所以监听selected方法根本无法准确的得到这些数值并设置。
于是,我们又想到应该监听组件刚展开下拉框的事件focus,于是:
结果如下:
顿时欣喜若狂,尼玛,终于好了,都忍不住向天狂笑啦!!!但是,发现又有了新的问题,我再自己任意选择其他选项时,悲剧发生了,如下:
唉,一个问题的解决伴随着其他问题的出现啊……怎么会这样?这定位也太不准了吧?
(4)抛弃kissy的offsetTop方法,使用原生的javascript方法
牙套姐MM就说,可能kissy的scrollTop方法和offsetTop有问题,因为是kissy封装的方法,可能不准确,于是抛弃了kissy的offsetTop方法:
发现,终于OK了,没问题了,这个问题终于得到了解决。
(5)探索kissy的offset方法
追根溯源,为什么kissy中的offset不准呢?于是查看Kissy源代码:
从源码中可以看出,kissy的offset是这样计算的,当relativeWin没有指定或者是window的时候,element的offsetTop指的是当前对象到page最顶端的距离,当指定的relativeWin不是window的时候,element的offsetTop指的是当前对象到浏览器client顶端的距离。所以不管我们是不是
中指定了相对父元素,只要这个父元素不是window,那么offset计算的就是当前对象到浏览器client顶端的距离,而非当前元素到这个相对父元素层顶端的距离,与原生的javascript不一致。