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

vel*_*our 1 html javascript jquery

我正在使用 jQuery 开发一个网站,但我试图不再使用它。在 jQuery 中,您可以在不在网站上或尚未创建的元素上添加偶数侦听器,这没有问题。我的元素仅在您登录时出现在 DOM 上,并且整个网站只有一个 JS 文件。

问题是,例如,当您登录时,您看不到“登录”按钮,它甚至不在 DOM 中,但代码中仍然有事件侦听器,控制台上没有错误,脚本运行出色地。

$("#logInButton").on("click", somefunction);
Run Code Online (Sandbox Code Playgroud)

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

我可以这样做:

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

logInButton ? logInButton.onclick = somefunction : "";
Run Code Online (Sandbox Code Playgroud)

它运作良好,但我知道这不是一个好的做法。如果不使用 jQuery,有什么解决方法或改进吗?

JSFiddle 如果发生什么情况。(参见控制台)

T.J*_*der 5

它运作良好,但我知道这不是一个好的做法。

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


但如果您想要 jQuery 的等价物,您需要以 jQuery 的“基于集合”的思维方式进行思考并使用querySelectorAll

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

除了 jQuery 使用#id调用格式来优化查询getElementById(速度快得多),然后使用 an 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);
}
Run Code Online (Sandbox Code Playgroud)

然后

qset("#logInButton").on("click", /*...*/);
Run Code Online (Sandbox Code Playgroud)

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


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

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

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