从chrome-extension-popup中删除无序列表中的一个项目也会删除

时间:2016-12-28 20:32:33

标签: javascript google-chrome google-chrome-extension event-handling popupwindow

简介

我们说我有一个包含3个项目的列表(这些项目是用户在点击Chrome扩展弹出窗口内的按钮时添加的URL,见图片)。当我点击' X'项目编号3的按钮,它只删除该项目。之后,当我点击' X'项目编号2,第二项被删除。最后,点击' X'它也被删除的第一个项目。一切都按预期工作。当我尝试相反时,会出现问题。

问题

我们有3个项目的相同列表。现在,我决定先删除第1项,而不是先删除第3项。当我这样做时,所有3个项目都立即消失了。然后我再次重新加载了3个项目,并尝试从删除项目编号2开始,这次只删除项目2和项目3,剩余项目1。这是一个奇怪的错误,因为每当我点击一个' X'按钮连续项目将与我要删除的项目一起删除。

点击' X'谷歌:

Before clicking the 'X' by Google

点击' X'只剩下Facebook:

after
然后我开始使用调试器。

调试器

所以我认为这很奇怪,我试图用调试器解决问题。只按下' X'谷歌按钮(与上图相同):
debug error

然后我去了popup.js并查看了包含这些行的特定代码行:

// the specific URL to delete
list.removeChild(items[j]);

代码部分中,我更详细地发布了代码部分。我在Google上搜索了错误并找到了这个:removeChild。这里,错误描述如下:

"如果孩子实际上是元素的孩子并且存在于DOM上,但已被删除"

现在这让我很奇怪,我再次凝视着我的代码,但据我所知,我还没有删除Google之后的网址,只有谷歌本身。我试图在纸上解决这个问题但不幸的是徒劳无功。我唯一能想到的是我应该删除" createButtonEvents"来自" addToDom"功能。但是,如果我这样做,我就不能再删除第1项(但是我可以删除第2项而不删除第3项)。我认为这个问题比我原先想象的要复杂得多,所以我不能自己解决这个问题,这也就是我在这里问这个问题的原因。现在来了'代码'部分。

代码

对于想要查看整个代码(所有行和文件)的任何人,请转到此页面:GitHub

对于那些只关注发生这种情况的特定代码的人:

我的popup.js文件的一部分



document.addEventListener('DOMContentLoaded', function() {
    restore();
    document.getElementById('add').addEventListener('click', fetchUrl);
    document.getElementById('clear').addEventListener('click', clearAll);
  });

function restore() {
    // get the tab link and title
    chrome.storage.local.get({urlList:[], titleList:[]}, function(data) {
        urlList = data.urlList;
        titleList = data.titleList;
     
        // add the titles and url's to the DOM
        var n = urlList.length;
        for (var i = 0; i < n; i++) {
            addToDom(urlList[i], titleList[i]);
        }
        // 'X' button handlers only when all URL's are in DOM
        createButtonEvents();
    }); 
}
function addToDom(url, title) {
    // change the (greeting) text message
    document.getElementById("div").innerHTML = "<h2 id='title'>Saved Pages</h2>";
    
    // Build the new DOM elements programmatically
    var newItem = document.createElement('li');
    var newLink = document.createElement('a');
    var thisButton = document.createElement('button');
    
    newLink.textContent = title;                            
    thisButton.textContent = 'X';                          

    thisButton.setAttribute('class', 'buttons');            
    thisButton.setAttribute('tabindex', -1);                
    newItem.setAttribute('class', 'items');                 
                                
    newLink.setAttribute('href', url);                      
    newLink.setAttribute('target', '_blank');               
    newLink.setAttribute('tabindex', -1);                   
    newLink.setAttribute('id', 'item');                     
    
    newItem.appendChild(thisButton);                        
    newItem.appendChild(newLink);                           
    document.getElementById('list').appendChild(newItem);   
    createButtonEvents();
}

function createButtonEvents() {
    // create event listeners for all the 'X' buttons next to list items
    // after the 'addToDom' function has been executed
    var allButtons = document.getElementsByClassName('buttons');
    for (var j = 0, k = allButtons.length; j < k; j++) {
        listenJ(j);
    } 
    function listenJ(j) {
        allButtons[j].addEventListener('click', () => removeMe(j));
    }  
}

function removeMe(j) {
    // remove it from the DOM
    var items = document.getElementsByClassName('items');
    var list = document.getElementById('list');
    // the specific URL to delete
    list.removeChild(items[j]);
    
    // return the DOM to original state
    if (items.length === 0) {
    document.getElementById('list').innerHTML = '';
    document.getElementById('div').innerHTML = '<h3>No content yet! Click "add link" to add the link of the current website!</h3>';
    }
    
    // remove it from chrome-storage
    chrome.storage.local.get({urlList:[], titleList:[]}, function(data) {
        urlList = data.urlList;
        titleList = data.titleList;
        urlList.splice(j, 1);
        titleList.splice(j, 1);

        // update chrome storage
        saveList();
    }); 
}
&#13;
&#13;
&#13;

修改

如果有人没有阅读,我会再次在调试器部分重复这句话:

我唯一能想到的就是我应该删除&#34; createButtonEvents&#34;来自&#34; addToDom&#34;功能。但是,如果我这样做,我就不能再删除第1项(但是我可以删除第2项而不删除第3项)。我认为这个问题比我最初认为的要复杂得多

我知道&#39;按钮类上的多个事件处理程序&#39;可能在同一时间工作,但我不知道如何以另一种方式格式化代码。

2 个答案:

答案 0 :(得分:2)

document.getElementsByClassName会创建 直播 元素列表。

多次调用

createButtonEvents();并添加多个事件侦听器,这些侦听器使用j作为实时集合的索引。因为侦听器使用每个添加事件侦听器调用唯一的匿名函数,所以它们不被视为相同且不会被丢弃。

因此删除最后一个元素是有效的,因为没有更多的&#34; jth&#39;第一次删除后要删除的元素。但是当你删除第一个元素时,因为列表是实时的,之后还有另一个要删除的第一个元素,因为有多个事件监听器......

我尝试删除createButtonEvents()中的addToDom调用,该调用修复了控制台错误消息,因为代码不再尝试删除不存在的节点。

引入了一个新错误:删除第一个按钮,因为它的索引在实时收藏中为0。但删除会更改实时列表中剩余项目的权限。现在删除第二个项目会删除第三个链接,因为它的索引已更改为1,而索引为1的内容现在为0。

<小时/> 更新了样本解决方案:

  1. 删除createButtonEvents功能。嵌套listenJ和捕获j的匿名函数(索引实时HTML集合)是错误的根本原因。

    移除createButtonEvents

    中对restore的来电

    createButtonEvents中的来电addToDom替换为

        thisButton.addEventListener('click', removeMe);
    

    以便列表中的所有按钮获得相同的点击处理程序,无论该按钮是从存储中恢复还是稍后添加。

  2. removeMe中,找到点击的按钮,在列表中找到当前,动态位置并将其删除。找到的位置与存储数据数组中项目的位置匹配:

    function removeMe() {
        // remove list item (parent of button clicked) from the DOM
        var list = document.getElementById('list');
    
        // find position of list element with button clicked:
        for( var j = 0, child = list.firstChild; 
                child;
                    child = child.nextSibling, ++j) {
    
             if (child == this.parentNode) {
                  break;
             }
    
        }    
        list.removeChild(this.parentNode); // this is button, parent is <li>
    
        // return the DOM to original state
        if (!list.firstChild) {
        document.getElementById('list').innerHTML = '';
        document.getElementById('div').innerHTML = '<h3>No content yet! Click "add link" to add the link of the current website!</h3>';
        }
    
        // remove from Chrome storage using position in j
    
        //    urlList = data.urlList;
        //    titleList = data.titleList;
        //    urlList.splice(j, 1);
        //    titleList.splice(j, 1);
    
    
    }
    
  3. 使用Chrome以外的测试值测试了urlListtitleList的更新:Chrome存储更新需要恢复。

答案 1 :(得分:0)

控制台中的错误告诉您需要将Node传递给removeChild,看起来您没有传递DOM元素。

相关问题