javascript - 转换脚本以独立处理多个表

标签 javascript loops foreach nodelist htmlcollection

我有两个脚本,当页面包含单个表时它们可以完美工作。但是,现在我需要将多个支持相同功能的表放在同一页面上。

我需要一些帮助,将这两个脚本转换为在同一页面上使用多个表,同时保持相同的功能。

第一个脚本称为“TABLE DATA STATES”。 第二个脚本称为“SORT TABLE DATA”。

当前 JSBin: https://jsbin.com/noyoluhasa/1/edit?html,js,output

// ===================================================================
// =================== TABLE DATA STATES =============================
// ===================================================================

// Answer to my question on Stackoverflow:
// http://stackoverflow.com/questions/33128718/change-data-attribute-on-click-of-html-elements
// JsFiddle: http://jsfiddle.net/pya9jzxm/14

// Get all rows into the array except the <thead> row
var tbody = document.querySelector('tbody');
var trs = tbody.querySelectorAll('tr');
var tr, index = 0, length = trs.length;
// Start the loop
for (; index < length; index++) {
    tr = trs[index];
    // Set the attributes to default state
    tr.setAttribute('data-state', 'enabled');
    tr.setAttribute('data-display', 'collapsed');
    tr.addEventListener('click',
        function () {
            // If its the row alphabet-label, skip it
            if (this.classList.contains('alphabet-label')) {
                return;
            }
            // Conditional logic to make the rows reset after clicking away from highlighted row
            var trIndex = 0, trLength = trs.length, hasExpanded = false;
            var state = 'disabled';
            if (tbody.querySelectorAll('[data-display="expanded"]').length > 0) {
                hasExpanded = true;
                state = 'enabled';
            }
            for (; trIndex < trLength; trIndex++) {
                // Set all rows to disabled on click of any row
                trs[trIndex].setAttribute('data-state', state);
                // Reset the display of all rows
                trs[trIndex].setAttribute('data-display', 'collapsed');
            }
            if (!hasExpanded) {
                // Set the clicked row to active highlighted state
                this.setAttribute('data-state', 'enabled');
                this.setAttribute('data-display', 'expanded');
            }
        }
    );
}


// ===================================================================
// =================== SORT TABLE DATA ===============================
// ===================================================================
// For reference:
// this.setAttribute('data-state', this.getAttribute('data-state').contains === "enabled" ? "disabled" : "enabled");

// Adds icon to clicked <th>
// VanillaJS version - opted for jquery.tablesorter plugin due to flexibility and ease of use
var thsort = document.querySelectorAll('th')
//console.log(thsort);
var sort, sortIndex = 0, sortlength = thsort.length;
for (; sortIndex < sortlength; sortIndex++) {
    sort = thsort[sortIndex];
    //console.log(sort);
    // On click to sort table column, do this:
    sort.addEventListener('click',
        function () {
            var rm, rmIndex = 0;
            for (; rmIndex < sortlength; rmIndex++) {
                rmsort = thsort[rmIndex];
                // Remove sort icon from other <th> elements
                rmsort.classList.remove('sort-key');
                // Add sort icon to this <th>
                this.classList.add('sort-key');
                //console.log(rmsort);


                // Conditional logic to switch asc desc label
                var state = 'asc', prevState = 'desc', hasAsc, prevState;
                if (this.classList.contains('asc')) {
                    hasAsc = true;
                    state = 'desc';
                    prevState = 'asc';

                    //console.log(prevState);

                }
                // Set all rows to disabled on click of any row
                this.classList.add(state);
                this.classList.remove(prevState);

                //if (hasAsc) {
                //    // Set the clicked row to active highlighted state
                //    this.setAttribute('class', state);
                //}
            }
        }
    );
}

除了用 thisTable 替换 tbody 的实例之外,我还尝试将我的代码包装在这段代码中,但脚本仅适用于表的最后一次出现:

var alltables = document.querySelectorAll('tbody')
console.log(alltables);
var thisTable, sortIndex = 0, sortlength = alltables.length;
for (; sortIndex < sortlength; sortIndex++) {
    thisTable = alltables[sortIndex];
    // original code here
}

最佳答案

所以这实际上只是一个范围问题。您在事件处理程序中引用 tbodytrs 的 NodeList,但由于存在多个表,这些值随着时间的推移而发生变化。当这些处理程序被调用并且它看到 tbody 时,它首先检查该变量是否属于其当前作用域的一部分,但事实并非如此。因此它会检查下一个范围,直到找到为止。但它发现的是该变量随时间变化的最后一个值。

解决此问题的最简单方法是将原始代码块包含在函数中,在调用时为其提供作用域,并调用该函数将每个表的当前表传递给它。那么该函数在其作用域中唯一拥有的就是我们关心的表,并且我们在该函数中创建的每个变量(例如 trs )将仅在该特定函数调用的作用域中。

看一下下面的代码并检查 fiddle ,如果您对此有任何疑问,请告诉我。您可以看到,我使用了您对所有表的循环的原始想法,只是我找到了基于 table 类的表,查询了表的 tbody 并将其传递给我们的configureTable 函数。

fiddle :https://jsfiddle.net/rbpc5vfu/

配置表功能:

function configureTable (tbody) {
    var trs = tbody.querySelectorAll('tr');
    var tr, index = 0,
        length = trs.length;
    // Start the loop
    for (; index < length; index++) {
        tr = trs[index];
        // Set the attributes to default state
        tr.setAttribute('data-state', 'enabled');
        tr.setAttribute('data-display', 'collapsed');
        tr.addEventListener('click',
            function() {
                // If its the row alphabet-label, skip it
                if (this.classList.contains('alphabet-label')) {
                    return;
                }
                // Conditional logic to make the rows reset after clicking away from highlighted row
                var trIndex = 0,
                    trLength = trs.length,
                    hasExpanded = false;
                var state = 'disabled';
                if (tbody.querySelectorAll('[data-display="expanded"]').length > 0) {
                    hasExpanded = true;
                    state = 'enabled';
                }
                for (; trIndex < trLength; trIndex++) {
                    // Set all rows to disabled on click of any row
                    trs[trIndex].setAttribute('data-state', state);
                    // Reset the display of all rows
                    trs[trIndex].setAttribute('data-display', 'collapsed');
                }
                if (!hasExpanded) {
                    // Set the clicked row to active highlighted state
                    this.setAttribute('data-state', 'enabled');
                    this.setAttribute('data-display', 'expanded');
                }
            }
        );
    }


    // ===================================================================
    // =================== SORT TABLE DATA ===============================
    // ===================================================================
    // For reference:
    // this.setAttribute('data-state', this.getAttribute('data-state').contains === "enabled" ? "disabled" : "enabled");

    // Adds icon to clicked <th>
    // VanillaJS version - opted for jquery.tablesorter plugin due to flexibility and ease of use
    var thsort = tbody.querySelectorAll('th');
        //console.log(thsort);
    var sort, sortIndex = 0,
        sortlength = thsort.length;
    for (; sortIndex < sortlength; sortIndex++) {
        sort = thsort[sortIndex];
        //console.log(sort);
        // On click to sort table column, do this:
        sort.addEventListener('click',
            function() {
                var rm, rmIndex = 0;
                for (; rmIndex < sortlength; rmIndex++) {
                    rmsort = thsort[rmIndex];
                    // Remove sort icon from other <th> elements
                    rmsort.classList.remove('sort-key');
                    // Add sort icon to this <th>
                    this.classList.add('sort-key');
                    //console.log(rmsort);


                    // Conditional logic to switch asc desc label
                    var state = 'asc',
                        prevState = 'desc',
                        hasAsc, prevState;
                    if (this.classList.contains('asc')) {
                        hasAsc = true;
                        state = 'desc';
                        prevState = 'asc';

                        //console.log(prevState);

                    }
                    // Set all rows to disabled on click of any row
                    this.classList.add(state);
                    this.classList.remove(prevState);

                    //if (hasAsc) {
                    //    // Set the clicked row to active highlighted state
                    //    this.setAttribute('class', state);
                    //}
                }
            }
        );
    }
}

加载时初始化表:

var alltables = document.querySelectorAll('.table');
var thisTable, sortIndex = 0, sortlength = alltables.length;
for (; sortIndex < sortlength; sortIndex++) {
    thisTable = alltables[sortIndex];
    var tbody = thisTable.querySelector('tbody');
    configureTable(tbody);
}

如你所见,如果你看的话,我并没有真正改变太多。我刚刚将您的原始代码包装在功能 block 中。然后从上面窃取循环,找到所有表,每个表找到它的 tbody 并调用我们的新函数将 tbody 传递给它。瞧。范围!

关于javascript - 转换脚本以独立处理多个表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34516684/

相关文章:

php - mysql查找包含大量数据的一行数据

powershell - 如何在powershell中忽略foreach中的空值?

javascript - 如何在 JavaScript 中解码用 PHP 编码的 URL?

javascript - AngularJS解析: in controller "Cannot read property ' goals' of undefined

python动态创建字典的字典

c# - 无法正确使用KeyDown和KeyUp事件? (Visual C# Windows 窗体)

c# - VB.NET 中 "yield return"的等效语法是什么?

javascript - Sails.js 条件模型加载

javascript - 缩放 MapBox GL map 以适合标记集

PHP 5.4 ForEach 疯狂吗?