Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Аналог nextAll() на чистом javascript (https://javascript.ru/forum/events/67939-analog-nextall-na-chistom-javascript.html)

Stay_Strong 16.03.2017 13:10

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

ksa 16.03.2017 13:20

Цитата:

Сообщение от Stay_Strong
Как это сделать?

Использовать свойство nextSibling у элементов...
http://www.fpublisher.ru/documentati...s#hnextsibling

Stay_Strong 16.03.2017 13:23

ksa,
Так он возвращает только один следующий элемент, а не все.

ksa 16.03.2017 13:25

Цитата:

Сообщение от Stay_Strong
Так он возвращает только один следующий элемент, а не все

Так у тебя еще есть циклы... :D

ksa 16.03.2017 13:26

Цитата:

Сообщение от Stay_Strong
Задался тут целью хоть раз написать плагин (точнее метод скорее) на нативном JS.

Не совсем понятно с чего ты решил, что тебе такое по силам, если ты основ не знаешь? :blink:

Stay_Strong 16.03.2017 13:35

ksa,
вот решил с основами и познакомиться таким образом. На jquery я писал плагин, получилось вроде бы неплохо.

ksa 16.03.2017 13:39

Цитата:

Сообщение от Stay_Strong
вот решил с основами и познакомиться таким образом

С таким же успехом можно начать строить свою нефтяную компанию! :D

Stay_Strong 16.03.2017 13:50

ksa,
Я думаю, что вы напрасно смеетесь. Потому что многие учатся таким способом. У меня пока что вот что получается
window.onload = function() {

  function loadElements() {
    //Основные параметры
    var element = '.filter__item', //элементы к которым будет применен метод
        childrenElements = '.filter__option', //дочерние элементы, больше числа которых появляется кнопка раскрытия
        count = 3, //число, после которого появится раскрытие
        speed = 250, //скорость раскрытия блока по нажатию на кнопку показа
        textMore = '+ Показать все', //Текст для кнопки "Показать все"
        textLess = '- Скрыть'; //Текст для кнопки "Cкрыть"

    //Переменные, используемые в плагине
    var elList = document.querySelectorAll(element); //находим все элементы на странице, к которым нужно применить метод

    Array.prototype.forEach.call(elList, function(el, i) { //Обходим в цикле все элементы
        var countChildren = elList[i].querySelectorAll(childrenElements);
        if(countChildren.length > count) {
          //Создаем контейнер, куда будем перемещать все элементы, которые нужно скрыть.
          var container = document.createElement('div');
          container.className = 'loadContainer';
          //Присваиваем контейнер в наш элемент
          elList[i].appendChild(container);
          //Выбираем все элементы, которые будем скрывать
          for(var j = 0; j < countChildren.length; j++) {
            if(j > count - 1) {
              container.appendChild(countChildren[j]);
            }
          }
        }
    });

  }

  loadElements();

}

ksa 16.03.2017 14:25

Stay_Strong, это и есть плагин? :blink:

Stay_Strong 16.03.2017 15:30

Нет, мне достаточно сложно сразу собирать плагин. Я реализую функционал. Потом создаю только объект default, и преобразую в плагин потом. Плагин можете посмотреть вот здесь мой (который на jquery).

А вообще принимаю любые советы по более правильной реализации структуры и оптимизации кода.

Rise 16.03.2017 17:23

Stay_Strong, смотри uncompressed версию jquery, там сделано примерно так:
function nextAll(elem) {
	var matched = [];
	while (elem = elem.nextSibling) {
		if (elem.nodeType === 1) {
			matched.push(elem);
		}
	}
	return matched;
}

PS: у меня вот что получилось)

PROPHESSOR 16.03.2017 17:41

А ты посмотри, как в JQuery это реализовано :)

рони 16.03.2017 17:56

nextAll на js
 
:write:
<!DOCTYPE html>

<html>
<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style type="text/css">
  .test{
    background-color: #008000;
  }
  .red{
    background-color: #FF0000;
  }

  </style>


</head>

<body>
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item test">test</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
 <script>
function nextAll(elem) {
    var next = false;
    return [].filter.call(elem.parentNode.children, function(child) {
        if (child === elem) next = true;
        return next && child !== elem
    })
};

var div = document.querySelector(".test"), next = nextAll(div);
next.forEach(function(el) {
       el.classList.add('red');
});

  </script>


</body>
</html>

Stay_Strong 16.03.2017 20:22

рони,
Спасибо, не подскажите, как мне на чистом js вот такое изобразить

$.fn.mobileMenu = function (options) {};


На jquery это просто. Делаю по своему же примеру https://github.com/WebTravel/multile.../mobileMenu.js

Там создаю объект default, потом расширяю еще option при помощи extand. А потом нужно бы возвращать первый элемент и делать это плагином.. А как я не в упор. Пока вот такое у меня:
var defaults = {
    //....
  }

  function LoadElements(element, options) {
    var extend = function(out) {
      out = out || {};
      for (var i = 1; i < arguments.length; i++) {
        if (!arguments[i])
          continue;
        for (var key in arguments[i]) {
          if (arguments[i].hasOwnProperty(key))
            out[key] = arguments[i][key];
        }
      }
      return out;
    };

    this.options = extend({}, defaults, options);
    this.element = element;
    this.init();
  }


Дальше будет

LoadElements.prototype.init = function () {
// тело плагина
}


И дальше как раз нужно вызов осуществлять, как в $.fn
Вопрос: а как?

рони 16.03.2017 20:46

Stay_Strong,
Небольшая JavaScript библиотека в jQuery стиле включающая собственные функции

рони 16.03.2017 20:51

Цитата:

Сообщение от Stay_Strong
создаю объект default, потом расширяю еще option при помощи extand

Object.assign

Stay_Strong 21.03.2017 18:29

рони,
Не подскажите, почему у меня this не берется, а документ передается в функцию prototype?

window.onload = function() {

  var defaults = {
    'childrenElements' : '.filter__option',//дочерние элементы, больше числа которых появляется кнопка раскрытия
    'count' : '3',//число, после которого появится раскрытие
    'speed' : '250',//скорость раскрытия блока по нажатию на кнопку показа
    'textMore' : '+ Показать все',//Текст для кнопки "Показать все"
    'textLess' : '- Скрыть'//Текст для кнопки "Cкрыть"
  }


  function LoadElements(element, options) {
    var extend = function(out) {
      out = out || {};
      for (var i = 1; i < arguments.length; i++) {
        if (!arguments[i])
          continue;
        for (var key in arguments[i]) {
          if (arguments[i].hasOwnProperty(key))
            out[key] = arguments[i][key];
        }
      }
      return out;
    };

    this.options = extend({}, defaults, options);
    this.element = element;
    this.init();
  }


  LoadElements.prototype.init = function() {
    var self = this;
    //Переменные, используемые в плагине
    var elList = document.querySelectorAll(self); //находим все элементы на странице, к которым нужно применить метод

    Array.prototype.forEach.call(elList, function(el, i) { //Обходим в цикле все элементы
        var countChildren = elList[i].querySelectorAll(self.options.childrenElements);
        if(countChildren.length > self.options.count) {
          //Создаем контейнер, куда будем перемещать все элементы, которые нужно скрыть.
          var container = document.createElement('div');
              container.className = 'loadContainer';
          //Создаем кнопку для раскрытия списка
          var showAll = document.createElement('div');
              showAll.className = 'loadMore';
              showAll.innerHTML = self.options.textMore;
          //Присваиваем контейнер в наш элемент
          elList[i].appendChild(container);
          //Присваиваем кнопку в наш элемент
          elList[i].appendChild(showAll);
          //Выбираем все элементы, которые будем скрывать и отправлем их в контейнер
          for(var j = 0; j < countChildren.length; j++) {
            if(j > self.options.count - 1) {
              container.appendChild(countChildren[j]);
            }
          }

          //Поочередно разворачиваем и сворачиваем контейнер при нажатии
          showAll.onclick = function() {
            this.previousElementSibling.classList.toggle('active');
          }

        }

    });

  }

  (function(window) {
    window.loadElements = function(element, options) {
        this.element = element;
        new LoadElements(this, options);
    }
    return this;
  })(window);

  document.querySelectorAll('.filter__item').loadElements(); 

}


<div class="filter__wrapper">
<form action="" class="filter">
<div class="filter__item">
          <div class="filter__name">Производители</div>
          <div class="filter__option--wrapper">
            <div class="filter__option">
              <input id="check1" type="checkbox"/>
              <label for="check1">ACV</label>
            </div>
            <div class="filter__option">
              <input id="check2" type="checkbox"/>
              <label for="check2">AE&T</label>
            </div>
            <div class="filter__option">
              <input id="check3" type="checkbox"/>
              <label for="check3">Ariston</label>
            </div>
            <div class="filter__option">
              <input id="check4" type="checkbox"/>
              <label for="check4">Armada</label>
            </div>
            <div class="filter__option">
              <input id="check5" type="checkbox"/>
              <label for="check5">Baxi</label>
            </div>
            <div class="filter__option">
              <input id="check6" type="checkbox"/>
              <label for="check6">Buderus</label>
            </div>
            <div class="filter__option">
              <input id="check7" type="checkbox"/>
              <label for="check7">Chaffoteaux</label>
            </div>
            <div class="filter__option">
              <input id="check8" type="checkbox"/>
              <label for="check8">Matrix</label>
            </div>
            <div class="filter__option">
              <input id="check9" type="checkbox"/>
              <label for="check9">MATRIX</label>
            </div>
          </div>
        </div>
</form>
</div>

рони 21.03.2017 18:52

Stay_Strong,
может тот кто лучше знает ООП подскажет.

Rise 22.03.2017 07:33

Stay_Strong, extend из конструктора убери не красиво он там)

Stay_Strong 22.03.2017 09:11

Rise,
Почему нельзя так обрабатывать extend? И как мне передать мой селектор? Как только я попадаю в функцию инициализации, вывожу console.log(this) и на выходе получаю весь документ, вместо моего селектора, к которому применяю метод. Вы понимаете в этом, могу взять урок по скайпу за плату.

ksa 22.03.2017 09:29

Цитата:

Сообщение от Stay_Strong
могу взять урок по скайпу за плату

Можно тут сделать простенький пример, иллюстрирующий проблему - на нем тебе расскажут чего ты намудрил.

У тебя пока огрызки кода. Да и в них столько мешанины шо пипец!

Rise 22.03.2017 11:45

Stay_Strong, в чем цель отказа от jquery, если есть возможность создать кастомный билд где заменить Sizzle на querySelectorAll, и исключить не нужные модули, также есть слим билды где уже вырезаны некоторые модули, может тебе стоит наоборот полностью в праведный jquery стиль переписать плагин и попрактиковаться в создании билдов, ведь jquery есть тоже плагин на нативном JS)

рони 22.03.2017 12:15

Скрыть элементы больше чем ...
 
Stay_Strong,
<!DOCTYPE html>

<html>
<head>
  <title>Untitled</title>
  <meta charset="utf-8">
  <style type="text/css">
  .loadContainer{
    display: none;
  }
  .loadContainer.active{
    display:  block;
  }
  </style>
  <script>
 if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target, firstSource) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }

        var keysArray = Object.keys(Object(nextSource));
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}
 window.addEventListener("DOMContentLoaded", function() {

    function wrap(create, elms, all) {
        function fn(item, i) {
            var to = all || i == len - 1 ? create : create.cloneNode(true);
            item = item.parentNode.replaceChild(to, item);
            to.appendChild(item)
        }
        var len = elms.length;
        len ? [].forEach.call(elms, fn) : fn(elms)
    }
    var defaults = {
        "childrenElements": ".filter__option",
        "count": "3",
        "speed": "250",
        "textMore": "+ Показать все",
        "textLess": "- Скрыть"
    };
    window.LoadElements = function LoadElements(elements, options) {
        if (!(this instanceof LoadElements)) return new LoadElements(elements, options);
        this.options = Object.assign({}, defaults, options);
        this.elements = typeof elements === "string" ? document.querySelectorAll(elements) :
            elements.length ? elements : [elements];
        this.init()
    };
    LoadElements.prototype.init = function() {
        var self = this;
        [].forEach.call(self.elements, function(el) {
            var countChildren = el.querySelectorAll(self.options.childrenElements);
            countChildren = [].slice.call(countChildren, self.options.count);
            if (countChildren.length) {
                var container = document.createElement("div");
                container.className = "loadContainer";
                wrap(container, countChildren, true);
                var showAll = document.createElement("div");
                showAll.className = "loadMore";
                showAll.innerHTML = self.options.textMore;
                showAll.addEventListener("click", function() {
                    container.classList.toggle("active");
                    showAll.innerHTML = container.classList.contains("active") ? self.options.textLess : self.options.textMore
                });
                container.parentNode.insertBefore(showAll, container.nextSibling)
            }
        })
    };
    LoadElements(".filter__item")
});
  </script>
</head>

<body>
<div class="filter__wrapper">
<form action="" class="filter">
<div class="filter__item">
          <div class="filter__name">Производители</div>
          <div class="filter__option--wrapper">
            <div class="filter__option">
              <input id="check1" type="checkbox"/>
              <label for="check1">ACV</label>
            </div>
            <div class="filter__option">
              <input id="check2" type="checkbox"/>
              <label for="check2">AE&T</label>
            </div>
            <div class="filter__option">
              <input id="check3" type="checkbox"/>
              <label for="check3">Ariston</label>
            </div>
            <div class="filter__option">
              <input id="check4" type="checkbox"/>
              <label for="check4">Armada</label>
            </div>
            <div class="filter__option">
              <input id="check5" type="checkbox"/>
              <label for="check5">Baxi</label>
            </div>
            <div class="filter__option">
              <input id="check6" type="checkbox"/>
              <label for="check6">Buderus</label>
            </div>
            <div class="filter__option">
              <input id="check7" type="checkbox"/>
              <label for="check7">Chaffoteaux</label>
            </div>
            <div class="filter__option">
              <input id="check8" type="checkbox"/>
              <label for="check8">Matrix</label>
            </div>
            <div class="filter__option">
              <input id="check9" type="checkbox"/>
              <label for="check9">MATRIX</label>
            </div>
          </div>
        </div>
 <div class="filter__item">
          <div class="filter__name">Производители</div>
          <div class="filter__option--wrapper">
            <div class="filter__option">
              <input id="check1" type="checkbox"/>
              <label for="check1">ACV</label>
            </div>
            <div class="filter__option">
              <input id="check2" type="checkbox"/>
              <label for="check2">AE&T</label>
            </div>
            <div class="filter__option">
              <input id="check3" type="checkbox"/>
              <label for="check3">Ariston</label>
            </div>
            <div class="filter__option">
              <input id="check4" type="checkbox"/>
              <label for="check4">Armada</label>
            </div>
            <div class="filter__option">
              <input id="check5" type="checkbox"/>
              <label for="check5">Baxi</label>
            </div>
            <div class="filter__option">
              <input id="check6" type="checkbox"/>
              <label for="check6">Buderus</label>
            </div>
            <div class="filter__option">
              <input id="check7" type="checkbox"/>
              <label for="check7">Chaffoteaux</label>
            </div>
            <div class="filter__option">
              <input id="check8" type="checkbox"/>
              <label for="check8">Matrix</label>
            </div>
            <div class="filter__option">
              <input id="check9" type="checkbox"/>
              <label for="check9">MATRIX</label>
            </div>
          </div>
        </div>
</form>
</div>


</body>
</html>

Stay_Strong 29.03.2017 18:13

рони,
Вот вы мне тут накатали, спасибо огромное, конечно. Теперь мне тут со всем разобраться нужно, потому что это совсем стиль, не тот, в котором я писал и пишу. Вы уроки не даете по скайпу?

P.S.: Здесь совсем все по-взрослому, без комментариев не разберусь.

рони 29.03.2017 18:24

Stay_Strong,
попробуйте разобраться самостоятельно ...


Часовой пояс GMT +3, время: 06:37.