[更新]我重写了代码以匹配所有具有 id 的锚点,并简化了sortByDistance
函数中向量范数的比较。
检查我在 jsFiddle 上的尝试(前一个在这里)。
javascript部分:
// findPos : courtesy of @ppk - see http://www.quirksmode.org/js/findpos.html
var findPos = function(obj) {
var curleft = 0,
curtop = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft;
curtop = obj.offsetTop;
while ((obj = obj.offsetParent)) {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
}
}
return [curleft, curtop];
};
var findClosestAnchor = function (anchors) {
var sortByDistance = function(element1, element2) {
var pos1 = findPos( element1 ),
pos2 = findPos( element2 );
// vect1 & vect2 represent 2d vectors going from the top left extremity of each element to the point positionned at the scrolled offset of the window
var vect1 = [
window.scrollX - pos1[0],
window.scrollY - pos1[1]
],
vect2 = [
window.scrollX - pos2[0],
window.scrollY - pos2[1]
];
// we compare the length of the vectors using only the sum of their components squared
// no need to find the magnitude of each (this was inspired by Mageek’s answer)
var sqDist1 = vect1[0] * vect1[0] + vect1[1] * vect1[1],
sqDist2 = vect2[0] * vect2[0] + vect2[1] * vect2[1];
if ( sqDist1 < sqDist2 ) return -1;
else if ( sqDist1 > sqDist2 ) return 1;
else return 0;
};
// Convert the nodelist to an array, then returns the first item of the elements sorted by distance
return Array.prototype.slice.call( anchors ).sort( sortByDistance )[0];
};
当 dom 准备好时,您可以像这样检索和缓存锚点: var anchors = document.body.querySelectorAll('a[id]');
我还没有在智能手机上测试过它,但我看不出它为什么不起作用的任何原因。
这就是我使用var foo = function() {};
表单的原因(更多 javascript 模式)。
这return Array.prototype.slice.call( anchors ).sort( sortByDistance )[0];
条线实际上有点棘手。
document.body.querySelectorAll('a['id']')
返回一个 NodeList,其中包含当前页面正文中具有属性“id”的所有锚点。遗憾的是,NodeList 对象没有“排序”方法,并且无法使用sort
Array 原型的方法,因为它与其他一些方法一起使用,例如 filter 或 map(NodeList.prototype.sort = Array.prototype.sort
本来真的很好)。
这篇文章更好地解释了为什么我曾经Array.prototype.slice.call
将我的 NodeList 变成一个数组。
最后,我使用该Array.prototype.sort
方法(以及自定义sortByDistance
函数)将 NodeList 的每个元素相互比较,我只返回第一项,这是最接近的一项。
要查找使用固定定位的元素的位置,可以使用以下更新版本findPos
:http ://www.greywyvern.com/?post=331 。
我的答案可能不是更有效(drdigit 的必须比我的更高),但我更喜欢简单而不是效率,我认为它是最容易维护的。
[还有一个更新]
这是一个经过大量修改的 findPos 版本,适用于 webkit css 列(没有间隙):
// Also adapted from PPK - this guy is everywhere ! - check http://www.quirksmode.org/dom/getstyles.html
var getStyle = function(el,styleProp)
{
if (el.currentStyle)
var y = el.currentStyle[styleProp];
else if (window.getComputedStyle)
var y = document.defaultView.getComputedStyle(el,null).getPropertyValue(styleProp);
return y;
}
// findPos : original by @ppk - see http://www.quirksmode.org/js/findpos.html
// made recursive and transformed to returns the corect position when css columns are used
var findPos = function( obj, childCoords ) {
if ( typeof childCoords == 'undefined' ) {
childCoords = [0, 0];
}
var parentColumnWidth,
parentHeight;
var curleft, curtop;
if( obj.offsetParent && ( parentColumnWidth = parseInt( getStyle( obj.offsetParent, '-webkit-column-width' ) ) ) ) {
parentHeight = parseInt( getStyle( obj.offsetParent, 'height' ) );
curtop = obj.offsetTop;
column = Math.ceil( curtop / parentHeight );
curleft = ( ( column - 1 ) * parentColumnWidth ) + ( obj.offsetLeft % parentColumnWidth );
curtop %= parentHeight;
}
else {
curleft = obj.offsetLeft;
curtop = obj.offsetTop;
}
curleft += childCoords[0];
curtop += childCoords[1];
if( obj.offsetParent ) {
var coords = findPos( obj.offsetParent, [curleft, curtop] );
curleft = coords[0];
curtop = coords[1];
}
return [curleft, curtop];
}