摘要:最近在學(xué)習(xí)的表格排序,沒想到看不起眼的表格排序?qū)嶋H上卻暗含了眾多知識點。二實現(xiàn)表格排序使用獲取數(shù)據(jù)之所以使用動態(tài)獲取數(shù)據(jù),是為了使用文檔碎片綁定數(shù)據(jù)。
最近在學(xué)習(xí)js的表格排序,沒想到看不起眼的表格排序?qū)嶋H上卻暗含了眾多JS知識點。在這里記錄一下此次學(xué)習(xí)過程。希望對大家也有所幫助。
完整的表格排序涉及了下列這些知識點:
call方法使用
sort方法深入
數(shù)據(jù)綁定
DOM映射
下面詳細(xì)的總結(jié)一下這些知識點,最后結(jié)合這些知識點實現(xiàn)下面這樣一個表格排序案例。
完整的案例源碼:https://github.com/daweihe/JS...
一、知識點總結(jié) 1、call方法使用call方法的作用是改變方法中的this指向。
call這個方法是定義在Function.prototype的方法。我們定義的任何一個函數(shù)都可以認(rèn)為它是Function這個類的一個實例。那么就可以通過實例的__proto__屬性找到所屬類的原型。任何一個函數(shù)都可以調(diào)用call和apply等方法。
先來看一個例子:
var obj = { name : "JS" } function testCall () { console.log(this); } testCall.call( obj ); // {name: "JS"}
首先函數(shù)testCall通過原型鏈查找機制找到call方法執(zhí)行,call方法在執(zhí)行過程中把調(diào)用call方法這個函數(shù)實例中的this都改變成call的第一個參數(shù),接下來調(diào)用call方法的這個實例函數(shù)執(zhí)行。
看兩個題目:
function fn1() { console.log(1); console.log(this); } function fn2() { console.log(2); console.log(this); } fn1.call(fn2); //this -> fn2 fn1.call.call(fn2); //這里的call是改變function.__proto__.call的call方法中的this,相當(dāng)于執(zhí)行參數(shù)
call方法在執(zhí)行的時候,call方法的第一個參數(shù)是用來改變this的,而從第二個參數(shù)開始都是傳給調(diào)用call的函數(shù)的參數(shù)。
在非嚴(yán)格模式下,給call方法不傳遞參數(shù)、或者傳遞null、undefined后,this都是指向window。
sum.call(); //window sum.call(null); //window sum.call(undefined); //window
嚴(yán)格模式下call執(zhí)行的時候和非嚴(yán)格模式不同:
sum.call(); //undefined sum.call(null); //null sum.call(undefined); //undefined
下面使用call方法實現(xiàn)一個類數(shù)組轉(zhuǎn)換為數(shù)組的方法:
function listToArray (likeAry) { var ary = []; try { ary = Array.prototype.slice.call(likeAry); } catch (e) { for (var i = 0; i < likeAry.length; i ++) { ary[ary.length] = likeAry[i]; } } return ary; }
和call類似的方法還有apply和bind方法,這里簡單總結(jié)一下。
apply方法的作用和call方法一模一樣,只是傳參的形式不太一樣,apply將函數(shù)的參數(shù)用數(shù)組包裹起來:
function sum(num1, num2) { console.log(num2 + num1); console.log(this); } sum.apply(null,[100,200]);
bind方法同樣也是用來改變this關(guān)鍵字的,但是它只是僅僅改變this指向,不立即執(zhí)行調(diào)用this的函數(shù)。
function sum(num1, num2) { console.log(num2 + num1); console.log(this); } var obj = {name : "zx"} var temp = sum.bind(obj); //temp已經(jīng)是被改變了this的函數(shù) temp(100,200); //當(dāng)我們需要的時候才執(zhí)行 //或者像這樣處理 var temp = sum.bind(null, 100, 200); temp();
bind方法體現(xiàn)了js中的預(yù)處理思想。
2、 sort排序深入我們知道數(shù)組的sort方法只能排序10以內(nèi)的數(shù)組。如果需要排序的數(shù)組中存在大于10的數(shù)字,我們就需要向sort方法中傳入回調(diào)函數(shù),常見的是這樣:
ary.sort(function (a,b) { return a - b; });
這樣就能實現(xiàn)數(shù)組的升序排序。那么這樣排序的原理到底是什么呢?
對于傳入的兩個參數(shù):a代表的是找到的數(shù)組中的當(dāng)前項,b代表的是當(dāng)前項的后一項。
return a -b : 如果a大于b,返回結(jié)果,a與b交換位置。如果a小于b,那么a和b位置不變。 這是升序排序
return b -a : 如果b大于a,返回結(jié)果,a與b交換位置。如果a小于b,那么a和b位置不變。 這是降序排序
了解了基本原理后,對于這樣一個二維數(shù)組,如何實現(xiàn)按年齡排序?
var persons = [{ name:"dawei", age:55 },{ name:"ahung", age:3 },{ name:"maomi", age:2 },{ name:"heizi", age:78 },{ name:"afu", age:32 }];
其實很簡單:
ary.sort(function(a,b){ return a.age - b.age; });
如果按姓名排序,則要涉及字符串的localeCompare()方法:
ary.sort(function(a,b){ return a.name.localeCompare(b.name); });
name.localeCompare()這個方法會根據(jù)兩個字符串的字母進(jìn)行比較,如果前一個字符串的第一個字母在24個英文字母中出現(xiàn)的位置比后一個字符串的第一個字符出現(xiàn)的位置靠前,則認(rèn)定第一個字符串小,返回-1。如果出現(xiàn)的位置靠后,則認(rèn)定第一個字符串大,返回1。如果所比較的字符相等。則比較下一個字符。
這個方法很實用,常用于按姓氏排序,對于漢字,該方法會自動將漢字轉(zhuǎn)換為漢語拼音進(jìn)行比較。
3、數(shù)據(jù)綁定在js中一般使用動態(tài)綁定或者拼接字符串的方式實現(xiàn)數(shù)據(jù)綁定。
動態(tài)綁定:
//ary為需要添加到頁面中的數(shù)據(jù)數(shù)組
var oDiv = document.getElementById("box");//獲取容器
var myUl = oDiv.getElementsByTagName("ul")[0];//獲取列表
var arrLength = ary.length;
for (var i = 0;i < arrLength ; i ++)
{ //動態(tài)創(chuàng)建元素
var oli = document.createElement("li");
oli.innerHTML = "" + (i + 5) + "" + ary[i].title;
myUl.appendChild(oli);//動態(tài)添加元素
}
每添加一次就會引起一次DOM回流,如果數(shù)據(jù)量過大,這樣則會嚴(yán)重影響性能。
關(guān)于DOM的回流與重繪,推薦大家看一下這篇文章:http://www.css88.com/archives...
拼接字符串:
var str = ""; for(var i=0; i"; str += ""; str += (i+5); str += ""; str += ary[i].title; str += ""; } myUl.innerHTML += str;
這種方式雖然只引起一次回流,但是它會去除原來存在的元素中所有的事件和屬性。如果我們?yōu)榱斜碇械膌i標(biāo)簽添加鼠標(biāo)移入,背景變色的事件,那么這種方法會使這個事件失效。
為了解決上面的兩種數(shù)據(jù)綁定方法帶來的問題,我們使用文檔碎片來添加數(shù)據(jù)。
var frg = document.createDocumentFragment();//創(chuàng)建文檔碎片 for (var i =0; i" + ary[i].title; frg.appendChild(li);//將數(shù)據(jù)動態(tài)添加至文檔碎片中 } myUl.appendChild(frg); //將數(shù)據(jù)一次性添加到頁面中 frg = null; //釋放內(nèi)存
這樣即只引起一次DOM回流,又會保留原來存在的事件。
4、DOM映射DOM映射機制:所謂映射,就是指兩個元素集之間元素相互“對應(yīng)”的關(guān)系。頁面中的標(biāo)簽集合和在JS中獲取到的元素對象(元素集合)就是這樣的關(guān)系。如果頁面中的HTML標(biāo)簽結(jié)構(gòu)發(fā)送變化,那么集合中對應(yīng)的內(nèi)容也會跟著自動改變。
對于這樣一個列表使用下列腳本:
var myul = document.getElementById("myul"); var mylis = myul.getElementsByTagName("li"); for (var i = mylis.length - 1 ; i >= 0; i --) { myul.appendChild(mylis[i]); } console.log(mylis.length); // 5
將獲取到的列表元素反序重新插入ul中,那么ul列表會變成下面這樣:
我們看到列表的長度依然是5,只是位置顛倒了。這是因為每個li標(biāo)簽和JS中獲取的標(biāo)簽對象存在一個對應(yīng)關(guān)系,當(dāng)某個標(biāo)簽被重新插入到頁面中時,頁面中對應(yīng)的標(biāo)簽會移動到插入的位置。這就是DOM映射。
二、實現(xiàn)表格排序 1、使用ajax獲取數(shù)據(jù)之所以使用動態(tài)獲取數(shù)據(jù),是為了使用文檔碎片綁定數(shù)據(jù)。
var res = ""; //聲明一個全局變量,接收數(shù)據(jù) var xhr = new XMLHttpRequest(); xhr.open("get", "date.txt", false); xhr.onreadystatechange = function() { if (xhr.readyState == 4 && xhr.status == 200) { res = JSON.parse(xhr.responseText); } } xhr.send(null);
此時數(shù)據(jù)就保存在了res這個全局變量之中。
2、使用文檔碎片綁定數(shù)據(jù)var frg = document.createDocumentFragment(); for (let i = 0; i < res.length; i++) { var tr = document.createElement("tr"); for (key in res[i]) { var td = document.createElement("td"); td.innerHTML = res[i][key]; tr.appendChild(td); } frg.appendChild(tr); } tbody.appendChild(frg);3、對表格進(jìn)行排序
這里涉及的點較多
//為兩列添加點擊事件 for (let i = 0; i < ths.length; i++) { let curTh = ths[i]; curTh.sortFlag = -1; //用于對列進(jìn)行升降序排列 curTh.index = i; //記錄當(dāng)前點擊列的索引,便于排序操作 if (curTh.className == "sort") { curTh.onclick = function() { sort.call(this); //改變排序函數(shù)內(nèi)this的指向,讓其指向當(dāng)前點擊列 } } } //排序方法 function sort() { //對數(shù)組元素進(jìn)行排序 let target = this; //這里將this取出,因為在sort方法里需要使用該this,但是sort方法里的this是調(diào)用方法的數(shù)組 this.sortFlag *= -1; //1 代表升序 -1代表降序 let ary = listToArray(bodyTrs); //獲取body數(shù)據(jù) ary = ary.sort(function(a, b) { let one = a.cells[target.index].innerHTML; let two = b.cells[target.index].innerHTML; let oneNum = parseFloat(one); let twoNum = parseFloat(two); if (isNaN(oneNum) || isNaN(two)) { return one.localeCompare(two) * target.sortFlag; } else { return (oneNum - twoNum) * target.sortFlag; } }); //把排好序的數(shù)組重新寫入頁面 let frg = document.createDocumentFragment(); for (let i = 0; i < ary.length; i++) { rg.appendChild(ary[i]); } tbody.appendChild(frg); frg = null; //點擊某列時,要將其他列的排序標(biāo)志恢復(fù)為-1,讓下次再點擊任意一個標(biāo)簽時都是默認(rèn)是升序排列 for (let i = 0; i < ths.length; i++) { if (ths[i] != this) { ths[i].sortFlag = -1; } } }
表格排序應(yīng)用很常見,在面試中也會有這樣的題目。這個小案例做下來,受益匪淺。這是我在學(xué)習(xí)的某峰學(xué)院的JS課程中的一個案例,如果對JS掌握不扎實的同學(xué),歡迎保存:鏈接: https://pan.baidu.com/s/1jHVy8Uq 密碼: v4jk。如果鏈接失效,加Q群領(lǐng)取:154658901。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/112840.html
摘要:最近在學(xué)習(xí)的表格排序,沒想到看不起眼的表格排序?qū)嶋H上卻暗含了眾多知識點。二實現(xiàn)表格排序使用獲取數(shù)據(jù)之所以使用動態(tài)獲取數(shù)據(jù),是為了使用文檔碎片綁定數(shù)據(jù)。 最近在學(xué)習(xí)js的表格排序,沒想到看不起眼的表格排序?qū)嶋H上卻暗含了眾多JS知識點。在這里記錄一下此次學(xué)習(xí)過程。希望對大家也有所幫助。 完整的表格排序涉及了下列這些知識點: call方法使用 sort方法深入 數(shù)據(jù)綁定 DOM映射 下面...
摘要:個人前端文章整理從最開始萌生寫文章的想法,到著手開始寫,再到現(xiàn)在已經(jīng)一年的時間了,由于工作比較忙,更新緩慢,后面還是會繼更新,現(xiàn)將已經(jīng)寫好的文章整理一個目錄,方便更多的小伙伴去學(xué)習(xí)。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 個人前端文章整理 從最開始萌生寫文章的想法,到著手...
摘要:我也意識到在學(xué)習(xí)一個框架前,將框架的思想和原生的實現(xiàn)進(jìn)行對比有多么重要。這個是目前為止一個大的框架思路,當(dāng)然還要再進(jìn)行每個功能的細(xì)分。表格將上一步的并集數(shù)據(jù)顯示出來渲染分表格,表格有一個表頭,用于展示商品的種類地區(qū)以及每月的銷售情況。 前言:由于剛?cè)肭岸藭r間并不長,之前最近一直處在學(xué)習(xí)的階段,現(xiàn)在準(zhǔn)備找工作,回首看看之前學(xué)的,發(fā)現(xiàn)了很多的瑕疵。我分析覺得主要原因在于之前有些東西學(xué)的太快...
閱讀 881·2021-11-15 11:37
閱讀 3619·2021-11-11 16:55
閱讀 3285·2021-11-11 11:01
閱讀 1009·2019-08-30 15:43
閱讀 2756·2019-08-30 14:12
閱讀 695·2019-08-30 12:58
閱讀 3398·2019-08-29 15:19
閱讀 2039·2019-08-29 13:59