Can this jQuery be done in vanilla JS?

大城市里の小女人 提交于 2020-01-05 14:24:43

问题


I've got this working on mobile devices, but because of the 32kb gzip-ed of jQuery I wonder if it's possible to create this code

$(document).ready(function() {
  $('body').addClass('js');

  var $menu = $('#menu'),
        $menulink = $('.menu-link'),
        $wrap = $('#wrap');

    $menulink.click(function() {
        $menulink.toggleClass('active');
        $wrap.toggleClass('active');
        return false;
    });
});

can be written in no library dependany vanilla JavaScript.

Can it be done? Where would I start?


回答1:


JQuery uses javascript/DOMscripting to create its framework. Everything JQuery does, can be done in basic scripting. For example $('body').addClass('js') can be written as:

document.querySelector('body').className += ' js';

And $menulink.toggleClass('active'); as something like

var current     = $menulink.className.split(/\s+/)
   ,toggleClass = 'active'
   ,exist       =  ~current.indexOf(toggleClass)
;
current.splice(exist ? current.indexOf(toggleClass) : 0,
               exist ? 1 : 0,
               exist ? null : toggleClass);
$menulink.className = current.join(' ').replace(/^\s+|\s+$/,'');

That's why JQuery wrapped this kind of code.

This jsfiddle contains a working example using javascript without a framework. Besides that it demonstrates how to program your own element wrapper.

Where to start? You'll have to dive into javascript I suppose. Or check this SO-question




回答2:


For modern browsers only.®

document.addEventListener('DOMContentLoaded', function() {
    document.body.classList.add('js');

    var wrap = document.getElementById('wrap');
    var menuLinks = Array.prototype.slice.call(document.getElementsByClassName('menu-link'));

    var toggleActive = function(element) {
        element.classList.toggle('active');
    };

    menuLinks.forEach(function(menuLink) {
        menuLink.addEventListener('click', function(e) {
            menuLinks.forEach(toggleActive);
            toggleActive(wrap);
        }, false);
    });
}, false);



回答3:


var toggleClass = function (el, className) {
  if(el) {
    if(el.className.indexOf(className)) {
      el.className = el.className.replace(className, '');
    }

    else {
      el.className += ' ' + className;
    }
 }
};

document.addEventListener('DOMContentLoaded', function () {
  document.body.className += ' js';

  var $menu = document.querySelector('#menu'),
  $menulink = document.querySelectorAll('.menu-link'),
  $wrap = document.querySelector('#wrap');

  $menulink.addEventListener('click', function (e) {

    toggleClass($menulink, 'active');
    toggleClass($wrap, 'active');
    e.preventDefault();
  });
});



回答4:


There's always classList (workaround for incompatible browsers included).




回答5:


Absolutely. Since jQuery is a subset of JavaScript (written entirely in JavaScript) any function you like can be duplicated. It's a matter of how much effort you want to put into it. Below is how I would duplicate the limited subset of jQuery in your post and it's reasonably cross-browser compatible (if a wee bit long...).

var Vanilla;
if (!Vanilla) {
    Vanilla = {};
}
//execute this now to have access to it immediately.
(function () {
    'use strict';
    Vanilla.addHandler = function (elem, event, handler) {
        if (elem.addEventListener) {
            elem.addEventListener(event, handler, false);
        } else if (elem.attachEvent) {
            elem.attachEvent('on' + event, handler);
        }
    };
    Vanilla.hasClass = function (elem, cssClass) {
        var classExists = false;
        //
        if (elem && typeof elem.className === 'string' && (/\S+/g).test(cssClass)) {
            classExists = elem.className.indexOf(cssClass) > -1;
        }
        //
        return classExists;
    };
    Vanilla.addClass = function (elem, cssClass) {
        if (elem && typeof elem.className === 'string' && (/\S+/g).test(cssClass)) {
            //put spaces on either side of the new class to ensure boundaries are always available
            elem.className += ' ' + cssClass + ' ';
        }
    };
    Vanilla.removeClass = function (elem, cssClass) {
        if (elem && typeof elem.className === 'string'&& (/\S+/g).test(cssClass)) {
            //replace the string with  regex
            cssClass = new RegExp('\\b' + cssClass + '\\b', 'g');
            elem.className = elem.className.replace(cssClass, '').replace(/^\s+/g, '').replace(/\s+$/g, ''); //trim className
        }
    };
    Vanilla.toggleClass = function (elem, cssClass) {
        if (Vanilla.hasClass(elem, cssClass)) {
            Vanilla.removeClass(elem, cssClass);
        } else {
            Vanilla.addClass(elem, cssClass);
        }
    };
    Vanilla.getElementsByClassName = function (cssClass) {
        var nodeList = [],
            classList = [],
            allNodes = null,
            i = 0,
            j = 0;
        if (document.getElementsByClassName1) {
            //native method exists in browser.
            nodeList = document.getElementsByClassName(cssClass);
        } else {
            //need a custom function
            classList = cssClass.split(' ');
            allNodes = document.getElementsByTagName('*');
            for (i = 0; i < allNodes.length; i += 1) {
                for (j = 0; j < classList.length; j += 1) {
                    if (Vanilla.hasClass(allNodes[i], classList[j])) {
                        nodeList.push(allNodes[i]);
                    }
                }
            }
        }
        return nodeList;
    };
}());
//Now we have a proper window onload
Vanilla.addHandler(window, 'load', function () {
    'use strict';
    var body = document.body,
        menu = document.getElementById('menu'),
        menulink = [],
        wrap = document.getElementById('wrap'),
        i = 0,
        menulinkClickHandler = function (e) {
            var i = 0;
            for (i = 0; i < menulink.length; i += 1) {
                Vanilla.toggleClass(menulink[i], 'active');
            }
            Vanilla.toggleClass(wrap, 'active');
            return false;
        };
    Vanilla.addClass(body, 'js');
    menulink = Vanilla.getElementsByClassName('menu-link');
    for (i = 0; i < menulink.length; i += 1) {
        Vanilla.addHandler(menulink[i], 'click', menulinkClickHandler);
    }
});


来源:https://stackoverflow.com/questions/12874006/can-this-jquery-be-done-in-vanilla-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!