2016-02-19 42 views
1

我在純js中創建了一個放大鏡。我發現在需要將div的鼠標位置相對於其父母進行轉換時,我發現在計算疊加放大器div的頂部時,offsetTop的工作方式與offsetLeft不同。在調整了什麼後,我需要減去整個容器div的offsetHeight。計算子div頂端位置 - 爲什麼父offsetHeight需要被減去?

在有問題的代碼行是這樣的:

magnifier.style.top = yPosition - container.offsetHeight + "px"; 

爲什麼我需要減去container.offsetHeight

我知道我已閱讀過關於此的一些信息,但無法找到它。

免責聲明此代碼正在工作。我問,所以我(和下面的人)可以理解盒子模型是如何工作的。

我知道有更多的跨瀏覽器可靠的jQuery替代品。我喜歡自己編寫代碼,以便我可以瞭解它是如何工作的。如果您發現某些內容與現代瀏覽器不兼容,請隨時發表評論。

最後,對於使用此功能的任何人,我從該示例中刪除了代碼以調整變換。例如,如果包裝器具有一個transform: translate(-50%, 0);以將包裝器水平居中,則需要將所得到的翻譯量(轉換爲包裝器的左邊位置)添加到計算中。

我創建了一個jsfiddle here。如果任何人有興趣,我會在小提琴中留下更多評論。

<!DOCTYPE html> 
<html> 

<head> 
<script type="text/javascript" src="../css/ms.js"></script> 

<style type="text/css"> 
/********************/ 
body { 
    background-color: #FFF; 
    margin-left: 30px; 
    margin-top: 10px; 
} 
.wrapper { 
    position: absolute; 
    left: 100px; 
} 

#container { 
    width: 527px; 
    height: 450px; 
    border: 5px black solid; 
    overflow: hidden; 
    background-color: #F2F2F2; 
    cursor: pointer; 
} 

#image { 
    width: 527px; 
    height: 450px; 
} 

#magnifier { 
    width: 250px; 
    height: 250px; 
    overflow:hidden; 
    position:relative; 
    z-index: 1000; 
    border: solid 1px; 
} 

#magnifier img { 
    position: absolute;  
} 

</style> 
</head> 
<body> 
<div class="wrapper" id="wrapper"> 
    <div id="container"> 
    <img id="image" src="../docs/grade-2/jpg/g2-bb-saints-francis.jpg"> 
    <div id="magnifier" class="magnifier"> 
     <img id="imagecopy">   
    </div> 
     <br> 
    </div> 
    <input type="button" value="Zoom" onClick="initmagnifier('magnifier', 'image', 'imagecopy');"><br> 
</div> 


<script> 

function initmagnifier(magnifier, image, imagecopy){ 
    var magnifier = document.getElementById("magnifier"); 
    var container = document.getElementById("container"); 
    var wrapper = document.getElementById("wrapper"); 
    var img = document.getElementById(image); 
    var imgcopy = document.getElementById(imagecopy); 
    var zoom = 2; 
    container.addEventListener("mousemove", 
    function(e){ 
     movemagnifier(e, img, imgcopy, magnifier, container, wrapper, zoom) 
    }, false); 
    var src = img.src; 
    imgcopy.src = src; 
    var src2 = imgcopy.src; 

    imgcopy.height = img.height * zoom; 
    imgcopy.width = img.width * zoom ; 
} 

function movemagnifier(e, img, imgcopy, magnifier, container, wrapper, zoom) { 
    // to get the left & top of the magnifier  
    // position needs to be adjusted for WRAPPER & CONTAINER top and left  
    // gets the top and left of the container 
    var containerPosition = getPosition(e.currentTarget); 

    // adjust out the CONTAINER's top/left 
    // Then takes 1/2 the hight of the MAGNIFIER and subtracts it from the MOUSE position to center MAGNIFIER around the MOUSE cursor 
    var xPosition = e.clientX - containerPosition.x - (magnifier.clientWidth/2); 
    var yPosition = e.clientY - containerPosition.y - (magnifier.clientHeight/2); 

    magnifier.style.left = xPosition + "px"; 
    magnifier.style.top = yPosition - container.offsetHeight + "px"; 

    // Adjust for zoom 
    // adjust the MAGNIFIER's top/left at an equal pace to the zoom amount 
    var yTravel = (e.clientY - containerPosition.y) * (zoom - 1); 
    var yimgPosition = -(yPosition - container.clientTop + yTravel); 
    imgcopy.style.top = yimgPosition + "px"; 

    var xTravel = (e.clientX - containerPosition.x) * (zoom - 1); // * 1.5 
    var ximgPosition = -(xPosition + xTravel); 
    imgcopy.style.left = ximgPosition + "px"; 

console.log('****'); 
console.log(e.clientY); // MOUSE POSTION 
console.log(containerPosition.y); 
console.log(wrapper.offsetTop); 
console.log(wrapper.clientHeight); 

console.log(container.offsetTop); 
console.log(container.clientHeight); 
console.log(yPosition); 
console.log(container.offsetHeight); 
console.log(magnifier.style.top); 
} 

function getPosition(element) { 
    var xPosition = 0; 
    var yPosition = 0; 
    // element is the CONTAINER 
    // This calculates the postion of the element (CONTAINER) TOP & LEFT relative to ALL parents 
    while (element) { 
    // if transform: translate in place for x and y, 
    // add it back as it skews the offsetLeft offsetTop values by the translate amount 
     xPosition += ((element.offsetLeft) - element.scrollLeft); 
     yPosition += ((element.offsetTop) - element.scrollTop); 
     element = element.offsetParent; 
    } 
    return { x: xPosition, y: yPosition }; 
} 
</script> 
</body> 
</html> 

回答

1

我花了我的時間超過我關心承認,但我找到了原因。在你的小提琴中,你定位了#magnifier -element relative,這意味着你必須將它從容器內部的圖像下方的「自然」位置移開。因此,通過將#magnifier拉到容器的頂部/左側位置,左側位置已經匹配,但是#magnifier的「自然」頂部位置是完整高度的當您從#container的頂部/左側位置計算容器時,您需要減去高度#container

一個簡單的解決方法是添加position: relative#container並在#magnifierposition: absolute改變position: relative

這會給你的#magnifiertop: 0; left: 0的絕對定位的元素預期的座標系是其相對母公司的左上角(第一被定位父元素,在這種情況下#container)。

a working example而不需要減去container.offsetHeight


,而我在這,你可能想看看進入Element.getBoundingClientRect功能,你可以得到你需要確定一個單一的通話位置的所有信息。

+0

我知道你的意思是「長於我關心的承認」。我在這方面花了太多時間...以及我自己的其他答案。感謝您花費的時間 - 非常感謝。我顯然不知道getBoundingClientRect - 它看起來非常有用。祝你有美好的一天! – mseifert

+0

很高興我可以幫忙;-)關於'getBoundingClientRect'的一個注意事項是,它會觸發一個[重繪](http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/),所以你可能想緩存它的輸出和/或將它用在['requestAnimationFrame'](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) –