首页 > 解决方案 > ES5 Javascript:从 2 个选择器中获取唯一值并添加/更新到数组

问题描述

在我的网页上有 2 个选择器 - 一个是选项卡,另一个是下拉菜单。根据用户对选项卡和下拉菜单的点击,我得到点击值并将其推送到数组中。数组中最多有 2 个元素 - 两个元素都需要分别是映射到选项卡和下拉选择的唯一值:

Tag1 -> value from Tab selection
Tag2 -> value from drop down

要将数组添加/更新到特定位置,我使用了Array.prototype.splice()

我设法从选项卡和数组中的下拉列表中推送选择值。但是,我遇到了一些问题场景,如下所述。

请看下面的测试代码:

// Get all tabs
var tabs = document.querySelectorAll('.tab')
// Get select element
var select = document.querySelector('select')
// Create tag array
var tags = []
var tagText = document.querySelector('#tags')

// Register click event listeners for tabs
if (tabs.length > 0) {
  tabs.forEach(function (tab) {
    tab.addEventListener('click', handleTabClick, true)
  })
}

// Register click event listener for select element
if (select) {
  select.addEventListener('change', handleSelectChange, true)
}

// Handle tab click
function handleTabClick(e) {
  var currentElement = e.target

  // Remove all active modifiers
  tabs.forEach(function (tab) {
    tab.classList.remove('active')
  })

  // Apply the active modifer to the current element
  currentElement.classList.add('active')

  // Update the UI showing the correct pane by ID
  var id = currentElement.dataset.targetPane

  if (id != 'tab-all') {
    // Add selected id to array
    tags.splice(0, 1, id)
  } else {
    tags.splice(0, 1, '')
  }

  tagText.innerHTML = tags
}

// Handle select change
function handleSelectChange(e) {
  var id = e.target.value

  if (id != 'all') {
    // Add selected id to array
    tags.splice(1, 1, id)
  } else {
    tags.splice(1, 1, '')
  }

  tagText.innerHTML = tags
}
.tabs {
  padding-left: 0;
  list-style-type: none;
  display: flex;
}

.tab {
  flex: 1;
  text-align: center;
  padding: 10px;
  cursor: pointer;
  color: #000000;
  border: 1px solid #d1d1d1;
}

.active {
  border-bottom: 3px solid red;
}
Tab options (1st in tags array): Tag 1
<ul class="tabs">
  <li class="tab active" data-target-pane="tab-all">All
  </li>
  <li class="tab" data-target-pane="finance">
    Finance
  </li>
  <li class="tab" data-target-pane="energy">
    Energy
  </li>
</ul>
Dropdown options (2nd in tags array): Tag 2
<label class="select">
  <select>
    <option value="all" selected="">All</option>
    <option value="whitepaper">Whitepaper</option>
    <option value="articles">Articles</option>
    <option value="video">Video</option>
  </select>
</label>
<p>Return tags array: <b><span id="tags"></span></b></p>
<p>Tag 1 -> value from Tab<br>
Tag 2 -> value from dropdown<br><br>Expect the tags array output to always be [Tag 1 , Tag 2].<br>Max 2 item in array. If user selected "All", empty the previous selection within the same Tag (1 or 2) array location.</p>

问题场景(不良结果)

1) 如果用户首先选择一个下拉选项 (Tag2),然后选择另一个下拉选项 (Tag2):Tags 数组则有 [Tag2, Tag2]。预期:[Tag2]

2) 如果用户首先选择一个下拉选项 (Tag2),然后选择一个选项卡 (Tag1):Tags 数组首先具有 [Tag2],然后被 [Tag1] 替换。预期:[Tag2,Tag1]

3)如果用户首先选择了一个下拉选项(Tag2),然后选择了另一个下拉选项(Tag2),最后选择了下拉值“All”(Tag2):Tags数组首先有[Tag2,Tag2]和“All " 选择它变成 [Tag2,]。预期:第一个 [Tag2] 并选择“全部”,[]

理想场景

1) 如果用户在选择下拉选项 (Tag2) 之前首先选择了一个选项卡 (Tag1):标签数组应该得到 [Tag1, Tag2]。

2) 如果用户选择“全部”,则清空同一标签(1 或 2)数组位置中的先前选择。例如,用户首先选择了一个选项卡 (Tag1),然后选择选项卡“全部”。标签数组获取 []。如果用户首先选择了一个选项卡 (Tag1) 并选择了一个下拉选项 (Tag2),然后选择了下拉“全部”值。标签数组应该变成 [Tag1]

我希望标签数组是以下之一:

1) 数组中最多 2 项 -> [Tag1 , Tag2] 或 [Tag2 , Tag1]

2) 单个数组元素 [Tag1] 或 [Tag2]

但它不应该有 [Tag1, Tag1] 或 [Tag2, Tag2]

简而言之,数组应该具有对应于选项卡选择和下拉选择的唯一值。

标签: arraysecmascript-5splice

解决方案


由于您有时需要 [Tag 1, Tag 2] 和其他时候 [Tag 2, Tag 1] 的结果,因此最好记住您上次将 Tag 1 选择存储在哪个插槽中,这样您就知道两者中的哪一个取代。

我将假设最后做出的选择也将始终是数组中的最后一个值。

所以我引入了tabIndex0 或 1 的变量。另外,我已经修改了代码,以便它首先从数组中删除当前值(从可以派生自的索引tabIndex),然后将所选值推送到末尾数组,tabIndex同时更新。

// Get all tabs
var tabs = document.querySelectorAll('.tab')
// Get select element
var select = document.querySelector('select')
// Create tag array
var tags = []
var tagText = document.querySelector('#tags')
var tabIndex = 0;

// Register click event listeners for tabs
tabs.forEach(function (tab) {
    tab.addEventListener('click', handleTabClick, true)
})

// Register click event listener for select element
if (select) {
  select.addEventListener('change', handleSelectChange, true)
}

// Handle tab click
function handleTabClick(e) {
    var currentElement = e.target

    // Remove all active modifiers
    tabs.forEach(function (tab) {
        tab.classList.remove('active')
    })

    // Apply the active modifer to the current element
    currentElement.classList.add('active')

    // Update the UI showing the correct pane by ID
    var id = currentElement.dataset.targetPane

    tags.splice(tabIndex, 1)
    if (id != 'tab-all') {
        // Add selected id to array
        tabIndex = tags.length
        tags.push(id)
    }
    tagText.textContent = JSON.stringify(tags)
}

// Handle select change
function handleSelectChange(e) {
    var id = e.target.value

    tags.splice(1-tabIndex, 1)
    if (id != 'all') {
        // Add selected id to array
        tabIndex = 1 - tags.length;
        tags.push(id)
    }

    tagText.textContent = JSON.stringify(tags)
}
.tabs {
  padding-left: 0;
  list-style-type: none;
  display: flex;
}

.tab {
  flex: 1;
  text-align: center;
  padding: 10px;
  cursor: pointer;
  color: #000000;
  border: 1px solid #d1d1d1;
}

.active {
  border-bottom: 3px solid red;
}
Tab options (1st in tags array): Tag 1
<ul class="tabs">
    <li class="tab active" data-target-pane="tab-all">All</li>
    <li class="tab" data-target-pane="finance">Finance</li>
    <li class="tab" data-target-pane="energy">Energy</li>
</ul>
Dropdown options (2nd in tags array): Tag 2
<label class="select">
  <select>
    <option value="all" selected="">All</option>
    <option value="whitepaper">Whitepaper</option>
    <option value="articles">Articles</option>
    <option value="video">Video</option>
  </select>
</label>
<p>Return tags array: <b><span id="tags"></span></b></p>
<p>Tag 1 -> value from Tab<br>
Tag 2 -> value from dropdown<br><br>Expect the tags array output to always be [Tag 1 , Tag 2].<br>Max 2 item in array. If user selected "All", empty the previous selection within the same Tag (1 or 2) array location.</p>


推荐阅读