Maison >interface Web >js tutoriel >Native JS implémente le tri des tables
J'ai récemment appris le tri de tableaux en JS. Je ne m'attendais pas à ce que le tri de tableaux discret implique en fait de nombreux points de connaissances JS. Enregistrez ce processus d’apprentissage ici. J'espère que cela aidera tout le monde aussi.
Le tri complet des tableaux implique les points de connaissances suivants :
la méthode d'appel utilise la
méthode de tri en profondeur
Liaison de données
Mappage DOM
Ce qui suit résume ces points de connaissances en détail et les combine enfin Les points de connaissance implémentent le cas de tri de table suivant.
Code source complet du cas : https://github.com/daweihe/JS...
. Toute fonction que nous définissons peut être considérée comme une instance de la classe Function.prototype
. Ensuite, vous pouvez trouver le prototype de la classe via l'attribut Function
de l'instance. N'importe quelle fonction peut appeler des méthodes telles que __proto__
et call
. apply
var obj = { name : 'JS' } function testCall () { console.log(this); } testCall.call( obj ); // {name: "JS"}Tout d'abord, la fonction
trouve la méthode d'appel via le mécanisme de recherche en chaîne du prototype et l'exécute pendant le processus d'exécution, l'appel. La méthode place la méthode d'appel dans l'instance de fonction. Celle-ci est remplacée par le premier paramètre de l'appel, puis la fonction d'instance de la méthode d'appel est appelée et exécutée. testCall
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,相当于执行参数Lorsque la méthode d'appel est exécutée, le premier paramètre de la méthode d'appel est utilisé pour changer cela, et à partir du deuxième paramètre sont les paramètres passés à la fonction appelant call. En mode non strict, si aucun paramètre n'est transmis à la méthode d'appel, ou si null ou undefined est passé, cela pointera vers
. window
sum.call(); //window sum.call(null); //window sum.call(undefined); //windowL'exécution de l'appel en mode strict est différente de celle en mode non strict :
sum.call(); //undefined sum.call(null); //null sum.call(undefined); //undefinedCe qui suit utilise la méthode call pour implémenter une méthode de conversion d'un tableau de classe en un tableau :
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; }Les méthodes similaires à l'appel incluent les méthodes apply et bind Voici un bref résumé. La méthode apply fonctionne exactement de la même manière que la méthode call, sauf que la forme de transmission des paramètres est différente. apply enveloppe les paramètres de la fonction dans un tableau :
function sum(num1, num2) { console.log(num2 + num1); console.log(this); } sum.apply(null,[100,200]);La liaison. La méthode est également utilisée pour modifier le mot-clé this, mais il ne change que le point de this et n'exécute pas immédiatement la fonction qui appelle this.
function sum(num1, num2) { console.log(num2 + num1); console.log(this); } var obj = {name : 'zx'} var temp = sum.bind(obj); //temp已经是被改变了this的函数 temp(100,200); //当我们需要的时候才执行 //或者像这样处理 var temp = sum.bind(null, 100, 200); temp();la méthode bind incarne l'idée de prétraitement en js. 2. Tri approfondiNous savons que la méthode
des tableaux ne peut trier que les tableaux inférieurs à 10. S'il y a des nombres supérieurs à 10 dans le tableau qui doivent être triés, nous devons transmettre la fonction de rappel à la méthode sort
La méthode courante ressemble à ceci : sort
ary.sort(function (a,b) { return a - b; });De cette façon, le le tableau peut être trié par ordre croissant. Alors quel est le principe de ce tri ? Pour les deux paramètres transmis :
représente l'élément actuel dans le tableau trouvé, et a
représente l'élément après l'élément actuel. b
: Si a est supérieur à b, le résultat est renvoyé et a et b échangent leurs positions. Si a est plus petit que b, alors les positions de a et b restent inchangées. Il s'agit d'un tri ascendant return a -b
: Si b est supérieur à a, renvoie le résultat et a et b échangent leurs positions. Si a est plus petit que b, alors les positions de a et b restent inchangées. C'est par ordre décroissantreturn b -a
var persons = [{ name:'dawei', age:55 },{ name:'ahung', age:3 },{ name:'maomi', age:2 },{ name:'heizi', age:78 },{ name:'afu', age:32 }];C'est en fait très simple :
ary.sort(function(a,b){ return a.age - b.age; });Si vous triez par nom, la méthode
de la chaîne intervient : localeCompare()
ary.sort(function(a,b){ return a.name.localeCompare(b.name); });
Cette méthode comparera les lettres des deux chaînes. Si la première lettre de la chaîne précédente apparaît avant le premier caractère de cette dernière chaîne parmi les 24 lettres anglaises, il est déterminé que La première chaîne est petite, retournez name.localeCompare()
. Si elle apparaît plus tard, la première chaîne est considérée comme plus grande et 1 est renvoyé. Si les caractères comparés sont égaux. Comparez ensuite le caractère suivant. -1
//ary为需要添加到页面中的数据数组 var op = document.getElementById("box");//获取容器 var myUl = op.getElementsByTagName("ul")[0];//获取列表 var arrLength = ary.length; for (var i = 0;i < arrLength ; i ++) { //动态创建元素 var oli = document.createElement("li"); oli.innerHTML = '<span>' + (i + 5) + '</span>' + ary[i].title; myUl.appendChild(oli);//动态添加元素 }Chaque ajout provoquera une redistribution du DOM. Si la quantité de données est trop importante, cela affectera sérieusement les performances. Concernant la redistribution et le redessin du DOM, je vous recommande de lire cet article : http://www.css88.com/archives...Épissage de chaînes :
var str = ""; for(var i=0; i<ary.length; i++){ str += '<li>'; str += '<span>'; str += (i+5); str += '</span>'; str += ary[i].title; str += '</li>'; } myUl.innerHTML += str;Bien que cette méthode ne provoque qu'une seule redistribution, elle supprimera tous les événements et attributs des éléments d'origine. Si nous ajoutons un événement pour la balise li dans la liste lorsque la souris entre et que l'arrière-plan change de couleur, cette méthode invalidera cet événement. Afin de résoudre les problèmes causés par les deux méthodes de liaison de données ci-dessus, nous utilisons des fragments de document pour ajouter des données.
var frg = document.createDocumentFragment();//创建文档碎片 for (var i =0; i <ary.length ;i ++ ){ var li = document.createElement("li"); li.innerHTML = '<span>' + ( i + 5 ) + '</span>' + ary[i].title; frg.appendChild(li);//将数据动态添加至文档碎片中 } myUl.appendChild(frg); //将数据一次性添加到页面中 frg = null; //释放内存Cela ne provoquera qu'une seule redistribution du DOM et conservera les événements existants d'origine.
DOM映射机制:所谓映射,就是指两个元素集之间元素相互“对应”的关系。页面中的标签集合和在JS中获取到的元素对象(元素集合)就是这样的关系。如果页面中的HTML标签结构发送变化,那么集合中对应的内容也会跟着自动改变。
<ul id="myul"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul>
对于这样一个列表使用下列脚本:
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列表会变成下面这样:
<ul id="myul"> <li>5</li> <li>4</li> <li>3</li> <li>2</li> <li>1</li> </ul>
我们看到列表的长度依然是5,只是位置颠倒了。这是因为每个li标签和JS中获取的标签对象存在一个对应关系,当某个标签被重新插入到页面中时,页面中对应的标签会移动到插入的位置。这就是DOM映射。
之所以使用动态获取数据,是为了使用文档碎片绑定数据。
var res = ''; //声明一个全局变量,接收数据 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);
此时数据就保存在了res
这个全局变量之中。
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);
这里涉及的点较多
//为两列添加点击事件 for (let i = 0; i < ths.length; i++) { let curTh = ths[i]; curTh.sortFlag = -1; //用于对列进行升降序排列 curTh.index = i; //记录当前点击列的索引,便于排序操作 if (curTh.className == 'sort') { curTh.onclick = function() { sort.call(this); //改变排序函数内this的指向,让其指向当前点击列 } } } //排序方法 function sort() { //对数组元素进行排序 let target = this; //这里将this取出,因为在sort方法里需要使用该this,但是sort方法里的this是调用方法的数组 this.sortFlag *= -1; //1 代表升序 -1代表降序 let ary = listToArray(bodyTrs); //获取body数据 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; } }); //把排好序的数组重新写入页面 let frg = document.createDocumentFragment(); for (let i = 0; i < ary.length; i++) { rg.appendChild(ary[i]); } tbody.appendChild(frg); frg = null; //点击某列时,要将其他列的排序标志恢复为-1,让下次再点击任意一个标签时都是默认是升序排列 for (let i = 0; i < ths.length; i++) { if (ths[i] != this) { ths[i].sortFlag = -1; } } }
表格排序应用很常见,在面试中也会有这样的题目。这个小案例做下来,受益匪浅。这是我在学习的某峰学院的JS课程中的一个案例,如果对JS掌握不扎实的同学,欢迎保存:链接: https://pan.baidu.com/s/1jHVy8Uq 密码: v4jk
。如果链接失效,加Q群领取:154658901
。
J'ai récemment appris le tri de tableaux en JS. Je ne m'attendais pas à ce que le tri de tableaux discret implique en fait de nombreux points de connaissances JS. Enregistrez ce processus d’apprentissage ici. J'espère que cela aidera tout le monde aussi.
Le tri complet des tableaux implique les points de connaissances suivants :
la méthode d'appel utilise la
méthode de tri en profondeur
Liaison de données
Mappage DOM
Ce qui suit résume ces points de connaissances en détail et les combine enfin Les points de connaissance implémentent le cas de tri de table suivant.
Code source complet du cas : https://github.com/daweihe/JS...
. Toute fonction que nous définissons peut être considérée comme une instance de la classe Function.prototype
. Ensuite, vous pouvez trouver le prototype de la classe via l'attribut Function
de l'instance. N'importe quelle fonction peut appeler des méthodes telles que __proto__
et call
. apply
var obj = { name : 'JS' } function testCall () { console.log(this); } testCall.call( obj ); // {name: "JS"}Tout d'abord, la fonction
trouve la méthode d'appel via le mécanisme de recherche en chaîne du prototype et l'exécute pendant le processus d'exécution, l'appel. La méthode place la méthode d'appel dans l'instance de fonction. Celle-ci est remplacée par le premier paramètre de l'appel, puis la fonction d'instance de la méthode d'appel est appelée et exécutée. testCall
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,相当于执行参数Lorsque la méthode d'appel est exécutée, le premier paramètre de la méthode d'appel est utilisé pour changer cela, et à partir du deuxième paramètre sont les paramètres passés à la fonction appelant call. En mode non strict, si aucun paramètre n'est transmis à la méthode d'appel, ou si null ou undefined est passé, cela pointera vers
. window
sum.call(); //window sum.call(null); //window sum.call(undefined); //windowL'exécution de l'appel en mode strict est différente de celle en mode non strict :
sum.call(); //undefined sum.call(null); //null sum.call(undefined); //undefinedCe qui suit utilise la méthode call pour implémenter une méthode de conversion d'un tableau de classe en un tableau :
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; }Les méthodes similaires à l'appel incluent les méthodes apply et bind Voici un bref résumé. La méthode apply fonctionne exactement de la même manière que la méthode call, sauf que la forme de transmission des paramètres est différente. apply enveloppe les paramètres de la fonction dans un tableau :
function sum(num1, num2) { console.log(num2 + num1); console.log(this); } sum.apply(null,[100,200]);La liaison. La méthode est également utilisée pour modifier le mot-clé this, mais il ne change que le point de this et n'exécute pas immédiatement la fonction qui appelle this.
function sum(num1, num2) { console.log(num2 + num1); console.log(this); } var obj = {name : 'zx'} var temp = sum.bind(obj); //temp已经是被改变了this的函数 temp(100,200); //当我们需要的时候才执行 //或者像这样处理 var temp = sum.bind(null, 100, 200); temp();la méthode bind incarne l'idée de prétraitement en js. 2. Tri approfondiNous savons que la méthode
des tableaux ne peut trier que les tableaux inférieurs à 10. S'il y a des nombres supérieurs à 10 dans le tableau qui doivent être triés, nous devons transmettre la fonction de rappel à la méthode sort
La méthode courante ressemble à ceci : sort
ary.sort(function (a,b) { return a - b; });De cette façon, le le tableau peut être trié par ordre croissant. Alors quel est le principe de ce tri ? Pour les deux paramètres transmis :
représente l'élément actuel dans le tableau trouvé, et a
représente l'élément après l'élément actuel. b
: Si a est supérieur à b, le résultat est renvoyé et a et b échangent leurs positions. Si a est plus petit que b, alors les positions de a et b restent inchangées. Il s'agit d'un tri ascendant return a -b
: Si b est supérieur à a, renvoie le résultat et a et b échangent leurs positions. Si a est plus petit que b, alors les positions de a et b restent inchangées. C'est par ordre décroissantreturn b -a
var persons = [{ name:'dawei', age:55 },{ name:'ahung', age:3 },{ name:'maomi', age:2 },{ name:'heizi', age:78 },{ name:'afu', age:32 }];C'est en fait très simple :
ary.sort(function(a,b){ return a.age - b.age; });Si vous triez par nom, la méthode
de la chaîne intervient : localeCompare()
ary.sort(function(a,b){ return a.name.localeCompare(b.name); });
Cette méthode comparera les lettres des deux chaînes. Si la première lettre de la chaîne précédente apparaît avant le premier caractère de cette dernière chaîne parmi les 24 lettres anglaises, il est déterminé que La première chaîne est petite, retournez name.localeCompare()
. Si elle apparaît plus tard, la première chaîne est considérée comme plus grande et 1 est renvoyé. Si les caractères comparés sont égaux. Comparez ensuite le caractère suivant. -1
//ary为需要添加到页面中的数据数组 var op = document.getElementById("box");//获取容器 var myUl = op.getElementsByTagName("ul")[0];//获取列表 var arrLength = ary.length; for (var i = 0;i < arrLength ; i ++) { //动态创建元素 var oli = document.createElement("li"); oli.innerHTML = '<span>' + (i + 5) + '</span>' + ary[i].title; myUl.appendChild(oli);//动态添加元素 }Chaque ajout provoquera une redistribution du DOM. Si la quantité de données est trop importante, cela affectera sérieusement les performances. Concernant la redistribution et le redessin du DOM, je vous recommande de lire cet article : http://www.css88.com/archives...Épissage de chaînes :
var str = ""; for(var i=0; i<ary.length; i++){ str += '<li>'; str += '<span>'; str += (i+5); str += '</span>'; str += ary[i].title; str += '</li>'; } myUl.innerHTML += str;Bien que cette méthode ne provoque qu'une seule redistribution, elle supprimera tous les événements et attributs des éléments d'origine. Si nous ajoutons un événement pour la balise li dans la liste lorsque la souris entre et que l'arrière-plan change de couleur, cette méthode invalidera cet événement. Afin de résoudre les problèmes causés par les deux méthodes de liaison de données ci-dessus, nous utilisons des fragments de document pour ajouter des données.
var frg = document.createDocumentFragment();//创建文档碎片 for (var i =0; i <ary.length ;i ++ ){ var li = document.createElement("li"); li.innerHTML = '<span>' + ( i + 5 ) + '</span>' + ary[i].title; frg.appendChild(li);//将数据动态添加至文档碎片中 } myUl.appendChild(frg); //将数据一次性添加到页面中 frg = null; //释放内存Cela ne provoquera qu'une seule redistribution du DOM et conservera les événements existants d'origine.
DOM映射机制:所谓映射,就是指两个元素集之间元素相互“对应”的关系。页面中的标签集合和在JS中获取到的元素对象(元素集合)就是这样的关系。如果页面中的HTML标签结构发送变化,那么集合中对应的内容也会跟着自动改变。
<ul id="myul"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul>
对于这样一个列表使用下列脚本:
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列表会变成下面这样:
<ul id="myul"> <li>5</li> <li>4</li> <li>3</li> <li>2</li> <li>1</li> </ul>
我们看到列表的长度依然是5,只是位置颠倒了。这是因为每个li标签和JS中获取的标签对象存在一个对应关系,当某个标签被重新插入到页面中时,页面中对应的标签会移动到插入的位置。这就是DOM映射。
之所以使用动态获取数据,是为了使用文档碎片绑定数据。
var res = ''; //声明一个全局变量,接收数据 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);
此时数据就保存在了res
这个全局变量之中。
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);
这里涉及的点较多
//为两列添加点击事件 for (let i = 0; i < ths.length; i++) { let curTh = ths[i]; curTh.sortFlag = -1; //用于对列进行升降序排列 curTh.index = i; //记录当前点击列的索引,便于排序操作 if (curTh.className == 'sort') { curTh.onclick = function() { sort.call(this); //改变排序函数内this的指向,让其指向当前点击列 } } } //排序方法 function sort() { //对数组元素进行排序 let target = this; //这里将this取出,因为在sort方法里需要使用该this,但是sort方法里的this是调用方法的数组 this.sortFlag *= -1; //1 代表升序 -1代表降序 let ary = listToArray(bodyTrs); //获取body数据 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; } }); //把排好序的数组重新写入页面 let frg = document.createDocumentFragment(); for (let i = 0; i < ary.length; i++) { rg.appendChild(ary[i]); } tbody.appendChild(frg); frg = null; //点击某列时,要将其他列的排序标志恢复为-1,让下次再点击任意一个标签时都是默认是升序排列 for (let i = 0; i < ths.length; i++) { if (ths[i] != this) { ths[i].sortFlag = -1; } } }
以上内容就是原生JS实现表格排序,希望能帮助到大家。
jquery中tablesorter表格排序组件是如何使用的?
js表格排序实例详解(支持int,float,date,string四种数据类型)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!