[TOC]
# 偏移量offset
offset是偏移、位移、補償的意思,offset家族由 offsetWidth、offsetHeight、offsetLeft、offsetTop、offsetParent 等組成,使用這些屬性可以獲取元素的實際寬高和元素到父元素(**父元素必須是定位**)的距離。具體關系如下
html和css代碼
```
<style>
body {
margin: 0;
}
#box {
position: absolute;
width: 300px;
height: 300px;
background-color: purple;
overflow: hidden;
margin: 50px;
}
#child {
width: 100px;
height: 100px;
background-color: lightskyblue;
margin: 50px;
border: 10px solid yellow;
padding: 10px;
}
</style>
<div id="box1">
<div id="box2">
</div>
</div>
```
JavaScript代碼
```
//獲取元素
var box1 = my$('box1');
var box2 = my$('box2');
console.log(box2.offsetWidth);
// offsetWidth = width + border + padding
console.log(box2.offsetHeight);
// offsetHeight = height + border + padding
console.log(box2.offsetLeft);
console.log(box2.offsetTop);
// 元素外邊距到父元素的邊框內側,其實就是 元素的margin + 父元素的padding,不包含邊框
// offsetLeft = margin-left + 定位父元素的padding-left
// offsetTop = margin-top + 定位父元素的padding-top
```
offset偏移量的圖示:

offsetParent:是一個只讀屬性,用于獲取最近一個定位父元素; parentNode:混合了所有(擁有子元素的) Node對象包含的共有方法和屬性。通俗的講,只要一個元素節點擁有子節點,這個元素節點就是 parentNode 類型;
offsetParent 和 parentNode的區別:offsetParent 獲取的是設置了 position 樣式的父元素,沒有設置position 則獲取到 body 元素;而 parentNode 則是直接獲取最近的父元素;
```
console.log(box2.offsetParent);
// offsetParent:獲取最近一個定位父元素,如果沒有定位父元素,則獲取到body元素
console.log(box2.parentNode);
//parentNode:獲取父元素(節點)
```
注意
>[info]1、獲取到的值是一個 number 類型,不帶單位;
2、獲取的寬高包含 border 和 padding;
3、只能讀取,不能設置;
# 客戶區client
client家族中較常用的四個屬性,clientLeft、clientTop、clientWidth、clientHeight,其中最常用的是 clientWidth、clientHeight。
html和css代碼
```
<style>
body {
margin: 0;
}
#box {
width: 100px;
height: 100px;
margin: 50px;
border: 30px solid red;
padding: 10px;
background-color: green;
}
</style>
<div id="box">
</div>
```
JavaScript代碼
```
var box = my$('box');
console.log(box.clientLeft);
// clientLeft = borderleft
console.log(box.clientTop);
// clientTop = bordertop
console.log(box.clientWidth);
// clientWidth = witdh + padding
console.log(box.clientHeight);
// clientHeight = hetight + padding
```
客戶區client的圖示:

# 滾動scroll
scroll家族中常用的幾個屬性有 scrollWidth、scrollHeight、scrollLeft、scrollTop 等,其中 scrollWidth、scrollHeight 獲取元素的寬和高,scrollLeft、scrollTop 獲取滾動出元素可視區域的距離。
html和css代碼
```
<style>
body {
margin: 0;
}
#box {
width: 100px;
height: 100px;
margin: 50px;
border: 30px solid red;
padding: 10px;
background-color: green;
overflow: auto;
}
</style>
<div id="box">
客戶:“這個圖下班之前必須發給我!” 設計師:“好的!” 第二天清早。 客戶:“圖怎么還沒發過來?” 設計師:“我還沒下班呢…”
</div>
```
JavaScript代碼
```
var box = my$('box');
console.log(box.scrollWidth); // scrollWidth代表可以滾動的總寬
console.log(box.scrollHeight); // scrollHeight代表可以滾動的總高
//獲取box滾動出去的區域的長度
console.log(box.scrollLeft); // scrollLeft代表橫向已滾動的長度
console.log(box.scrollTop); // scrollTop代表縱向已滾動的長度
// 注冊box的滾動條滾動事件,當滾動條滾動的時候執行事件處理函數
box.onscroll = function () {
// console.log('你滾');
//獲取box滾動出去的區域的長度
console.log(box.scrollLeft);
console.log(box.scrollTop);
}
```
滾動scroll的圖示:

*****
# 案例
## 拖拽窗口案例(了解)
>[success]====================06_鼠標拖拽盒子的案例>01.html====================
>思路:
>1、當鼠標按下時,求出鼠標在盒子中的位置;
> 鼠標在盒子中的位置 = 鼠標在頁面中的位置 - 盒子在頁面中的位置
>2、當鼠標移動時,保持鼠標在盒子中的位置不變(即盒子跟隨鼠標移動)
> 盒子的坐標 = 鼠標當前在頁面中的位置 - 鼠標在盒子中的位置
>使用到的屬性有:offsetLeft、offsetTop、pageX、pageY
>注意:盒子要脫離文檔流,即設置 position:absolute
>====================07_鼠標拖拽盒子的案例02.html====================
>問題:鼠標彈起了,盒子還黏在鼠標上。
>解決:當鼠標彈起時,移除鼠標移動事件。
>關閉按鈕:當鼠標點擊關閉按鈕時,隱藏盒子
>注意:使用getPage(e)解決pageX和pageY的瀏覽器兼容性問題
html和css代碼
```
~~~
<style>
* {
margin: 0;
height: 0;
border: 0;
list-style: none;
}
header {
width: 100%;
height: 40px;
line-height: 40px;
position: absolute;
top: 0;
left: 0;
background: green;
color: white;
text-indent: 2em;
}
#box {
width: 500px;
height: 300px;
border: 2px solid #ccc;
position: absolute;
top: 30%;
left: 30%;
/*left: 50%;
margin-left: -250px;*/
padding: 1px;
box-sizing: border-box;
}
.top {
/*width: 100%;*/
height: 40px;
line-height: 40px;
color: #fff;
background: #ccc;
display: flex;
justify-content: space-between;
padding: 0 10px;
cursor: move; /*改變鼠標指針為十字形*/
}
.top a {
color: white;
text-decoration: none;
}
</style>
<body>
<header>注冊信息</header>
<div id="box">
<div class="top" id="top">
<span> 注冊信息(可以關閉)</span>
<a href="javascript:void(0);">【關閉】</a>
</div>
</div>
</body>
```
JavaScript代碼
```
~~~
<script>
console.log(box);
//鼠標按下去
getId('top').onmousedown = function (e) {
// console.log(e.pageX, e.pageY);
// console.log(box.offsetLeft, box.offsetTop);
var x = e.pageX - getId('box').offsetLeft;
var y = e.pageY - getId('box').offsetTop;
getId('top').onmousemove =function(event){
console.log(event.pageX, event.pageY);
var xx =event.pageX-x;
var yy =event.pageY-y;
getId('box').style.left=xx+'px';
getId('box').style.top=yy+'px';
};
};
//鼠標松開
getId('top').onmouseup =function () {
getId('top').onmousemove=null;
}
</script>
```
## 登錄窗口案例
>[success] ===============08_彈出登錄窗口01.html===============
> 思路:
> 1、點擊“登錄”連接,顯示登錄框和遮蓋層
> 遮蓋層作用:
> 1)突出顯示登錄窗口;
> 2)遮擋窗口后面的內容,使頁面不能再點擊。
>
> 2、點擊關閉按鈕,隱藏登錄框和遮蓋層
> 3、拖拽:當鼠標移動時,讓登錄框與鼠標保持靜止位置;
> 參考頁面 09_彈出登錄窗口02.html
>
> ===============09_彈出登錄窗口02.html===============
> 3、拖拽:當鼠標移動時,讓登錄框保持與鼠標靜止位置;
> 注意:鼠標彈起時,移除鼠標移動事件
html和css代碼
```
~~~
<style>
* {
margin: 0;
padding: 0;
border: 0;
list-style: none;
}
header {
height: 100px;
line-height: 100px;
text-align: right;
padding-right: 200px;
}
a {
text-decoration: none;
color: #333;
font-size: 20px;
}
.modal {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.modal-bg {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background: rgba(0, 0, 0, 0.3);
}
.modal-box {
background: #fff;
width: 500px;
height: 300px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -250px;
margin-top: -150px;
}
.top {
height: 50px;
line-height: 50px;
text-align: center;
font-size: 18px;
cursor: move
}
.down {
padding: 10px;
}
label {
display: block;
height: 40px;
line-height: 40px;
margin-bottom: 20px;
}
input {
border: 1px solid #ccc;
border-radius: 3px;
height: 38px;
float: right;
width: 90%;
}
.btn {
width: 100px;
height: 30px;
line-height: 30px;
text-align: center;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 3px;
margin: auto;
}
.close {
position: absolute;
top: -15px;
right: -15px;
border-radius: 50%;
width: 30px;
height: 30px;
line-height: 30px;
background: #fff;
font-size: 12px;
text-align: center;
cursor: pointer;
}
</style>
~~~
~~~
<body>
<header>
<a href="javascript:void(0);">會員登錄</a>
</header>
<div class="modal" id="modal">
<div class="modal-bg"></div>
<div class="modal-box" id="modal-box">
<div class="top" id="top">會員登錄</div>
<div class="down">
<label for="">
賬號:
<input type="text" placeholder="請輸入賬號">
</label>
<label for="">
密碼:<input type="password" placeholder="請輸入密碼">
</label>
</div>
<div class="btn">登錄</div>
<span class="close" onclick="getId('modal').style.display='none'">關閉</span>
</div>
</div>
</body>
~~~
```
JavaScript代碼
```
~~~
<script>
getId('top').onmousedown = function (e) {
var x = e.pageX - getId('modal-box').offsetLeft;
var y = e.pageY - getId('modal-box').offsetTop;
getId('top').onmousemove = function (event) {
// console.log(event.pageX, event.pageY);
var aa = event.pageX - x;
var bb = event.pageY - y;
getId('modal-box').style.left = aa + 'px';
getId('modal-box').style.top = bb + 'px';
getId('modal-box').style.marginLeft = 0; // 使marginLeft和marginTop歸零,從而使盒子不跑偏
getId('modal-box').style.marginTop = 0;
};
};
//鼠標松開
getId('top').onmouseup = function () {
getId('top').onmousemove = null;
};
document.onmouseup = function () {
getId('top').onmousemove = null;
}
</script>
~~~
```
## 放大鏡
>[success] ===============10_放大鏡效果-案例01===============
> 思路:
> 1、鼠標經過的時候,顯示mask和big,當鼠標離開box的時候隱藏mask和big
> 2、當鼠標在盒子中移動的時候,讓mask和鼠標一起移動(相對靜止)
> 3、當mask移動的時候,讓大圖片移動
>
> 把以上問題拆開,一個一個解決,如下
>
> (1)鼠標經過的時候,顯示mask和big,當鼠標離開box的時候隱藏mask和big
> a、獲取6個元素
> b、綁定鼠標移入、移出事件,完成顯示和隱藏mask和bigImg功能
>
>
> ===============11_放大鏡效果-案例02===============
>
> (2)當鼠標在盒子中移動的時候,讓mask和鼠標一起移動
> a、獲取鼠標在盒子中的位置
> b、讓鼠標出現在遮蓋層的中心的
> c、設置遮蓋層位置
> 問題:鼠標移動到box外面了,但遮蓋層沒有消失。因為事件冒泡
> 解決:把mask限制到box中,設置mask可以在box中移動的最大值、最小值即可。
>
> ===============12_放大鏡效果-案例03===============
>
> (3)當mask移動的時候,讓大圖片移動
> 求 大圖片將要移動的距離,根據比例公式:
> mask移動的距離/mask最大能夠移動的距離 = 大圖片移動的距離/大圖片最大能夠移動的距離
>
> 求未知數:
> mask最大能夠移動的距離
> 大圖片最大能夠移動的距離
> 最后求出 大圖片移動的距離
>
> 設置大圖片移動的位置:注意位置正負數和移動方向的關系
>
> ===============13_放大鏡的兼容性處理-案例04===============
> 注意:IE中兼容性問題
> 只有谷歌支持.webp, 所以將 .webp 改成 .jpg
>
> 以下事件在不觸發事件冒泡的時候,效果一樣,但是在事件冒泡后,就有瀏覽器兼容性問題
> mouseenter mouseleave 不會觸發事件冒泡
> mouseover mouseout 會觸發事件冒泡
>
> IE7、8中不支持rgba()
> 使用
> filter:alpha(opacity=40)progid:DXImageTransform.Microsoft.gradient(startColorstr=#FFFF00,endColorstr=#FFFF00);
html和css代碼
```
~~~
<style>
*{
margin: 0;
padding: 0;
border: 0;
list-style: none;
}
#box{
width: 350px;
height: 350px;
background: url("images/small.jpg")no-repeat;
background-size: 100%;
margin: 100px;
position:relative;
}
span{
width: 150px;
height: 150px;
background: rgba(255,255,0,0.7);
position: absolute;
left: 0;
top: 0;
cursor: move;
display: none;
}
#bigImg{
width: 400px;
height: 400px;
background: url("images/big.jpg") no-repeat;
position: absolute;
left: 360px;
top: 0;
display: none;
}
</style>
<script src="common.js"></script>
~~~~~~
<body>
<div id="box">
<span id="sp"></span>
<div id="bigImg"></div>
</div>
</body>
~~~
```
JavaScript代碼
```
~~~
<script>
/*
* 鼠標移入移出某個物體,可以使用onmouseover和onmouseout
* 但這兩個事件會產生事件冒泡,
* 所以我們有另外兩個代替他們的事件: onmouseenter和onmouseleave
* */
// 鼠標移入box
getId('box').onmouseenter=function () {
// 黃色盒子出現
getId('sp').style.display='block';
getId('bigImg').style.display='block';
// 鼠標移動事件
getId('box').onmousemove=function (e) {
// 獲取鼠標在盒子中的坐標點
var x= e.pageX-getId('box').offsetLeft;
var y= e.pageY-getId('box').offsetTop;
/* 以下兩個判斷是用來檢測span的最大移動范圍 */
if (x<=75){
x=75;
} else if (x>=275) {
x=275;
}
if (y<=75){
y=75;
} else if (y>=275) {
y=275;
}
// 給span賦值left和top
var spanx=x-75;
var spany=y-75;
getId('sp').style.left=spanx+'px';
getId('sp').style.top=spany+'px';
//設置bigImg的 backgroundPositionX 和 backgroundPositionY
getId('bigImg').style.backgroundPositionX=-2*spanx+'px';
getId('bigImg').style.backgroundPositionY=-2*spany+'px';
};
};
// 鼠標移出box
getId('box').onmouseleave=function () {
// 黃色盒子消失
getId('sp').style.display='none';
//大圖消失
getId('bigImg').style.display='none';
// 鼠標移動事件清空
getId('box').onmousemove = null;
};
~~~
```
## 模擬滾動條(熟悉)
>[success] =================15_模擬滾動條01=================
> 方式一:當內容超出父容器時,直接設置父容器的樣式為 overflow:auto,缺點是難看,有瀏覽器兼容性問題
>
> 思路:
> 1、根據內容大小,計算滾動條的高度
> 滾動條的高度/scroll的高度 = box的高度 / 內容的高度
> 利用以下幾個關于高度的屬性:
> offsetHeight 元素的大小 + padding + border
> clientHeight 元素的大小 + padding
> scrollHeight 內容的大小 + padding
>
> 問題:沒有內容或內容不超出div時,不應該顯示滾動條,但此時卻顯示出來了。
> 解決:當內容的高度大于box的高度,則計算滾動條的高度,否則滾動條的高度為0。
>
> =================16_模擬滾動條02=================
> 2、讓滾動條能拖動
> 2.1 當鼠標按下的時候,求鼠標在滾動條中的位置
> 2.2 當鼠標在頁面上移動的時候,求滾動條的位置
>
> 問題:bar滾動到滾動區域scroll外面了。
> 解決:控制bar不能移出滾動區域scroll。
>
>
>
> =================17_模擬滾動條03=================
> 3、當拖拽滾動條時,改變內容位置
> 公式:
> 內容滾動的距離/內容最大能滾動的距離 = 滾動條滾動的距離/滾動條最大能滾動的距離
>
> 注意:滾動條的滾動方向與內容的滾動方向是相反的,所以滾動的位置大小是負數。
html和css代碼
```
~~~
<style>
* {
margin: 0;
padding: 0;
border: 0;
list-style: none;
}
#box{
width: 300px;
height: 400px;
border: 1px solid #f00;
overflow: hidden;
margin: 100px;
padding-right: 24px;
box-sizing: border-box;
position: relative;
}
#content{
user-select:none;
padding-bottom: 3px;
}
.scrollbar {
width: 24px;
height: 100%;
background: #ccc;
position: absolute;
right: 0;
top: 0;
}
span {
width: 24px;
border-radius: 24px;
background: #f00;
position: absolute;
left: 0;
top: 0;
/*display: block;*/
cursor: pointer;
}
</style>
<script src="common.js"></script>
~~~~~~
<body>
<div id="box">
<div id="content">
從前有座山,山里有座廟,廟里有倆和尚,一老一小,老和尚給小和尚講了一個故事:
從前有座山,山里有座廟,廟里有倆和尚,一老一小,老和尚給小和尚講了一個故事:
……
…(n)…
……
從前有座山,山里有座廟,廟里有倆和尚,一老一小,老和尚給小和尚講了一個故事:
從前有座山,山里有座廟,廟里有倆和尚,一老一小,老和尚給小和尚講了一個故事。
</div>
<div class="scrollbar" id="scb">
<span id="sp"></span>
</div>
</div>
</body>
~~~
```
jiavascript代碼
```
~~~
<script>
//獲取 scrollbar 的高度
var scrollbarHeight = getId('scb').clientHeight;
//獲取 box 的高度
var boxHeight = getId('box').clientHeight;
//獲取 content 的高度
var contentHeight = getId('content').scrollHeight;
//根據比例獲取 span 的高度
var spanHeight = boxHeight / contentHeight * scrollbarHeight;
getId('sp').style.height = spanHeight + 'px';
// span的mousedown事件
getId('sp').onmousedown = function(){
//span的mousemove事件
document.onmousemove = function(e){
var y = e.pageY - getId('box').offsetTop;
//計算y的可移動范圍
var halfSpanHeight = spanHeight/2;//sp的幾何中心距離頂部的距離
if (y >= halfSpanHeight && y <= (scrollbarHeight - halfSpanHeight)) {
var hasMoveLen = y - halfSpanHeight;//求取已經移動的距離
getId('sp').style.top = hasMoveLen + 'px';
// 求mt,mt就是content向上滾動的距離
mt = hasMoveLen / scrollbarHeight * contentHeight;
getId('content').style.marginTop = -mt + 'px';
} else {
return;
}
}
};
getId('sp').onmouseup = function () {
document.onmousemove = null;
};
document.onmouseup = function () {
document.onmousemove = null;
};
~~~
```