Ответы пользователя по тегу JavaScript
  • Как добавлять в билд Vite файл js без type module?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Если ты их руками в html вписываешь - там у тебя в корне должна быть папка public(если нет - создай) - туда и клади, он тупо их перекопирует в dist.
    Если же эти скрипты должны работать где-то в рамках других, то пиши где надо import '<script_path>'; (без from и всего такого).
    Ответ написан
    1 комментарий
  • Ошибка при отправке POST запроса на open server?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Проблема скорее всего тут .then(response => console.log(response.json())). И скорее всего в том, что твой сервер по адресу db.json отдаёт вместо json какую-то фигню. Открой вкладку Сеть в инструментах разработчика и посмотри, что тебе от сервера в ответ на твой POST приходит.
    Ответ написан
    7 комментариев
  • Как проверить объект на присутствие неизвестного ключа?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    function isPermittedObject(obj) {
      if (!obj) return false;
      
      const permitted = new Set(["v", "c", "g"]);
      let max = 1;
    
      for (const key in obj)
        if (!permitted.has(key) || !max--) 
          return false;
      return true;
    }
    
    console.log(!isPermittedObject({
      v: 1,
      c: 3,
      g: 5
    }))
    
    console.log(!isPermittedObject({
      v: 1
    }))
    Ответ написан
    Комментировать
  • Почему JS код выполняется повторно?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Проблема не в этом коде, очевидно:
    Скорее всего ты просто подключаешь этот код два раза. Проищи внимательнее.
    Ответ написан
    Комментировать
  • Как задать логику преобразования объекта в массив?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Что-то типа такого:
    class Users {
      constructor() {
        this.store = []
      }
      [Symbol.iterator] = () => this.store[Symbol.iterator]() 
    }
    Но взможно вам проще и красивее будет сделать самих User'ов наследником массива:
    class Users extends Array {
      constructor() {
        super();
      }
    }
    И использовать сразу this вместо this.store со всеми методами массива кроме тех которые вы переопределите:).
    Ответ написан
    3 комментария
  • Как происходит кеширование, если вызывает функция slow?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    В js функция не является чем-то особенным и неприкасновенным.

    function slow(x) { ... }
    Утириовано: создана функция и положена в переменную slow, аналогично:
    var slow;
    slow = function (x) { ... };


    slow = cachingDecorator(slow);
    Пишем в переменную результат вызова cachingDecorator с аргументом из slow.

    Всё происходит по порядку:
    0. Создаётся функция и кладётся в пременую slow.
    1. Берётся текушая функция из slow.
    2. Кладётся в аргуметы cachingDecorator.
    3. Результат cachingDecorator(slow) кладётся в переменную slow.

    Есть всякие нюансы и оговорки, но в целом не следует переусложнять, со всеми сущностями в js можно работать одинаково.
    Ответ написан
    5 комментариев
  • Как добавить в каждый объект массива новое свойство?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Ответ drawnofmymind не отвечает на заданный вопрос "как добавить", т.к. создаёт полностью новый массив с полностью новыми объектами.

    В некоторых случаях это предпочтительнее(когда необходима иммутабельность), но ответ именно на заданный вопрос куда проще:
    items.forEach(item => item.alert = false)
    Ответ написан
    1 комментарий
  • Как сделать фильтрацию?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Чтоб сделать фильтрацию просто делаешь так:
    const [selected, setSelected] = useState('all');
    
      let filterdTodos;
      switch(selected) {
        case 'all':
          filterdTodos = todos;
          break;
        case 'checked':
          filterdTodos = todos.filter(t => t.checked);
          break;
        case 'notChecked':
          filterdTodos = todos.filter(t => !t.checked);
          break;
      }

    Или так, с оптимизацией:
    const [selected, setSelected] = useState('all');
    
      const filterdTodos = useMemo(() => {
        switch(selected) {
          case 'all':
            return todos;
          case 'checked':
            return todos.filter(t => t.checked);
          case 'notChecked':
            return todos.filter(t => !t.checked);
        }
      }, [selected, todos])

    <select className="todos__filter" onChange={(event) =>setSelected(event.target.value)}>
    ...
    {filterdTodos.map(...)}
    Ответ написан
  • Как решить проблему исчезновения данных товаров при перезагрузке страницы во Vue.js приложении?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Во-первых: не используй onMounted внутри стора. onMounted - это хук компонента, а не стора. Оно работает только благодаря стечению обстоятельств.
    Во вторых: products должны быть ref. Сейчас они не реактивны(никак не реагируют на изменения). При этом ты присваииваешь массиву value. То что это хоть как-то работало - очередное чудо.
    В-третьих: ты должен учитывать, что какое-то время данные будут грузиться и показывать лоадер пока их нет.

    В общем если загрузка должна начинаться в лбом случае при первой инициализации store'a(обычно загрузку привязывают к маршрутам или компонентам), то выглядеть оно будет как-то так:
    export const useAllMainFiltersStore = defineStore('allMainFilters', () => {
      const products = ref([]);
    
      try {
        async function getStoreData() {
          sidebarResizeStore.updateSidebarVisibility()
          const data = await productsData();
          products.value = data;
        }
        getStoreData()
      } catch (error) {
        console.error('Error:', error);
      }
      
      return {
        products,
      }
    })


    В компоненте:
    const route = useRoute();
    // продукт делаем вычисляемым, чтоб не городить вотчеров
    const product = computed(() => getProductById(route.params.id));
    
    function getProductById(id) {
      console.log('products component: ', mainFiltersStore.products) //при первой загрузке всё ок, при перезагрузке страницы всё ломается и пустой массив в придачу
      return products.find(product => product.id == id);
    }
    
    watch(product, current => {
      // проверяем что продукт есть
      if (current) fetchComments(current.id);
    }, { immediate: true })
    Ответ написан
    3 комментария
  • Откуда берутся iron icon?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Ну собсно как и всегда когдадокументация говно - идёшь на гитхаб, там открываешь код и смотришь как оно работает.
    Тут благо прямо в коде есть ссылка на описание кастомных иконсетов. Точно также как там в примере кастомный иконсет inline, тут используется кастомный иконсет settings.
    Ответ написан
  • Почему при отсчете времени на iPhone выводит 'NaN' вместо цифр?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Ну потому что 2023-10-21 7:00:00 PM GMT+0300 - это херпойми какой формат. То что его чудом жрёт хром - это случайность.
    Используй ISO: 2023-10-21T19:00:00+0300
    Ответ написан
    Комментировать
  • Не видит значение input, как исправить?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Во-первых у input нет свойства length.
    var intxt=document.querySelector('input').length;
    intxt === undefined
    console.log вообще-то должен был тебе это показать.

    Далее: if(intxt.length<5){ тут ты пытаешься получить свойство length у unefined о чем тебе и пишет ошибка.

    Скорее всего ты хочешь что-то такое:
    var intxt=document.querySelector('input');
    ....
    if(intxt.value.length<5){
      ....
    } else {
    Ответ написан
    Комментировать
  • При решении каких задач используют генераторы?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    В практике генераторы не используются. Конец. :)

    На самом деле я лично видел ровно два практических кейса использования генераторов:
    1. Использование для асинхронных операций с возможностью прерывания, примеры: redux-saga, mobx actions.
    Суть: допустим ты делаешь какую-то ступенчатую операцию, и нужна возможность резко остановить исполнение извне. На async-ax тебе придётся городить что-то типа:
    async function multiStep() {
      await step1();
      if (stop) throw new Error(stop);
      await step2();
      if (stop) throw new Error(stop);
      await step3();
      if (stop) throw new Error(stop);
    }
    и никак красивее не сделать.
    На генераторе ты можешь просто писать:
    function* multiStep() {
      yield step1();
      yield step2();
      yield step3();
    }

    и просто не брать следующее значение, если исполнение прервалось.

    2. До появления воркеров с их помощью можно было работать с очень большими массивами не вызывая зависания страницы.

    На этом всё.:)
    Ответ написан
    2 комментария
  • Как добавить готоую форму amoCrm в Vue3?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Я хз что такое AmoCrm, но если надо тупо добавить не-vue скрипы как vue-компонент, то как-то так:
    import { ref, h } from 'vue';
    
    function loadScript(options, root = document.head) {
      return root.appendChild(Object.assign(document.createElement('script'), options));
    }
    
    const Comp = defineComponent(() => {
      const root = ref(null);
    
      onMounted(() => {
        loadScript(
          {
            innerHTML: `
          !(function (a, m, o, c, r, m) {
        (a[o + c] = a[o + c] || {
            setMeta: function (p) {
                this.params = (this.params || []).concat([p]);
            },
        }),
            (a[o + r] =
                a[o + r] ||
                function (f) {
                    a[o + r].f = (a[o + r].f || []).concat([f]);
                }),
            a[o + r]({
                id: "....",
                hash: "....",
                locale: "ru",
            }),
            (a[o + m] =
                a[o + m] ||
                function (f, k) {
                    a[o + m].f = (a[o + m].f || []).concat([[f, k]]);
                });
    })(window, 0, "amo_forms_", "params", "load", "loaded");
          `
          },
          root.value
        );
        loadScript(
          {
            id: 'amoforms_script_...',
            async: 'async',
            charset: 'utf-8',
            src: 'https://forms.amocrm.ru/forms/assets/js/amoforms.js?...'
          },
          root.value
        );
      });
    
      return () => h('div', { ref: root });
    });
    Ответ написан
  • Не получается подключить js файл через CDN, в чём может быть проблема?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Как надо: открываешь ссылку с библиотекой(например https://unpkg.com/tictic@0.1.0/) руками и находишь там версию UMD или без специальных пометок - это именно та что тебе нужна.
    ***
    ESM/ES/ES6 версия - это версия на модулях, её можно использовать только внутри script type="module" через import(никаких глобальных вызовов).
    CJS версия - это версия на Common JS, старого стандарта Node js, в браузере ты её использовать не сможешь без специального загрузчика.
    ***
    После этого копируешь себе ссылку убирая из неё /browse.

    В данной конкретной библиотеке НЕТ версии для обычного подключения через скрипт. Тебе остаётся либо использовать модуль, либо использовать систему сборки фронтэнда(vite, webpack, rollup, gulp...), либо отказаться от неё.

    P.S. С модулями оно будет выглядеть примерно так:
    <script type="importmap">
      {
        "imports": {
          "tictic": "https://unpkg.com/tictic@0.1.0/esm/index.js",
          "tslib": "https://unpkg.com/tslib@2.6.2/tslib.es6.js"
        }
      }
    </script>
    
    <script type="module">
      import { getDate } from 'tictic';
    
      console.log(getDate({}));
    </script>

    Как видишь тут пришлось добавить ещё и tslib, т.к. у tictic от неё зависимость, хорошо что только одна. Зачастую зависимостей целая куча и проще таки использовать системы сборки, чем все их прописывать руками.
    Так же стоит помнить что модули - это только для современных браузеров.
    Ответ написан
    Комментировать
  • Почему берет одну запись по селектору?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Для самого свежего хрома можно обойтись css:
    [role="row"]:has(.fraud) {
      background-color: #f1f7bc;
    }

    Для иных браузеров можно использовать такую извращенную классику(с оговорками):
    [role="row"] {
      position: relative;
      background-color: transparent;
    }
    [role="row"] .fraud::before {
      content: "";
      display: block;
      position: absolute;
      z-index: -1;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      background-color: #f1f7bc;
    }


    Ну либо использовать MutationObserver и следить за появлением новых [role="row"].
    Ответ написан
    Комментировать
  • Как при нажатии кнопки выводить поэтапно строки которые значение увеличивается на 1?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Для начала забудем о react и поговорим о javascript: javascript риусет ui в одном потоке, потому while - это атомарная операция. На экране ничего не отобразится пока while не закончит своё действие. Т.е. выведя 10 строк через while - ты сразу увидишь их на экране, они не будут появляться по одной. Если, конечно, не подключишь асинхронность с async и await внутри цикла.

    Теперь к react: отображение нескольких строк осуществляется с помощью массива:
    const lines = [1, 2, 3];
    
    return lines.map(line => (
      <p> {line} </p>
    ));


    Если ты хочешь, чтоб при клике добавлялась строчка, то состояние этого массива надо отслеживать, т.е. напримр положить его в state:
    function Component() {
      const [lines, setLines] = useState([1, 2, 3]);
      const addLine = useCallback(() => {
        setLines(lines => [...lines, lines.length+1])
      });
    
      return(
        <>
          <button onClick={addLine} className="button">
            addLine
          </button>
          {lines.map(line => (
            <p> {line} </p>
          ))}
        </>
    }


    Если ты хочешь, чтоб при клике постепенно добавлялась 10 строчек с задержкой, то это можно сделать с помощью setTimeout(тут я обернул его в Promise для простоты и наглядности):
    const delay = (ms) => new Promise(r => setTimeout(r, ms))
    
    function Component() {
      const [lines, setLines] = useState([]);
      const addLines = useCallback(async () => {
        let i = 0;
        while(i++ < 10) {
          await delay(1000);  
          setLines(lines => [...lines, i])
        }
      });
      return(
        <>
          <button onClick={addLines} className="button">
            addLine
          </button>
          {lines.map(line => (
            <p> {line} </p>
          ))}
        </>
      );
    }
    Ответ написан
    Комментировать
  • Проблема с цветом видео в разных браузерах?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Конечно сталкивались, и простого решения конкретной проблемы нет: видео это немного отдельный поток и там всегда могут быть свои настройки отображения.

    Решения есть следующие:
    1. Делать видео сразу с прозрачностью, а не с бэкграундом, современные браузеры это поддерживают:
    2. Рисовать видео на canvas, программно подгоняя фон.
    3. Накладывать SVG фильтр на видео, который погонит фон.
    Ответ написан
    Комментировать
  • Почему возникает ошибка Uncaught (in promise) DOMException: The element has no supported sources?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Мужик, просто попробуй открыть файл руками.
    Если возвращается "текущий HTML код страницы" и ошибка "The element has no supported sources" - вполне очевидно, что такого файла по такому адресу просто нет.
    Ответ написан