• В чем суть роутера на php?

    onqu
    @onqu
    weasy
    1. Здесь пугают всякими контроллерами, ларавелями. Давайте жить проще. Для начала дадим определение модному слову роутер. Это маршрутизатор. Что делает маршрутизатор? Правильно. Обрабатывает маршруты, являясь связующим звеном. Маршрутом для web сайта принято считать метод запроса [GET, POST, PUT и другие] и компоненты URI.

    например: https://ru.wikipedia.org/wiki/URI?foo=bar#title
    [схема: https] :// [источник: ru.wikipedia.org] [путь: /wiki/URI] [запрос: ?foo=bar] [фрагмент: #title]


    Но для определения маршрута может браться любая другая информация передаваемая серверу, определение выше это лишь наиболее употребляемые параметры.

    Сама работа, как правило проста: от клиента приходит запрос, маршрутизатор перебирает все заданные ему пути до первого совпадения. При совпадении вызывается определенная вами функция, которая возвращает ответ клиенту.

    2. Он необходим, если в приложении одна точка входа, когда любой запрос приходит на один файл.

    3. Простой пример
    // файл index.php
    
    // Маршруты
    // [маршрут => функция которая будет вызвана]
    $routes = [
        // срабатывает при вызове корня или /index.php
        '/' => 'hello',
        // срабатывает при вызове /about или /index.php/about
        '/about' => 'about',
        // динамические страницы
        '/page' => 'page'
    ];
    
    // возвращает путь запроса
    // вырезает index.php из пути
    function getRequestPath() {
        $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
    
        return '/' . ltrim(str_replace('index.php', '', $path), '/');
    }
    
    // наш роутер, в который передаются маршруты и запрашиваемый путь
    // возвращает функцию если маршшрут совпал с путем
    // иначе возвращает функцию notFound
    function getMethod(array $routes, $path) {
        // перебор всех маршрутов
        foreach ($routes as $route => $method) {
            // если маршрут сопадает с путем, возвращаем функцию
            if ($path === $route) {
                return $method;
            }
        }
    
        return 'notFound';
    }
    
    // функция для корня
    function hello() {
        return 'Hello, world!';
    }
    
    // функция для страницы "/about"
    function about() {
        return 'About us.';
    }
    
    // чуть более сложный пример
    // функция отобразит страницу только если
    // в запросе приходит id и этот id равен
    // 33 или 54
    // [/page?id=33]
    function page() {
    
        $pages = [
            33 => 'Сага о хомячках',
            54 => 'Мыши в тумане'
        ];
    
        if (isset($_GET['id']) && isset($pages[$_GET['id']])) {
            return $pages[$_GET['id']];
        }
    
        return notFound();
    }
    
    // метод, который отдает заголовок и содержание для маршрутов,
    // которые не существуют
    function notFound() {
        header("HTTP/1.0 404 Not Found");
    
        return 'Нет такой страницы';
    }
    
    
    // Роутер
    // получаем путь запроса
    $path = getRequestPath();
    // получаем функцию обработчик
    $method = getMethod($routes, $path);
    // отдаем данные клиенту
    echo $method();


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

    4. Обойтись без него можно. Если каждая страница в вашем приложении будет являться отдельным файлом, который отвечает за отдачу информации.
    index.php
    about.php
    contact.php
    ...


    Это олдскульная структура, в новых проектах почти не применяется.
    Ответ написан
    13 комментариев
  • С чем связана ошибка?

    @alexprowars
    У вас в момент загрузки скрипта этого элемента нет на странице, оберните код в функцию

    document.addEventListener('DOMContentLoaded', function() {
    });
    Ответ написан
    Комментировать
  • Как эффективно блокировать пользователя на сайте?

    FanatPHP
    @FanatPHP
    Чебуратор тега РНР
    Как эффективно блокировать пользователя на сайте?

    никак
    Как по вашему мнению, активация акка с привязкой к телефону более чем эффективна

    Не более, но эффективна.
    Есть ли смысл наворачивать к такой активации еще что то ?

    Нет.

    Другое дело, что вы тут же потеряете массу лояльных пользователей, которые не захотят получать спам на свой телефон.
    Ответ написан
    Комментировать
  • Как определить появление элемента во вьюпорт?

    @Ridz
    full необязательный параметр, если full = true, функция вернёт true, только когда элемент полностью виден.
    function elemInViewport(elem,full) {
        var box = elem.getBoundingClientRect();
        var top = box.top;
        var left = box.left;
        var bottom = box.bottom;
        var right  = box.right;
        var width = document.documentElement.clientWidth;
        var height = document.documentElement.clientHeight;
        var maxWidth = 0;
        var maxHeight = 0;
        if(full) { maxWidth = right - left; maxHeight = bottom - top};
        return Math.min(height,bottom)- Math.max(0,top) >= maxHeight && Math.min(width,right)- Math.max(0,left)>= maxWidth
    }
    Ответ написан
    2 комментария
  • Почему импорт модуля не считает подключение верхним уровнем?

    yarkov
    @yarkov Куратор тега JavaScript
    Помог ответ? Отметь решением.
    Надо всем скриптам указать атрибут type="module".
    Ну и на всякий случай поменять их местами.
    Ответ написан
    1 комментарий
  • Как при доскроливании к элементу добавлять класс блоку?

    @MEDIOFF
    Python Developer
    Как я понимаю класс animated
    function scrollReveal() {
          var revealPoint = 150;
          var revealElement = document.querySelectorAll(".scrollReveal");
          for (var i = 0; i < revealElement.length; i++) {
            var windowHeight = window.innerHeight;
            var revealTop = revealElement[i].getBoundingClientRect().top;
            if (revealTop < windowHeight - revealPoint) {
              revealElement[i].classList.add("animated");
            }
          }
        }
    
        window.addEventListener("scroll", scrollReveal);
        scrollReveal();


    просто убирите блок else,
    можно еще удалять eventListener, потому что как я понимю нужда в нем отпадает:

    spoiler
    function scrollReveal() {
          var revealPoint = 150;
          var revealElement = document.querySelectorAll(".scrollReveal");
          for (var i = 0; i < revealElement.length; i++) {
            var windowHeight = window.innerHeight;
            var revealTop = revealElement[i].getBoundingClientRect().top;
            if (revealTop < windowHeight - revealPoint) {
              revealElement[i].classList.add("animated");
              window.removeEventListener('scroll', scrollReveal)
            }
          }
        }
    
        window.addEventListener("scroll", scrollReveal);
        scrollReveal();
    Ответ написан
    Комментировать
  • Как обрабатывать formData на сервере PHP?

    SagePtr
    @SagePtr
    Еда - это святое
    Потому что заголовок устанавливаете
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    А данные отправляете в другом формате - multipart/form-data
    И как по-вашему PHP должен обрабатывать пользовательский ввод, в котором содержимое не соответствует заявленному в заголовке типу?
    Ответ написан
    2 комментария
  • Как сделать калькулятор с ползунками?

    Stalker_RED
    @Stalker_RED
    Для изменения внешнего вида есть куча способов стилизировать input range (на js или css).

    А дальше слушаете на форме событие input или change и применяете вашу формулу расчета.
    Ответ написан
    1 комментарий
  • Как перегнать jQuery в Javascript?

    Seasle
    @Seasle Куратор тега JavaScript
    You might not need jQuery
    Как-то так

    const wrappers = document.querySelectorAll('.how_it_works');
    const svgLine = document.querySelector('#svg-line');
    const line12 = svgLine.querySelector('.line-1-2');
    const line23 = svgLine.querySelector('.line-2-3');
    const line34 = svgLine.querySelector('.line-3-4');
    const line45 = svgLine.querySelector('.line-4-5');
    
    const setAttributes = (element, attrs) => {
    	for (const attr in attrs) {
    		element.setAttribute(attr, attrs[attr]);
    	}
    };
    
    const line = (wrapper) => {
    	const wrapperBox = wrapper.getBoundingClientRect();
    	const items = wrapper.querySelectorAll('.block_line .item');
    	const points = [];
    
    	for (const item of items) {
    		const element = item.querySelector('.num');
    		const box = element.getBoundingClientRect();
    
    		points.push({
    			x: box.left + box.width / 2 - wrapperBox.left,
    			y: box.top + box.height / 2 - wrapperBox.top
    		});
    	}
    
    	svgLine.style.setProperty('top', 0);
    	svgLine.style.setProperty('left', 0);
    
    	setAttributes(line12, {
    		x1: points[0].x,
    		y1: points[0].y,
    		x2: points[1].x,
    		y2: points[1].y
    	});
    	setAttributes(line12, {
    		x1: points[1].x,
    		y1: points[1].y,
    		x2: points[2].x,
    		y2: points[2].y
    	});
    	setAttributes(line12, {
    		x1: points[2].x,
    		y1: points[2].y,
    		x2: points[3].x,
    		y2: points[3].y
    	});
    	setAttributes(line12, {
    		x1: points[3].x,
    		y1: points[3].y,
    		x2: points[4].x,
    		y2: points[4].y
    	});
    };
    
    const start = () => {
    	for (const wrapper of wrappers) {
    		line(wrapper);
    	}
    };
    
    start();
    
    window.addEventListener('resize', start);

    Ответ написан
    8 комментариев
  • Как написать скрипт для счётчика который будет менять цену в зависимости с количеством товара?

    Tim-A-2020
    @Tim-A-2020
    примерно накидал. Дальше сами. Примерно такой логике событие change или blur нужно сделать
    Ответ написан
    1 комментарий
  • Как узнать что отмеченные чекбоксы идут по порядку?

    Simkav
    @Simkav
    Через селектор собираете все чекбоксы, и проверете какие из них checked
    Ответ написан
    5 комментариев
  • Как проверить скобки в строке?

    Rsa97
    @Rsa97
    Для правильного вопроса надо знать половину ответа
    Такие задачи решаются через общий стек. При поступлении на вход открывающей скобки на стек кладётся соответствующая закрывающая скобка (или эквивалентный код). При поступлении закрывающей скобки снимается вершина стека и проверяется на совпадение с ней.
    Например

    function check(str, bracketsConfig) {
      let bconf = bracketsConfig.reduce(
        (acc, val) => {
          acc[val[0]] = val[1];
          acc[val[1]] = null;
          return acc;
        },
        {}
      );
      let stack = [];
      for (let i = 0; i < str.length; i++) {
        let char = str[i];
        if (bconf[char] === null) {
          if (stack.pop() !== char) {
            return false;
          }
        } else if (bconf[char] !== undefined) {
          stack.push(bconf[char]);
        }
      }
      if (stack.length !== 0) {
        return false;
      }
      return true;
    }

    Ответ написан
    Комментировать
  • Есть ли JavaScript библиотека максимально похожая на Google Sheets?

    oshliaer
    @oshliaer
    Google Products Expert
    Возможно, лучшим предложением будет https://myliang.github.io/x-spreadsheet
    60163c8f90202752482539.png
    в то время, как контейнером таблицы я бы предпочел https://sheetjs.com за надежность. Если у вас нет необходимости в формулах, то возьмите второе.
    60163c63d87f3460037426.png
    Ответ написан
    2 комментария
  • Как работает этот код?

    vabka
    @vabka
    Токсичный шарпист
    https://developer.mozilla.org/ru/docs/Web/JavaScri...
    например:
    const two = 2;
    function square(n) {
      return n*n;
    }
    const result = square(two);
    console.log(result);

    Почему тут функция смотрит на n, но видит two?
    Ответ написан
    Комментировать
  • Бюджетная водянка на процессор - стоит ли?

    xez
    @xez
    TL Junior Roo
    Водянка - это для тех, кто не наигрался в конструктор. Дорого, не надежно. Какой-то существенной разницы в температурах или в уровне шума там нет.
    За 70 евро можно купить такие суперкуллеры как GamerStorm Assassin III, Thermalright Macho Rev.B... Еще чуть добавить - вот вам и be quiet! DARK ROCK PRO 4.
    Каждый из них легко справится с вашим процесором и даже шуметь не будет.
    Или раскошелиться на Noctua NH-D15 или Thermalright Silver Arrow IB-E Extreme Rev. B - не каждая водянка их обойдет.
    Я не предлагаю мне верить на слово - посмотрите тесты Thermalright Macho Rev.B и сами решите - стоит ли геморой с водянкой этих градусов.
    Ответ написан
    6 комментариев
  • Как отфильтровать ключи в URLSearchParams?

    Seasle
    @Seasle Куратор тега JavaScript
    for (const key of utm) {
        params.delete(key);
    }

    UPD:
    const href = 'https://example.com/?user=John&some_key=1&id=3';
    const url = new URL(href);
    const availableKeys = ['user', 'id'];
    for (const key of [...url.searchParams.keys()]) {
        if (!availableKeys.includes(key)) {
            url.searchParams.delete(key);
        }
    }
    console.log(url.toString()); // 'https://example.com/?user=John&id=3'
    Ответ написан
    8 комментариев
  • Когда стоит вкладывать input в label, а когда нет?

    DanArst
    @DanArst Куратор тега HTML
    Гриффиндор в моде при любой погоде!
    Значения не имеет.
    Просто есть два способа связи тега label с элементом формы/объектом:
    1 - помещение объекта внутрь тега
    <label><input type="text"> Пример 1</label>

    2 - при помощи id
    <input id="example-2" type="text"><label for="example-2">Пример 2</label>
    Ответ написан
    1 комментарий
  • Как передать через fetch() на бекенд картинку?

    Tim-A-2020
    @Tim-A-2020
    let data = new FormData();
    
    
    data.append('file', input.files[0]);
    
    const options = {
      method: 'POST',
      body: data	
    }
    
    const response = await fetch('url', options);
    const res = await response.json();
    console.log(res);
    Ответ написан
    1 комментарий
  • Устарел ли getElementsBy* и чем лучше querrySelector?

    bingo347
    @bingo347 Куратор тега JavaScript
    Crazy on performance...
    Вот народ ушел в спор о производительности, но никто даже не попытался разобраться, а что под капотом... Производительность ведь искусственными бенчмарками меряют, ага...
    Что ж, времена сейчас такие
    многие на работу кодеров берут, которые даже интереса не имеют в глубь копать. Инженеров брать... - это устаревший подход, как выразился автор "популярного сайта", который прочел автор вопроса. Инженеры они дорогие, и найти их сложно, лучше кодер, пусть и не желающий на работе мозг включать, не говоря уж о желании в устройстве инструментов разбираться.

    Говорить о том, что некие фичи устарели - крайне глупо, если знать, что они ведут себя иначе, чем более модные альтернативы. Предлагаю немного разобраться и начать с того что на поверхности:
    - getElementById и querySelector возвращают конкретную ноду в единственном экземпляре
    - querySelectorAll и getElementsByName возвращает статичную коллекцию NodeList
    - getElementsByClassName, getElementsByTagName и getElementsByTagNameNS возвращают динамическую коллекцию HTMLCollection
    Как видим результат у разного апи различен, а значит и говорить, что некоторые из них устарели - глупо.
    Правда тут есть забавный момент
    в спеке HTMLCollection отмечен как "исторический артефакт", который не стоит использовать при проектировании нового апи. Но заметка эта не для веб-разработчиков, а для тех кто проектирует новое DOM апи.

    С устареванием вроде разобрались, но в вопросе еще есть часть "чем лучше". И тут есть теория, что getElementsBy* быстрее querySelector*. Чисто теоретически звучит логично, querySelector* должен делать полный поиск по дереву со сложностью O(n), а getElementsBy* могут использовать индексы на базе HashMap и получать данные со сложностью O(1), тут и особенности HTMLCollection будут кстати, так как можно не копировать коллекцию, а отдавать одну и ту же (и браузеры действительно так делают). Но без пруфов теория так и останется теорией.
    И бенчмарки - так себе пруф
    Хотя направлять инвесторов в нужную сторону - самое то. Проблема бенчмарков, что можно написать их так, что любая из сравниваемых сторон заметно обгонит другую. Дело техники. Например BubbleSort с O(n2) при определенных условиях в чистую уделывает MergeSort и QuickSort с их O(n×log2n), а именно при n=20 или меньше, 400 простых memswap в наглую рвут 87 рекурсивных операций с memcpy внутри
    Гораздо лучше тут выглядят исходники. И я выбрал исходники chromium, как самого распространенного:
    - getElementsBy* методы все как один обращаются к некой шаблонной функции EnsureCachedCollection, которая в свою очередь обращается к некоему NodeLists кэшу, устроенному внутри действительно как HashMap или что-то наподобие. Никакого поиска тут нет, просто берутся готовые значения, сложность у всего этого действительно константная O(1).
    - querySelector* используют абстракцию SelectorQuery, которая и в самом деле делает поиск по DOM. Но данный поиск неплохо оптимизирован и обвешан кэшами. Притом CSSOM использует абсолютно тот же алгоритм поиска DOM нод для каждого селектора в css.
    Для примера
    в подключенных на странице этого вопроса стилях более 1600 правил (некоторые из которых потенциально могут содержать несколько селекторов), полная обработка стилей из этого файла заняла на моей машине (Ryzen 3600 в стоке) чуть больше 9 мс. Если все это немного округлить, то понадобится 15000 querySelectorAll подряд, притом с разными селекторами, чтоб был промах кэша, дабы я ощутил заметную глазу задержку в ~100мс


    На этом спор думаю можно закрыть. querySelector* методы действительно могут быть медленнее, но чтоб убить ими производительность, нужно очень постараться. На фоне того, что пишут кривые ручки среднестатистического дешевого js-кодера это будет незначительной потерей измеряемой в наносекундах. Используйте то что удобнее в каждой конкретной ситуации.
    Ответ написан
    1 комментарий
  • Устарел ли getElementsBy* и чем лучше querrySelector?

    @eandr_67
    web-программист (*AMP, Go, JavaScript, вёрстка).
    Нет, не устарел: да, querySelector и querySelectorAll намного универсальнее (почти jQuery), но из-за своей универсальности могут быть чуть медленеее, чем специализированные getElementsBy*.
    Ответ написан
    6 комментариев