一、首先,我們先了解一下三大家族及其區別(offset/scroll/client)
1.offset
1.1.offsetWidth = width+padding+border;
1.2.offsetHeight = Height+padding+border;
1.3.offsetTop:檢測距離帶有定位的父盒子的上面的距離,返回值不帶有px
1.4.offsetLeft:檢測距離帶有定位的父盒子的左邊的距離,返回值不帶有px
1.5.offsetParent:檢測最近的帶有定位的父盒子的節點,返回值是一個節點。(若父盒子都沒有定位,則返回body)
2.scroll
2.1.scrollWidth = width+padding;
2.2.scrollHeight = Height+padding;如果文字超出了盒子,高度爲超出盒子的內容的高。不超出是盒子本身高度。IE8以下(不包括IE8) 爲盒子本身內容的高度。
2.3.scrollTop:特指網頁被捲去的頭部的高度(這個屬性的獲取有兼容問題,下文將闡述)
2.4.scrollLeft:特指網頁左邊被捲去的寬度(一般不用)
3.client
3.1.clientWidth = width+padding;
3.2.clientHeight = Height+padding;
3.3.clientTop:獲取盒子的上border的寬度
3.4.clientLeft:獲取盒子的左側border的寬度
3.5.clientX:event調用,鼠標距離瀏覽器可視區域的左邊距離
3.6.clientY:event調用,鼠標距離瀏覽器可視區域的頂部距離
二、各種函數封裝(動畫、獲取值)
1.勻速動畫封裝
function animate(ele,target){
//要用定時器,先清除定時器
//一個盒子只能有一個定時器,這樣兒的話,不會和其他盒子出現定時器衝突
//而定時器本身講成爲盒子的一個屬性
clearInterval(ele.timer);
//我們要求盒子既能向前又能向後,那麼我們的步長就得有正有負
//目標值如果大於當前值取正,目標值如果小於當前值取負
var speed = target>ele.offsetLeft?10:-10;
ele.timer = setInterval(function () {
//在執行之前就獲取當前值和目標值之差
var val = target - ele.offsetLeft;
ele.style.left = ele.offsetLeft + speed + "px";
//目標值和當前值只差如果小於步長,那麼就不能在前進了
//因爲步長有正有負,所有轉換成絕對值來比較
if(Math.abs(val)<Math.abs(speed)){
ele.style.left = target + "px";
clearInterval(ele.timer);
}
},30)
}
2.緩動動畫封裝
function animate(ele,target) {
//要用定時器,先清定時器
clearInterval(ele.timer);
//定義定時器
ele.timer = setInterval(function () {
//獲取步長
//步長應該是越來越小的,緩動的算法。
var step = (target-ele.offsetLeft)/10;
//對步長進行二次加工(大於0向上取整,小於0向下取整)
step = step>0?Math.ceil(step):Math.floor(step);
//動畫原理: 目標位置 = 當前位置 + 步長
ele.style.left = ele.offsetLeft + step + "px";
//檢測緩動動畫有沒有停止
//console.log(1);
if(Math.abs(target-ele.offsetLeft)<=Math.abs(step)){
//處理小數賦值
ele.style.left = target + "px";
clearInterval(ele.timer);
}
},30);
}
3.緩動動畫封裝(單個屬性)(這裏有一個獲取元素樣式的封裝函數getStyle,後文將給出)
//參數變爲3個
function animate(ele,attr,target){
//先清定時器
clearInterval(ele.timer);
ele.timer = setInterval(function () {
//四部
var leader = parseInt(getStyle(ele,attr)) || 0;
//1.獲取步長
var step = (target - leader)/10;
//2.二次加工步長
step = step>0?Math.ceil(step):Math.floor(step);
leader = leader + step;
//3.賦值
ele.style[attr] = leader + "px";
//4.清除定時器
if(Math.abs(target-leader)<=Math.abs(step)){
ele.style[attr] = target + "px";
clearInterval(ele.timer);
}
},25);
}
4.緩動動畫封裝(多個屬性,多個屬性將用json來實現)(這裏有一個獲取元素樣式的封裝函數getStyle,後文將給出)
function animate(ele,json){
//先清定時器
clearInterval(ele.timer);
ele.timer = setInterval(function () {
//開閉原則
var bool = true;
//遍歷屬性和值,分別單獨處理json
//attr == k(鍵) target == json[k](值)
for(var k in json){
//四部
var leader = parseInt(getStyle(ele,k)) || 0;
//1.獲取步長
var step = (json[k] - leader)/10;
//2.二次加工步長
step = step>0?Math.ceil(step):Math.floor(step);
leader = leader + step;
//3.賦值
ele.style[k] = leader + "px";
//4.清除定時器
//判斷: 目標值和當前值的差大於步長,就不能跳出循環
//不考慮小數的情況:目標位置和當前位置不相等,就不能清除定時器。
if(json[k] !== leader){
bool = false;
}
}
console.log(1);
//只有所有的屬性都到了指定位置,bool值纔不會變成false;
if(bool){
clearInterval(ele.timer);
}
},25);
}
5.緩動動畫封裝(回調函數)(這裏有一個獲取元素樣式的封裝函數getStyle,後文將給出)
//參數變爲3個
function animate(ele,json,fn){
//先清定時器
clearInterval(ele.timer);
ele.timer = setInterval(function () {
//開閉原則
var bool = true;
//遍歷屬性和值,分別單獨處理json
//attr == k(鍵) target == json[k](值)
for(var k in json){
//四部
var leader = parseInt(getStyle(ele,k)) || 0;
//1.獲取步長
var step = (json[k] - leader)/10;
//2.二次加工步長
step = step>0?Math.ceil(step):Math.floor(step);
leader = leader + step;
//3.賦值
ele.style[k] = leader + "px";
//4.清除定時器
//判斷: 目標值和當前值的差大於步長,就不能跳出循環
//不考慮小數的情況:目標位置和當前位置不相等,就不能清除清除定時器。
if(json[k] !== leader){
bool = false;
}
}
console.log(1);
//只有所有的屬性都到了指定位置,bool值纔不會變成false;
if(bool){
clearInterval(ele.timer);
//所有程序執行完畢了,現在可以執行回調函數了
//只有傳遞了回調函數,才能執行
if(fn){
fn();
}
}
},25);
}
6.獲取元素樣式封裝
function getStyle(ele,attr){
if(window.getComputedStyle){
return window.getComputedStyle(ele,null)[attr];
}
return ele.currentStyle[attr];//兼容IE
}
7.獲取頂部或左邊被捲去部分的高度或寬度封裝(返回值是一個json,可以用.top獲取)
function scroll(){
//簡單封裝(實際工作使用)
return {
"top": window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,
"left": window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft
}
}
8.獲取屏幕可視區域的寬高的封裝(返回值是一個json,可以用.width獲取)
//獲取屏幕可視區域的寬高
function client(){
if(window.innerHeight !== undefined){
return {
"width": window.innerWidth,
"height": window.innerHeight
}
}else if(document.compatMode === "CSS1Compat"){//判斷是否有dtd約束
return {
"width": document.documentElement.clientWidth,
"height": document.documentElement.clientHeight
}
}else{
return {
"width": document.body.clientWidth,
"height": document.body.clientHeight
}
}
}
三、event對象的屬性
1.獲取event對象:在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象中包含着所有與事件有關的信息event對象要在事件的驅動函數裏面獲取,如:
document.onclick = function (event) {
//兼容寫法,兼容IE瀏覽器
event = event || window.event;
}
2.event的屬性:
特別注意pageY/X這兩個屬性,它是表示鼠標位於整個網頁頁面的頂部和左側部分的距離。
但是IE不支持這兩個屬性,於是就有了pageY和pageX的兼容寫法:
var pagey = event.pageY || scroll().top + event.clientY;
var pagex = event.pageX || scroll().left + event.clientX;
//鼠標在頁面的位置=被捲去的部分+看得見的部分
四、事件和冒泡/取消冒泡
1.事件和一些特殊屬性
1.滾動事件:window.onscroll
2.屏幕滾動到具體位置:window.scrollTo(x,y)//屏幕滾動到座標x,y
3.鼠標按下:onmousedown 鼠標彈起:onmouseup
4.鼠標移動:onmousemove //如果事件是鼠標按下並移動,那這個事件的調用者應該是document(如拖拽一個盒子、模擬滾動條)
5.瀏覽器大小改變:window.onresize
6.檢測屏幕寬度和高度:window.screen.width/window.screen.height
2.冒泡、取消冒泡、捕獲、事件委託
1.冒泡就是當子盒子和父盒子都綁定了同一個事件時,如果子盒子的事件被觸發,那麼父盒子相應的事件會在之後觸發。
2.捕獲剛好和冒泡相反,子盒子的事件被觸發時,父盒子相應的事件會先觸發,子盒子的事件再觸發。想要實現捕獲可以用addEventListenner(參數1,參數2,參數3)這個方法。參數1:事件去掉on ;參數2 :調用的函數;參數3:可有可無。(不寫或是false是冒泡,True是捕獲。)
3.取消冒泡:
元素.事件= function (event) {
//阻止冒泡
event = event || window.event;
if(event && event.stopPropagation){
event.stopPropagation();
}else{
event.cancelBubble = true;//兼容IE瀏覽器
}
}
4.事件委託:事件委託就是普通的事件綁定沒有辦法爲新創建的元素綁定事件。所以我們要使用冒泡的特性來實現事件委託。比如我們新創建了一個li標籤,我們想給這個標籤綁定一個事件,就可以給他的父類ul綁定一個事件,然後用event.target來獲取事件觸動的時候傳遞過來的對象,判斷之後再進行操作,給出一個樣例代碼:
//事件委託
ul.onclick = function (event) {
//獲取事件觸動的時候傳遞過來的值
event = event || window.event;
var a = event.target?event.target:event.srcElement;//兼容IE寫法
//判斷標籤名,如果是li標籤就綁定驅動函數
if(a.tagName === "LI"){
alert("我是li");
}
}