Maison >interface Web >js tutoriel >Native JS implémente le tri des tables

Native JS implémente le tri des tables

小云云
小云云original
2017-12-06 14:52:032965parcourir

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.
Native JS implémente le tri des tables

Code source complet du cas : https://github.com/daweihe/JS...

1. 🎜 >

1. Utilisation de la méthode d'appel

La fonction de la méthode d'appel est de changer le pointeur this dans la méthode.

call Cette méthode est définie dans

. 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

Regardons d'abord un exemple :

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

Regardez deux questions :

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); //window
L'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); //undefined
Ce 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 : &#39;zx&#39;}

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 approfondi

Nous 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

Après avoir compris les principes de base, comment trier un tel tableau bidimensionnel par âge ?

var persons = [{
    name:&#39;dawei&#39;,
    age:55
},{
    name:&#39;ahung&#39;,
    age:3
},{
    name:&#39;maomi&#39;,
    age:2
},{
    name:&#39;heizi&#39;,
    age:78
},{
    name:&#39;afu&#39;,
    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

Cette méthode est très pratique et est souvent utilisée pour trier par nom de famille. Pour les caractères chinois, cette méthode convertira automatiquement les caractères chinois en Pinyin chinois pour comparaison.

3. Liaison de données

En js, la liaison dynamique ou l'épissage de chaînes est généralement utilisé pour réaliser la liaison de données.

Liaison dynamique :

//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 = &#39;<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 += &#39;<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.

4、DOM映射

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映射。

二、实现表格排序

1、使用ajax获取数据

之所以使用动态获取数据,是为了使用文档碎片绑定数据。

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这个全局变量之中。

2、使用文档碎片绑定数据

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、对表格进行排序

这里涉及的点较多

//为两列添加点击事件
for (let i = 0; i < ths.length; i++) {
    let curTh = ths[i];
    curTh.sortFlag = -1; //用于对列进行升降序排列
    curTh.index = i; //记录当前点击列的索引,便于排序操作
    if (curTh.className == &#39;sort&#39;) {
        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.
Native JS implémente le tri des tables

Code source complet du cas : https://github.com/daweihe/JS...

1. 🎜 >

1. Utilisation de la méthode d'appel

La fonction de la méthode d'appel est de changer le pointeur this dans la méthode.

call Cette méthode est définie dans

. 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

Regardons d'abord un exemple :

var obj = {
    name : &#39;JS&#39;
}

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

Regardez deux questions :

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); //window
L'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); //undefined
Ce 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 : &#39;zx&#39;}

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 approfondi

Nous 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

Après avoir compris les principes de base, comment trier un tel tableau bidimensionnel par âge ?

var persons = [{
    name:&#39;dawei&#39;,
    age:55
},{
    name:&#39;ahung&#39;,
    age:3
},{
    name:&#39;maomi&#39;,
    age:2
},{
    name:&#39;heizi&#39;,
    age:78
},{
    name:&#39;afu&#39;,
    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

Cette méthode est très pratique et est souvent utilisée pour trier par nom de famille. Pour les caractères chinois, cette méthode convertira automatiquement les caractères chinois en Pinyin chinois pour comparaison.

3. Liaison de données

En js, la liaison dynamique ou l'épissage de chaînes est généralement utilisé pour réaliser la liaison de données.

Liaison dynamique :

//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 = &#39;<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 += &#39;<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.

4、DOM映射

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映射。

二、实现表格排序

1、使用ajax获取数据

之所以使用动态获取数据,是为了使用文档碎片绑定数据。

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这个全局变量之中。

2、使用文档碎片绑定数据

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、对表格进行排序

这里涉及的点较多

//为两列添加点击事件
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学习总结经典小案例之表格排序

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn