понимание связанных функций, как вернуть jquery-подобный сам элемент, как избежать "... это не функция" - PullRequest
0 голосов
/ 04 февраля 2019

Совершенно экспериментально и только для обучения я пытаюсь заново изобрести колесо, колесо под названием jquery.Первоначальной целью было понять цепные функции.Поэтому я написал функцию, которая делает это, и, насколько я вижу, очень хорошо, например, так: (немного сокращенно)

var $ = function(s) {
    var el = document.querySelectorAll(s);

    var myobj = {
        addClass(className) {
            el.forEach(elem => {elem.classList.add(className)});
            return this;
        },
        toggleClass(className) {
            el.forEach(elem => {elem.classList.toggle(className)});
            return this;
        },
        removeClass(className) {
            el.forEach(elem => {elem.classList.remove(className)});
            return this;
        },
        html(html) {
            if (typeof html == 'string') {
                el.forEach(elem => {elem.innerHTML = html});
                return this;
            } else {
                return el[0].innerHTML;
            }
        }
    };

    return myobj;
};

(это действительно рабочий пример) Теперь я могу использовать jquery-подобный синтаксис для манипулирования классами и html элемента (или списка узлов), например, так: $('#test').html('new html content'); или цепочка, как $('a').html('my new link').addClass('newclassname');, что действительно круто.

Для тех, кто заинтересован, вотполный снимок сценария на сегодняшний день , включая css() и attr(), включая отсутствующую функцию jquery id().

Мои вопросы:

  • [RESOLVED] Как я могу заставить эту функцию возвращать jquery-подобный только сам элемент, такой как var elm = $('div#test');, теперь я возвращаю весь объект.

  • [RESOLVED] (плз. См. Комментарии ниже) Как я могу написать запасную функцию, чтобы предотвратить получение сообщения об ошибке типа $(...).animate is not a function, если я использую метод, которыйв настоящее время не охватывается этой функцией, как $('div#test').addClass('newclass').animate({top:'2.3em',background:'red'});, так как animate() не реализован вмоментВ php есть функция __get(), есть ли что-то похожее в javascript?

Пожалуйста, не спрашивайте меня, почему я делаю все это, как я уже говорил, это дляобучение и понимание

Спасибо.

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

Загляните в репозиторий github из jquery.Соответствующие файлы:

https://github.com/jquery/jquery/blob/master/src/core.js

https://github.com/jquery/jquery/blob/master/src/core/init.js

jQuery делает это более сложным способом, чем я буду здесь, так что это всего лишьбазовое объяснение.

Функция jQuery (и ее псевдоним $) вызывают new jQuery.fn.init(selector, root) в своих телах функций.Это создает новый jQuery collection (это термин, который они используют в документации) из jQuery.prototype.К этому прототипу прикреплены все обычные методы jQuery (например, on, find, animate и т. Д.).

Они делают это:

function jQuery (selector, root) {
  return new jQuery.fn.init(selector, root);
}

jQuery.fn = jQuery.prototype = { /* skipped */ }

jQuery.fn.init = function (selector, root) { /* skipped */ }
jQuery.fn.init.prototype = jQuery.fn;

Ключвот последняя строка, где они делают jQuery.prototype также prototype из jQuery.fn.init (не путайтесь с fn, это просто другой псевдоним, который они используют, поэтому им не нужно вводить prototype все время).

Когда вы сканируете функцию конструктора jQuery.fn.init, вы заметите, что они сохраняют все соответствующие элементы DOM по индексу в новую коллекцию.Упрощенно:

jQuery.fn.init = function (selector, root) {
  let elms = Array.from(root.querySelectorAll(selector));
  elms.forEach((el, index) => {
    this[index] = el;
  }, this);
}

Они делают много вещей под капотом, но это в основном объясняет, что такое коллекция jQuery : пользовательский тип объекта, который частично выглядит как NodeList, но с пользовательским prototype, к которому прикреплены все методы jQuery .

Это означает, что ваш первый вопрос основан на неверном предположении: использование $('div#test') вернет коллекцию jQuery с одним элементом .Вы никогда не получите "сырой" узел DOM от jQuery.

Что касается вашего второго вопроса: вы можете использовать прокси для этого.

0 голосов
/ 04 февраля 2019

Как я могу заставить эту функцию возвращать jquery-подобный только сам элемент, такой как var elm = $('div#test');, теперь я возвращаю весь объект.

jQuery всегда возвращает вамвесь объект jQuery.Если вы ссылаетесь на то, что определенные вами методы (addClass,…) не отображаются с объектом в консоли браузера, это достигается путем совместного использования этих свойств с prototype вместо созданияновый набор функций для каждого объекта.Классы ES6 - это удобный способ создания конструкторов, которые позволяют вам определять прототип с помощью методов и создавать объекты, которые наследуют его:

class MyElementCollection {
    constructor(el) {
        this.el = el;
    }

    addClass(className) {
        this.el.forEach(elem => {elem.classList.add(className)});
        return this;
    }

    // ⋮
}

var $ = function(s) {
    var el = document.querySelectorAll(s);

    return new MyElementCollection(el);
};

Затем, если вы хотите, чтобы он отображался как массив в Firefox и имелэлементы, доступные по индексу $('div#test')[0], как это делает jQuery, вы присваиваете элементы этим индексам и присваиваете своей коллекции length:

class MyElementCollection {
    constructor(el) {
        el.forEach((elem, i) => {
            this[i] = elem;
        });

        this.length = el.length;
    }

    each(action) {
        for (let i = 0; i < this.length; i++) {
            action(this[i]);
        }
    }

    addClass(className) {
        this.each(elem => {elem.classList.add(className)});
        return this;
    }

    // ⋮
}

Затем, если вы хотите, чтобы она отображалась как массив в Chrome,вы делаете странный взлом (все еще применимый в 2019 году) , определяющий splice метод , даже если он не делает то же самое, что делает с массивами ... или вообще что-то делает:

class MyElementCollection {
    // ⋮

    splice() {
        throw new Error('Not implemented');
    }
}

Как написать резервную функцию, чтобы предотвратить получение сообщения об ошибке, например $(...).animate, не является функцией, если я использую метод, который в настоящее время не рассматривается в этой функции, например $('div#test').addClass('newclass').animate({top:'2.3em',background:'red'});, поскольку animate() на данный момент не реализовано.В php есть функция __get(), есть ли что-то похожее в javascript?

Вы можете сделать это с прокси в JavaScript, ноЯ не рекомендовал бы это - это не очень чисто.(Ваш объект будет претендовать на то, чтобы иметь все свойства, а не только те, которые существуют в jQuery, которые вы не реализовали, и не будет списка их для поиска в прототипе. Прокси-серверы также идут с потерями производительности и понятности.) Вместо этогорассмотрите возможность назначения всех неосуществленных вещей одной и той же реализации:

class MyElementCollection {
    // ⋮
}

const notImplemented = () => {
    throw new Error('Not implemented');
};

['animate', …].forEach(name => {
    MyElementCollection.prototype[name] = notImplemented;
});
...