document.querySelector()不在DOM中的元素?

时间:2017-09-17 17:55:57

标签: javascript jquery html

我正在使用jQuery在网站上工作,但我不再尝试使用它了。在jQuery中,您可以在网站上没有创建的元素上添加偶数监听器,或者尚未创建且没有问题。当你登录时我有只在DOM上的元素,我只有一个JS文件用于整个网站。

问题是,例如,当您登录时,您无法看到"登录"按钮,它甚至不在DOM中,但它仍然在代码中有事件监听器,控制台上没有错误,脚本运行良好。

$("#logInButton").on("click", somefunction);

但是,使用document.querySelector("#logInButton").onclick = somefunction并且已经登录,它会抛出错误,因为document.querySelector("#logInButton")为空。

我可以这样做:

let logInButton = document.querySelector("#logInButton");

logInButton ? logInButton.onclick = somefunction : "";

它运作良好,但我知道这不是一个好习惯。任何解决方法或改进,而不是使用jQuery?

JSFiddle if what happens. (See console)

2 个答案:

答案 0 :(得分:2)

  

它运作良好,但我知道这不是一个好习惯。

如果页面上有#logInButton是可选的,那么这是非常好的做法 - 除了使用onclick而不是addEventListener(但这可能是一种风格问题)。当然,您可以在文档的 end 链接的脚本中使用此代码,就在</body>标记之前(或通过DOMContentLoaded回调触发它)。

但是如果你想要相当于jQuery,你需要考虑jQuery的“基于集合”的思维模式并使用querySelectorAll

// Not very efficient
document.querySelectorAll("#logInButton").forEach(function() {
    // Set up the handler here using `this`
});

除了jQuery使用#id格式优化查询到getElementById调用(显着更快),然后使用if(和你的一样)来用一个元素或零构建集合。

也许在你不使用jQuery的过程中,你可能会给自己一些辅助函数来代替它,因为DOM API非常详细。如果您喜欢jQuery基于集合的特性,您甚至可以将它们设置为基于集合:

function MyQuery(selector) {
    if (!selector) {
        this.data = [];
    } else if (typeof selector === "string") {
        // (jQuery takes it further than this, search in an unminified version for `rquickExpr`)
        var id = /#([\w-]+)/.match(selector);
        if (id) {
            var e = document.getElementById(id[0]);
            this.data = e ? [e] : [];
        } else {
            this.data = Array.from(document.querySelector(selector));
        }
    } else {
        /* ...handle other things, such as DOM elements or arrays of them...? */
        this.data = /*...*/;
    }
}
MyQuery.prototype = {
    constructor: MyQuery,
    on: function(eventName, handler) {
        this.data.forEach(function(element) {
            element.addEventListener(eventName, handler);
        });
        return this;
    }
    // ...etc...
};
function qset(selector) {
    return new MyQuery(selector);
}

然后

qset("#logInButton").on("click", /*...*/);

当然,您可能会发现自己基本上正在重新创建jQuery。但如果你保持精益......

附注:在forEach的返回值上使用querySelectorAll需要最新的浏览器,或者您需要填充它:

if (typeof NodeList !== "undefined" &&
    NodeList.prototype &&
    !NodeList.prototype.forEach) {
    Object.defineProperty(NodeList.prototype, "forEach", {
        value: Array.prototype.forEach
    });
}

对于真正过时的浏览器(如IE8),您必须先填充Array.prototype.forEach

答案 1 :(得分:0)

你可以像jQuery一样使用事件冒泡来完成它。

document.addEventListener('click', function (ev) { 
  if (ev.target.id === 'someIdHere') { 
    console.log('click'); 
  }
});