Можно ли сделать этот jQuery в vanilla JS?

У меня это работает на мобильных устройствах, но из-за 32-килобайтного архива jQuery мне интересно, возможно ли создать этот код

$(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;
    });
});

может быть написан ни в одной библиотеке, не зависящей от ванильного JavaScript.

Можно ли это сделать? С чего бы мне начать?


person Stuart Robson    schedule 13.10.2012    source источник
comment
Jquery — это среда Javascript, поэтому, естественно, все, что вы пишете в jquery, должно быть выполнимо в Javascript.   -  person Matija Milković    schedule 13.10.2012
comment
Как сказала @MatijaMilković, ответ на этот вопрос всегда положительный. Иногда сложнее, чем другие, но jQuery — это JavaScript.   -  person Chris Ferdinandi    schedule 19.06.2014


Ответы (4)


JQuery использует javascript/DOMscripting для создания своей структуры. Все, что делает JQuery, можно сделать с помощью базовых сценариев. Например, $('body').addClass('js') можно записать так:

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

И $menulink.toggleClass('active'); как-то так

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+$/,'');

Вот почему JQuery обернул такой код.

Этот jsfiddle содержит рабочий пример использования javascript без фреймворка. Кроме того, он демонстрирует, как запрограммировать собственную оболочку элемента.

Когда начать? Полагаю, вам придется погрузиться в javascript. Или проверьте этот SO-вопрос

person KooiInc    schedule 13.10.2012
comment
Это неверно, он заменяет такие классы, как activeyo (потому что не проверяет границы) и activeyo active-something-else (из-за флага g), но это не соответствует active (поскольку в нем нет начального пробела). - person chelmertz; 13.10.2012
comment
@chelmertz: я сказал «что-то вроде». Но ты прав, плохой пример. Отредактировал ответ на лучший. - person KooiInc; 14.10.2012

Только для современных браузеров.

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);
person Community    schedule 13.10.2012

Всегда есть classList (включая обходной путь для несовместимых браузеров).

person chelmertz    schedule 13.10.2012

Абсолютно. Поскольку jQuery является подмножеством JavaScript (полностью написанным на JavaScript), любая функция, которая вам нравится, может быть продублирована. Это вопрос того, сколько усилий вы хотите приложить к этому. Ниже показано, как я бы продублировал ограниченное подмножество jQuery в вашем посте, и оно достаточно совместимо с разными браузерами (если немного долго...).

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);
    }
});
person pete    schedule 14.10.2012