← Back to context

Comment by hsbauauvhabzb

16 hours ago

These days I’ve moved to native JS, but hot damn the $() selector interface was elegant and minimal vs document.getElement[s]by[attribute)].

While presumably jquery is slower than native selectors, maybe that could be pre-computed away.

In case you missed them: check out querySelector and querySelectorAll. They are closer to what the jQuery selector system does, and I think they were inspired by it.

If the verbosity bothers you, you can always define an utility function with a short name (although I'm not personally a fan of this kind of things).

https://developer.mozilla.org/docs/Web/API/Document/querySel...

https://developer.mozilla.org/docs/Web/API/Document/querySel...

https://developer.mozilla.org/docs/Web/API/Element/querySele...

https://developer.mozilla.org/docs/Web/API/Element/querySele...

  • body.qsa('.class').forEach(e=>): Yes, add qs() and Array.from(qsa()) aliases to the Node prototype, and .body to the window, and you’ve saved yourself thousands of keystrokes. Then you can get creative with Proxy if you want to, but I never saw the need.

const $ = document.querySelector.bind(document);

const $$ = document.querySelectorAll.bind(document);

jQuery but gets compiled out like svelte... Not a bad idea at all.

  • I hate to sound like a webdev stereotype but surely the parsing step of querySelector, which is cached, is not slow enough to warrant maintaining such a build step.

Very simple jquery implementation with all the easy apis:

  (function (global) {
    function $(selector, context = document) {
      let elements = [];

      if (typeof selector === "string") {
        elements = Array.from(context.querySelectorAll(selector));
      } else if (selector instanceof Element || selector === window || selector === document) {
        elements = [selector];
      } else if (selector instanceof NodeList || Array.isArray(selector)) {
        elements = Array.from(selector);
      } else if (typeof selector === "function") {
        // DOM ready
        if (document.readyState !== "loading") {
          selector();
        } else {
          document.addEventListener("DOMContentLoaded", selector);
        }
        return;
      }

      return new Dollar(elements);
    }

    class Dollar {
      constructor(elements) {
        this.elements = elements;
      }

      // Iterate
      each(callback) {
        this.elements.forEach((el, i) => callback.call(el, el, i));
        return this;
      }

      // Events
      on(event, handler, options) {
        return this.each(el => el.addEventListener(event, handler, options));
      }

      off(event, handler, options) {
        return this.each(el => el.removeEventListener(event, handler, options));
      }

      // Classes
      addClass(className) {
        return this.each(el => el.classList.add(...className.split(" ")));
      }

      removeClass(className) {
        return this.each(el => el.classList.remove(...className.split(" ")));
      }

      toggleClass(className) {
        return this.each(el => el.classList.toggle(className));
      }

      hasClass(className) {
        return this.elements[0]?.classList.contains(className) ?? false;
      }

      // Attributes
      attr(name, value) {
        if (value === undefined) {
          return this.elements[0]?.getAttribute(name);
        }
        return this.each(el => el.setAttribute(name, value));
      }

      removeAttr(name) {
        return this.each(el => el.removeAttribute(name));
      }

      // Content
      html(value) {
        if (value === undefined) {
          return this.elements[0]?.innerHTML;
        }
        return this.each(el => (el.innerHTML = value));
      }

      text(value) {
        if (value === undefined) {
          return this.elements[0]?.textContent;
        }
        return this.each(el => (el.textContent = value));
      }

      // DOM manipulation
      append(content) {
        return this.each(el => {
          if (content instanceof Element) {
            el.appendChild(content.cloneNode(true));
          } else {
            el.insertAdjacentHTML("beforeend", content);
          }
        });
      }

      remove() {
        return this.each(el => el.remove());
      }

      // Utilities
      get(index = 0) {
        return this.elements[index];
      }

      first() {
        return new Dollar(this.elements.slice(0, 1));
      }

      last() {
        return new Dollar(this.elements.slice(-1));
      }
    }

    global.$ = $;
  })(window);