js 仿window拉选框 / 选中文件

目录

1. window效果

2. 实现思路

1. 元素分析

2. 思路分析

3. 实现拉选框

1. 代码

2. 实现效果 

4. 实现元素选中效果 

1. 获取所有元素的我们需要的属性

2. 判断是否选中了某个元素并改变他的颜色

3. 实现效果

5. 完整代码

 6. 总结


1. window效果

 这里是window11的效果

2. 实现思路

1. 元素分析

1. 只要包含在拉选框内的都会被选中,这样就需要获取拉选框的x,y,height,width和元素的x,y,widht,height来进行组合判断。

2. 获取元素的所需要的属性可以使用getBoundingClientRect方法来获取这个矩形的属性值

3. 图标元素的x,y就等于getBoundingClientRect().x ,getBoundingClientRect().x。widht和height相同的原理

2. 思路分析

1. 拉选框是一个绝对定位的元素,我这里使用div

// css
.box{
  position: absolute;
  background-color: rgba(13, 153, 255, 0.3);
  border: 1px solid rgb(13, 153, 255);
}
// js
const box = document.createElement('div');
box.className = 'box';

2. 给拉选框添加事件

1.mousedown  向body添加box元素并添加move,up事件

function mouseDown(e){
  box.style.width = '0px';
  box.style.height = '0px';
  body.append(box);
  // initPosition 记录初始坐标
  initPosition.x = e.clientX;
  initPosition.y = e.clientY;
  box.style.top = e.clientY + 'px';
  box.style.left = e.clientX + 'px';

  body.addEventListener('mousemove', mouseMove);
  body.addEventListener('mouseup', mouseUp);
}

2.mousemove 初始坐标为定点想象一个象限轴,可以有四个方向移动

function mouseMove(e){
  const {x,y} = initPosition;
  // 设置移动位置
  const moveX = e.clientX;
  const moveY = e.clientY;
  // 计算移动后对应元素宽高
  const width = Math.abs(x - moveX);
  const height = Math.abs(y - moveY);
  // 判断方向及顶点位置
  if(moveX > x && moveY > y){ // 4象限
    box.style.left = x + 'px';
    box.style.top = y + 'px';
  }else if(y > moveY && x < moveX){ // 1象限
    box.style.top = moveY + 'px';
    box.style.left = x + 'px';
  }else if(moveX < x && moveY > y){ // 3象限
    box.style.left = moveX + 'px';
    box.style.top = y + 'px';
  }else if(moveY < y && moveX < x){ // 2象限
    box.style.top = moveY + 'px';
    box.style.left = moveX + 'px';
  }
  requestAnimationFrame(() => {
    box.style.width = width + 'px';
    box.style.height = height + 'px';
  })
}

3.mouseup 鼠标抬起时应该移除box元素和move,up事件

function mouseUp(){
  body.removeChild(box);
  body.removeEventListener('mousemove', mouseMove);
  body.removeEventListener('mouseup', mouseUp);
}

3. 实现拉选框

1. 代码

const body = document.querySelector('body');
const box = document.createElement('div');
box.className = 'box';
body.addEventListener('mousedown', mouseDown);
function mouseDown(e){
  box.style.width = '0px';
  box.style.height = '0px';
  selectArr = [];
  body.append(box);
  initPosition.x = e.clientX;
  initPosition.y = e.clientY;
  box.style.top = e.clientY + 'px';
  box.style.left = e.clientX + 'px';
  body.addEventListener('mousemove', mouseMove);
  body.addEventListener('mouseup', mouseUp);
}
function mouseMove(e){
  const {x,y} = initPosition;
  // 设置移动位置
  const moveX = e.clientX;
  const moveY = e.clientY;
  // 计算移动后对应元素宽高
  const width = Math.abs(x - moveX);
  const height = Math.abs(y - moveY);
  // 判断方向及顶点位置
  if(moveX > x && moveY > y){ // 4
    box.style.left = x + 'px';
    box.style.top = y + 'px';
  }else if(y > moveY && x < moveX){ // 1
    box.style.top = moveY + 'px';
    box.style.left = x + 'px';
  }else if(moveX < x && moveY > y){ // 3
    box.style.left = moveX + 'px';
    box.style.top = y + 'px';
  }else if(moveY < y && moveX < x){ // 2
    box.style.top = moveY + 'px';
    box.style.left = moveX + 'px';
  }
  requestAnimationFrame(() => {
    box.style.width = width + 'px';
    box.style.height = height + 'px';
    // isSelect();
  })
}
function mouseUp(){
  body.removeChild(box);
  body.removeEventListener('mousemove', mouseMove);
  body.removeEventListener('mouseup', mouseUp);
}

2. 实现效果 

4. 实现元素选中效果 

1. 获取所有元素的我们需要的属性

function initSelectBox(){
  const domArr = document.querySelectorAll('.select');
  for(let i = 0; i < domArr.length; i++){
    const item = domArr[i];
    const obj = {
      dom:item,
      x:item.getBoundingClientRect().left,
      y:item.getBoundingClientRect().top,
      width:item.getBoundingClientRect().width,
      height:item.getBoundingClientRect().height,
    }
    select.push(obj);
  }
}

2. 判断是否选中了某个元素并改变他的颜色

function isSelect(){
  const {width, height, left, top} = box.getBoundingClientRect();
  for(let i = 0; i < select.length; i++){
    const item = select[i];
    if(
      left < item.x + item.width &&
      item.x < left + width &&
      top < item.y + item.height &&
      item.y < top + height
    ){
      if(!selectArr.find(items => items === item)){ // 如果selectArr里有item元素则不push
        selectArr.push(item);
      }
      item.dom.style.backgroundColor = 'rgba(13, 153, 255, 0.3)';
    }else{
      if(selectArr.find(items => items === item)){ // 如果能找到item元素则从selectArr里删除该元素
        selectArr.splice(selectArr.findIndex(items => items === item), 1);
      }
      item.dom.style.backgroundColor = 'rgba(122, 145, 161)';
    }
  }
}

3. 实现效果

5. 完整代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    *{
      margin: 0;
      padding: 0;
    }
    body{
      width: 100vw;
      height: 100vh;
      position: relative;
    }
    .box{
      position: absolute;
      background-color: rgba(13, 153, 255, 0.3);
      border: 1px solid rgb(13, 153, 255);
    }
    .container{
      width: 100vw;
      height: 100vh;
    }
    .item{
      display: flex;
    }
    .select{
      cursor: pointer;
      margin: 100px;
      width: 100px;
      height: 100px;
      min-width: 100px;
      min-height: 100px;
      background-color: rgba(122, 145, 161, 1);
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="item">
      <div class="select"></div>
      <div class="select"></div>
      <div class="select"></div>
      <div class="select"></div>
    </div>
    <div class="item">
      <div class="select"></div>
      <div class="select"></div>
      <div class="select"></div>
      <div class="select"></div>
    </div>
  </div>
  <script>
    const body = document.querySelector('body');
    const box = document.createElement('div');
    box.className = 'box';
    const select = [];
    let selectArr = []
    const initPosition = {
      x: 0,
      y: 0
    }
    initSelectBox();
    function initSelectBox(){
      const domArr = document.querySelectorAll('.select');
      for(let i = 0; i < domArr.length; i++){
        const item = domArr[i];
        const obj = {
          dom:item,
          x:item.getBoundingClientRect().left,
          y:item.getBoundingClientRect().top,
          width:item.getBoundingClientRect().width,
          height:item.getBoundingClientRect().height,
        }
        select.push(obj);
      }
    }
    body.addEventListener('mousedown', mouseDown);
    function mouseDown(e){
      box.style.width = '0px';
      box.style.height = '0px';
      selectArr = [];
      body.append(box);
      initPosition.x = e.clientX;
      initPosition.y = e.clientY;
      box.style.top = e.clientY + 'px';
      box.style.left = e.clientX + 'px';

      body.addEventListener('mousemove', mouseMove);
      body.addEventListener('mouseup', mouseUp);
    }
    function mouseMove(e){
      const {x,y} = initPosition;
      // 设置移动位置
      const moveX = e.clientX;
      const moveY = e.clientY;
      // 计算移动后对应元素宽高
      const width = Math.abs(x - moveX);
      const height = Math.abs(y - moveY);
      // 判断方向及顶点位置
      if(moveX > x && moveY > y){ // 4
        box.style.left = x + 'px';
        box.style.top = y + 'px';
      }else if(y > moveY && x < moveX){ // 1
        box.style.top = moveY + 'px';
        box.style.left = x + 'px';
      }else if(moveX < x && moveY > y){ // 3
        box.style.left = moveX + 'px';
        box.style.top = y + 'px';
      }else if(moveY < y && moveX < x){ // 2
        box.style.top = moveY + 'px';
        box.style.left = moveX + 'px';
      }
      requestAnimationFrame(() => {
        box.style.width = width + 'px';
        box.style.height = height + 'px';
        isSelect();
      })
    }
    function mouseUp(){
      console.log(selectArr)
      body.removeChild(box);
      body.removeEventListener('mousemove', mouseMove);
      body.removeEventListener('mouseup', mouseUp);
    }
    // 判断box是否选中元素
    function isSelect(){
      const {width, height, left, top} = box.getBoundingClientRect();
      for(let i = 0; i < select.length; i++){
        const item = select[i];
        if(
          left < item.x + item.width &&
          item.x < left + width &&
          top < item.y + item.height &&
          item.y < top + height
        ){
          if(!selectArr.find(items => items === item)){
            selectArr.push(item);
          }
          item.dom.style.backgroundColor = 'rgba(13, 153, 255, 0.3)';
        }else{
          if(selectArr.find(items => items === item)){
            selectArr.splice(selectArr.findIndex(items => items === item), 1);
          }
          item.dom.style.backgroundColor = 'rgba(122, 145, 161)';
        }
      }
    }

  </script>
</body>
</html>

 6. 总结

大概的实现思路就是这样,网络上也会有更优的方法,我写的还一点小bug如果大家发现并能修复可以告诉博主,感谢!!!

<think>我们之前已经实现了在孙子div的左上角添加复选框,现在需要实现当复选框被点击时,将对应的div数据存入一个列表中。步骤:1.我们需要一个全局的列表(数组)来存储被选中的div的数据。2.给每个复选框添加点击事件监听器,当点击时,判断复选框选中状态,如果选中,则将对应的div数据添加到列表中;如果取消选中,则从列表中移除。3.关于“数据”:根据需求,我们需要存储什么样的数据?可能是div的内容、id、或者其他自定义属性。这里假设我们需要存储整个div元素(或者其关键数据),具体取决于实际应用。考虑到实际应用,通常我们不会存储整个DOM元素,而是存储能够标识该div的数据(比如id,或者从div中提取的特定数据属性)。这里我们假设每个孙子div有一个唯一标识(id),如果没有,我们在创建复选框时已经生成一个(存储在checkbox.dataset.targetId)。另外,我们可能还需要存储一些其他数据,比如div的内容或者自定义数据属性。由于用户需求是“将对应div的数据存入列表中”,但未明确具体数据,我们可以先存储一个包含id和div内容的对象。实现:修改复选框的创建代码,添加事件监听:```javascriptcheckbox.addEventListener('change',function(){if(this.checked){//添加到列表//构建数据对象constdata={id:grandchild.id||this.dataset.targetId,//优先使用div的id,如果没有则用我们生成的content:grandchild.innerText,//或者根据需求提取特定内容element:grandchild//存储DOM元素引用,但注意:如果元素被删除,这里可能会成为过时引用};selectedItems.push(data);}else{//从列表中移除//根据id查找并移除constidToRemove=grandchild.id||this.dataset.targetId;selectedItems=selectedItems.filter(item=>item.id!==idToRemove);}});```注意:我们使用了一个全局数组`selectedItems`,需要在脚本顶部声明:```javascriptletselectedItems=[];```但是,由于我们可能在一个页面中有多个容器,或者需要避免全局污染,我们可以将`selectedItems`放在闭包中。另外,考虑到性能,当div被删除时,我们可能还需要从`selectedItems`中移除对应的项。这可以通过MutationObserver来监听孙子div的移除,但这里我们先不实现,因为用户提到“table1中的操作项有一个删除”,所以删除操作可能由用户的其他代码触发,我们可以在删除时同步更新`selectedItems`。另一种思路:我们可以不存储整个对象,而是存储一个引用,然后通过复选框的状态来动态获取选中项。但是,如果需要在多处使用选中列表,存储一个数组会更方便。考虑到代码组织,我们可以将整个功能封装在一个模块中,避免全局变量。修改后的完整代码框架:```javascript(function(){letselectedItems=[];//存储选中项functionprocessGrandchildren(container){constchildren=container.querySelectorAll(':scope>div');children.forEach(child=>{constgrandchildren=child.querySelectorAll(':scope>div');grandchildren.forEach(grandchild=>{if(!grandchild.querySelector('.auxo-dynamic-checkbox')){//...之前的定位代码...//创建复选框constcheckbox=document.createElement('input');checkbox.type='checkbox';checkbox.className='auxo-dynamic-checkbox';consttargetId=grandchild.id||generateUniqueId();//如果grandchild没有id,我们给它设置一个,以便后续引用if(!grandchild.id){grandchild.id=targetId;}checkbox.dataset.targetId=targetId;//...组装复选框容器...//添加事件监听checkbox.addEventListener('change',function(){if(this.checked){//添加到选中列表selectedItems.push({id:targetId,element:grandchild,//可以添加其他需要的数据content:grandchild.textContent.trim()//示例:存储文本内容});}else{//从选中列表中移除selectedItems=selectedItems.filter(item=>item.id!==targetId);}//可以在这里打印选中项,或者触发其他操作console.log(selectedItems);});//将复选框容器添加到grandchildgrandchild.appendChild(checkboxContainer);}});});}//...generateUniqueId函数...//其他部分:MutationObserver等//...//如果需要,可以暴露selectedItems给外部使用window.getSelectedItems=function(){returnselectedItems;};})();```注意:1.我们给没有id的grandchild设置了id,以确保每个被操作的div都有唯一标识。2.当复选框状态变化时,我们更新selectedItems数组。3.我们提供了一个全局函数`getSelectedItems`来获取当前选中的项(如果需要)。但是,如果同一个div被多次处理(比如在动态添加时),我们通过检查是否已有复选框来避免重复添加,所以事件监听器也只添加一次。另外,当用户删除table1中的项(即某个孙子div)时,我们需要同时更新selectedItems。我们可以监听删除操作(比如删除按钮的点击事件),然后从selectedItems中移除对应的项。由于删除操作可能不在我们的脚本中,我们可以提供一个公共方法来移除:```javascriptfunctionremoveItemFromSelected(divId){selectedItems=selectedItems.filter(item=>item.id!==divId);}```然后,在用户删除操作中调用这个函数。或者,我们可以监听DOM的变化,当孙子div被移除时,自动从selectedItems中移除。这可以通过MutationObserver实现,但要注意性能。另一种更简单的方式:在删除按钮的事件处理函数中,我们不仅删除DOM元素,还调用`removeItemFromSelected`。由于用户需求中提到“table1中的操作项有一个删除”,我们可以假设每个孙子div中有一个删除按钮,我们可以在这个按钮的点击事件中处理:例如,在创建孙子div的内容时,可能有一个删除按钮:```javascript//假设每个grandchild中有一个删除按钮,类名为"delete-btn"grandchild.addEventListener('click',function(e){if(e.target.classList.contains('delete-btn')){//删除操作//先获取这个grandchild的idconstid=grandchild.id;//调用移除函数removeItemFromSelected(id);//然后从DOM中移除grandchild.remove();}});```但是,我们并不清楚用户如何实现删除按钮,所以这里只是提供思路。如果用户使用的是动态框架(如Vue),则应该在框架的数据模型中移除,而不直接操作DOM,那么我们的selectedItems也应该与框架的状态同步。由于我们的脚本是纯JavaScript,我们只能提供基本的DOM操作和事件监听。总结:我们通过给复选框添加change事件,维护了一个选中项的列表。同时,我们提供了从列表中移除项的方法,并建议在删除操作中调用该方法。注意:如果页面中有多个容器(多个table),我们需要将selectedItems按容器分开存储,或者存储在一个以容器为键的对象中。这里我们假设只有一个容器。如果多个容器,我们可以这样:```javascriptletselectedItemsMap=newMap();//key:container,value:arrayfunctionprocessGrandchildren(container){if(!selectedItemsMap.has(container)){selectedItemsMap.set(container,[]);}constselectedItems=selectedItemsMap.get(container);//...然后在事件监听中使用这个selectedItems...}```但根据用户之前的问题,我们只处理一个容器(类名为".auxo-sp-infinit-container")。因此,我们按照单一容器实现。最后,我们还需要考虑:当弹出框关闭再打开时,需要根据selectedItems来隐藏已选中的复选框(即用户需求中提到的“已选中的在弹出框中隐藏checkbox”)。这需要我们在每次处理孙子div时,检查当前div是否已经在selectedItems中,如果是,则隐藏复选框。在processGrandchildren函数中,添加:```javascriptgrandchildren.forEach(grandchild=>{//...其他代码...//在创建复选框之前,检查是否已经在选中列表中consttargetId=grandchild.id||generateUniqueId();if(!grandchild.id){grandchild.id=targetId;}//检查这个grandchild是否已经被选中if(selectedItems.some(item=>item.id===targetId)){//如果已选中,则跳过创建复选框(或者创建后隐藏)//根据需求,我们隐藏复选框//但我们还没有创建,所以我们可以在创建后隐藏//或者不创建?但是不创建的话,如果之后被取消选中(从table1中删除)又需要恢复,所以最好还是创建,但初始为隐藏//所以这里我们先创建,然后根据选中状态设置隐藏}//创建复选框...//初始状态:如果已经在selectedItems中,则隐藏整个复选框容器,并且设置checkbox.checked=true(虽然隐藏,但状态是选中)if(selectedItems.some(item=>item.id===targetId)){checkbox.checked=true;checkboxContainer.style.display='none';//隐藏}//...添加事件监听...});```在事件监听中,当复选框选中时,我们不需要立即隐藏它(因为用户是在弹出框中操作,点击保存后才添加到table1并隐藏),但根据需求,是在保存后隐藏。所以这里我们不在change事件中隐藏,而是在用户点击保存按钮后,再隐藏弹出框中已选中的复选框。因此,我们可能需要一个函数,在保存操作后,更新所有孙子div的复选框显示状态:```javascriptfunctionupdateCheckboxDisplay(container){constcheckboxes=container.querySelectorAll('.auxo-dynamic-checkbox');checkboxes.forEach(checkbox=>{consttargetId=checkbox.dataset.targetId;constcontainer=checkbox.closest('.auxo-checkbox-container');if(selectedItems.some(item=>item.id===targetId)){container.style.display='none';}else{container.style.display='block';}});}```然后,在保存按钮的点击事件中,调用这个函数。但是,由于用户需求是“点击保存后添加到另一个表中”,然后隐藏弹出框中的复选框,所以我们在保存后,应该更新弹出框(即我们的container)中的复选框显示状态。由于我们并不清楚用户如何实现弹出框和保存操作,所以这里我们只提供更新函数,由用户在适当的时候调用。另外,当用户删除table1中的项时,我们不仅要从selectedItems中移除,还要在弹出框中显示对应的复选框(如果弹出框正在显示)。因此,在删除操作中,我们还需要调用updateCheckboxDisplay来更新弹出框。由于删除操作后,弹出框可能没有打开,所以我们可以先存储状态,然后在弹出框打开时更新。或者,我们可以在每次弹出框打开时,重新处理一次孙子div(即重新运行processGrandchildren),这样就会根据当前的selectedItems来设置复选框的显示/隐藏。这样更简单:在打开弹出框时,调用processGrandchildren,这样就会根据selectedItems来初始化复选框的显示状态。因此,我们修改processGrandchildren函数,在创建复选框时,检查该div是否在selectedItems中,如果在,则隐藏复选框容器,并且将复选框设为选中状态(虽然用户看不到,但状态是选中,这样如果之后取消选中,我们可以通过事件监听器来处理)。修改后的复选框创建部分:```javascript//在创建复选框容器后constisSelected=selectedItems.some(item=>item.id===targetId);checkbox.checked=isSelected;if(isSelected){checkboxContainer.style.display='none';}```然后,在事件监听器中,当复选框选中时,我们只是添加到selectedItems,但并没有隐藏它(因为用户可能还会取消,直到保存才隐藏)。但是,根据需求,保存后才隐藏。所以,在保存操作中,我们再次调用processGrandchildren(或者updateCheckboxDisplay)来隐藏选中的复选框。或者,我们可以在保存操作中,遍历所有选中的项,隐藏它们在弹出框中的复选框容器。具体实现取决于保存操作如何触发。为了灵活性,我们提供一个更新函数:```javascriptfunctionupdateCheckboxesVisibility(container){container.querySelectorAll('.auxo-dynamic-checkbox').forEach(checkbox=>{consttargetId=checkbox.dataset.targetId;constcontainer=checkbox.closest('.auxo-checkbox-container');if(selectedItems.some(item=>item.id===targetId)){container.style.display='none';}else{container.style.display='block';}});}```然后,在保存按钮的点击事件处理函数中:```javascriptdocument.getElementById('saveButton').addEventListener('click',function(){//保存选中的项到table1(这部分由用户自己实现)//...//更新弹出框中复选框的可见性updateCheckboxesVisibility(popupContainer);//popupContainer是弹出框中包含孙子div的容器});```这样,保存后,选中的复选框就会隐藏。当用户删除table1中的项时,除了调用removeItemFromSelected,还需要更新弹出框(如果弹出框正在显示)中对应复选框的显示状态:```javascriptfunctionremoveItemFromSelected(divId){selectedItems=selectedItems.filter(item=>item.id!==divId);//如果弹出框是打开的,更新复选框显示if(popupContainer){//假设popupContainer是弹出框容器updateCheckboxesVisibility(popupContainer);}}```注意:popupContainer需要在我们打开弹出框时赋值。由于实现细节较多,这里只提供核心思路。综上所述,我们实现了:1.点击复选框时,将对应div的数据(id、内容等)添加到selectedItems列表。2.提供函数来更新复选框的显示状态(根据是否在selectedItems中)。3.提供函数来从selectedItems中移除项(用于删除操作)。这样,用户就可以根据需求在适当的地方调用这些函数。由于代码较长,这里只给出了关键部分。实际应用中,需要根据具体页面结构调整。</think>要实现选框被点击时将对应的 `<div>` 数据添加到列表中,可以通过以下步骤实现: ### 解决方案:使用事件监听和数据结构存储选中项 ```javascript (function() { // 存储选中项的列表 let selectedItems = []; function processGrandchildren(container) { const children = container.querySelectorAll(':scope > div'); children.forEach(child => { const grandchildren = child.querySelectorAll(':scope > div'); grandchildren.forEach(grandchild => { if (!grandchild.querySelector('.auxo-dynamic-checkbox')) { // 确保有相对定位 if (window.getComputedStyle(grandchild).position === 'static') { grandchild.style.position = 'relative'; } const checkboxContainer = document.createElement('div'); checkboxContainer.className = 'auxo-checkbox-container'; // 创建复选框 const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.className = 'auxo-dynamic-checkbox'; // 创建标签 const label = document.createElement('label'); label.textContent = '选择项'; // 组装元素 checkboxContainer.appendChild(checkbox); checkboxContainer.appendChild(label); // 定位样式 checkboxContainer.style.position = 'absolute'; checkboxContainer.style.top = '0'; checkboxContainer.style.left = '0'; checkboxContainer.style.zIndex = '10'; // 添加点击事件监听器 checkbox.addEventListener('change', function() { if (this.checked) { // 当选中时,将div数据添加到列表 const divData = { id: grandchild.id || generateUniqueId(), content: grandchild.innerText, // 提取文本内容 element: grandchild, // 存储DOM引用 // 可添加更多自定义数据 timestamp: new Date().toISOString() }; selectedItems.push(divData); console.log('已添加:', divData); } else { // 当取消选中时,从列表中移除 const itemId = grandchild.id || this.dataset.targetId; selectedItems = selectedItems.filter(item => item.id !== itemId); console.log('已移除:', itemId); } // 可选:更新UI显示当前选中数量 updateSelectionCount(); }); grandchild.appendChild(checkboxContainer); } }); }); } // 生成唯一ID function generateUniqueId() { return 'auxo-' + Math.random().toString(36).substr(2, 9); } // 更新选中计数显示 function updateSelectionCount() { const counter = document.getElementById('selection-counter') || document.createElement('div'); counter.id = 'selection-counter'; counter.textContent = `已选: ${selectedItems.length} 项`; counter.style.position = 'fixed'; counter.style.bottom = '20px'; counter.style.right = '20px'; counter.style.padding = '10px'; counter.style.background = 'rgba(0,0,0,0.7)'; counter.style.color = 'white'; counter.style.borderRadius = '4px'; if (!document.getElementById('selection-counter')) { document.body.appendChild(counter); } } // 初始化容器处理 const container = document.querySelector('.auxo-sp-infinit-container'); if (container) { processGrandchildren(container); // 添加MutationObserver监听DOM变化 const observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (mutation.addedNodes.length) { processGrandchildren(container); } }); }); observer.observe(container, { childList: true, subtree: true }); } // 暴露selectedItems供外部访问 window.getSelectedItems = function() { return selectedItems; }; })(); ``` ### 核心实现原理 1. **数据结构**: ```javascript const divData = { id: grandchild.id || generateUniqueId(), content: grandchild.innerText, element: grandchild, timestamp: new Date().toISOString() }; ``` - `id`: 唯一标识符,用于跟踪项目 - `content`: 存储div的文本内容 - `element`: 保留DOM引用以便直接操作 - `timestamp`: 添加时间戳记录选中时间 2. **事件监听**: ```javascript checkbox.addEventListener('change', function() { if (this.checked) { // 添加到列表 selectedItems.push(divData); } else { // 从列表中移除 selectedItems = selectedItems.filter(item => item.id !== itemId); } }); ``` - 使用`change`事件监听复选框状态变化 - 根据选中状态添加/移除数据 3. **数据管理**: - 使用`Array.filter()`实现高效的项目移除 - 提供`window.getSelectedItems()`全局访问接口 ### 使用场景示例 ```javascript // 获取所有选中项 const selected = window.getSelectedItems(); // 处理选中数据 function processSelectedItems() { const selectedItems = getSelectedItems(); // 创建数据表格 const table = document.createElement('table'); table.innerHTML = ` <thead> <tr><th>ID</th><th>内容</th><th>选中时间</th></tr> </thead> <tbody> ${selectedItems.map(item => ` <tr> <td>${item.id}</td> <td>${item.content.substring(0, 30)}</td> <td>${new Date(item.timestamp).toLocaleTimeString()}</td> </tr> `).join('')} </tbody> `; document.body.appendChild(table); } // 添加处理按钮 const processBtn = document.createElement('button'); processBtn.textContent = '处理选中项'; processBtn.addEventListener('click', processSelectedItems); document.body.appendChild(processBtn); ``` ### 高级功能扩展 1. **持久化存储**: ```javascript // 保存到localStorage function saveSelection() { localStorage.setItem('selectedItems', JSON.stringify(selectedItems)); } // 从localStorage加载 function loadSelection() { const saved = localStorage.getItem('selectedItems'); if (saved) selectedItems = JSON.parse(saved); } ``` 2. **跨页面同步**: ```javascript // 使用BroadcastChannel同步不同标签页 const channel = new BroadcastChannel('selection-updates'); channel.onmessage = (event) => { if (event.data.type === 'selection-change') { selectedItems = event.data.payload; updateCheckboxes(); } }; function notifySelectionChange() { channel.postMessage({ type: 'selection-change', payload: selectedItems }); } ``` 3. **与后端交互**: ```javascript async function saveToServer() { const response = await fetch('/api/save-selection', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(selectedItems) }); return response.json(); } ``` ### 注意事项 1. **内存管理**: - 当DOM元素被移除时,建议从`selectedItems`中清除对应项 - 使用WeakMap存储DOM引用避免内存泄漏: ```javascript const itemMap = new WeakMap(); // 存储时 itemMap.set(grandchild, divData); // 检索时 const data = itemMap.get(element); ``` 2. **性能优化**: - 对于大量数据,使用虚拟滚动技术 - 添加防抖处理频繁的选中状态变更: ```javascript const debounceUpdate = _.debounce(updateSelectionCount, 300); ``` 3. **可访问性**: - 添加ARIA属性增强无障碍支持: ```javascript checkbox.setAttribute('aria-label', `选择${grandchild.innerText}`); ``` 4. **框架集成**: - Vue/React中可通过自定义hook封装: ```javascript // Vue composition API示例 export function useSelectionManager() { const selectedItems = ref([]); const addItem = (item) => { /* ... */ }; const removeItem = (id) => { /* ... */ }; return { selectedItems, addItem, removeItem }; } ``` 此方案实现了当用户点击复选框时,自动将对应的`<div>`数据存储到列表中,并提供多种方式访问和处理这些数据[^1][^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值