Chrome扩展:将元素追加到DOM中没有立即出现的新注入的元素中

Chrome Extension: Appending elements to newly injected element not immediately appearing in DOM

本文关键字:元素 新注入 注入 扩展 追加 Chrome DOM      更新时间:2023-09-26

我正在编写一个Chrome扩展,有问题的功能来自一个内容脚本,当右键单击任何元素并选择上下文菜单项时就会调用它。功能:

--右键单击元素时--

  1. 创建<div>
  2. 将jQuery UI对话框小部件应用于<div>
  3. 将包含<select>元素的HTML文件注入到<div>
  4. 分析所选元素的所有属性(标记、属性等),并根据这些属性编译<option>元素
  5. <option>元素写入<select>元素

--然后在选择上下文菜单后--

  1. 最后,当选择上下文菜单项时,将显示对话框,其中包含带选项的select元素

HTML文件非常基本,所以为了简洁起见,我在下面的代码中省略了它。

问题是,当第一次右键单击某个元素时,除步骤5外的所有内容都有效,但第二次也有效。然后,无论元素是什么,每次单击鼠标右键都可以正常工作。

这是代码:

var GTFA_ELE = {};
var GTFA_DIALOG_FLAG = false;
$(document).on('contextmenu',function(event){
    GTFA_ELE = {};
    //Check if the dialog has been created yet, if not, make it:
    if(!GTFA_DIALOG_FLAG){
        var dialogEle = document.createElement("div");
        dialogEle.id = "gtfa_dialog";
        //Inject the HTML for the rule form:
        $.get(chrome.extension.getURL('inject.html'), function(data) {
            $(data).appendTo(dialogEle);
        });
        //Commit the dialog box modal to dom:
        document.body.appendChild(dialogEle);
        //Apply the modal widget:
        $(function() {
            $( "#gtfa_dialog" ).dialog({
                autoOpen: false
            });
        });
        GTFA_DIALOG_FLAG = true;
    }
    GTFA_ELE = {};
    //Get info from the clicked element:
    var ele = $(event.target);
    //Get all the attributes:
    $(ele[0].attributes).each(function() {
        //Handle multiple classes differently:
        if(this.nodeName == "class" && this.nodeValue.indexOf(" ") > 0){
            //Split the string of classes into an array:
            var classes = this.value.split(" ");
            GTFA_ELE["classes"] = classes;
        } else {
            GTFA_ELE[this.nodeName] = this.value;
        }
    });
    //Get the tag name and the html of the selected element. These won't be added by the loop below, because they aren't attributes:
    GTFA_ELE.tag = event.target.tagName;
    GTFA_ELE.html = ele.html();
    var output_html = "";
    //Create the <option> elements from the available selectors (tag, id, class, href, etc...):
    $.each(GTFA_ELE, function(key, item) {
        if(key == "classes"){
            class_list = "";
            for(i = 0; i < item.length; i++){
                class_list += "<option>"+item[i]+"</option>";
            }
            output_html += "<option>Class...</option>";
        } else {
            output_html += "<option>"+key+": "+item+"</option>";
        }
    });
    $("#GTFA_ruleForm_url").val(GTFA_ELE.tag);
    //Inject the option elements created earlier:
    $( "#GTFA_ruleForm_selector" ).html(output_html);
});
//Handle message from background.js (context menu item is selected):
chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.type == "open_rule"){
        $( "#gtfa_dialog" ).dialog( "open" );
      //sendResponse({farewell: "goodbye"});
    }
  });

很抱歉,如果我的解释很糟糕,如果有什么可以补充的,请告诉我。我省略了很多,因为它在很大程度上是不相关的,除了提供更多的上下文之外,没有任何帮助。

这是对回调使用的典型误解。事实上,步骤(4)和(5)第一次不能正确工作,因为$.get请求尚未完成,所以在尝试(4)或(5)时没有发生(3)。

我建议阅读回调和异步javascript的正确使用。

然后,我将把(4)和(5)放在它们自己的函数中,并在$.get回调中的(3)之后和if(!GTFA_DIALOG_FLAG){块之后的else块中调用它。