• Почему v-on:keyup.enter и @:keyup.enter работают по-разному?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    @:click -> @click, соответственно, не: @:keyup.enter, а @keyup.enter

    Ну и не относится к проблеме, но красивее писать так:
    @click="add()" -> @click="add"
    Ответ написан
  • Как динамически передавать методы или переменные в компонент который рэндерится через v-for?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Вот смотри, прям беру твой код и пихаю как есть:

    И смотри-ка, всё работает.
    Проблема твоя где-то в другом месте.

    P.S. По-нормальному это делается как-то так:
    const thumbs = reactive([null, null, null]);
    v-for="(swiper, i) in thumbs" @swiper="thumbs[i]=$event" :thumbs="{ swiper }"

    Но может и ещё проще, если бы было больше контекста.:)
    Ответ написан
  • Как остановить цикл по нажатию кнопки html / js?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Никак.
    По умолчанию, без специальных ухищрений, javascript работает в одном потоке.
    Пока цикл не завершится - вообще больше ничего не произойдёт, в т.ч. реакция на клик - страница тупо "зависает".
    Ответ написан
    Комментировать
  • Regex, Как сделать поиск всех совпадений слов?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Вот навскидку накидал франкенштейна(больше под свои задачи):
    function escapeRegExp(string) {
      return String(string).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }
    // для оптимизации неплохо бы завернуть в memoize-one
    const toSpacedRegExp = (needle, ignoreCase = true) => new RegExp(
      needle
      .trim()
      .split(/\s+/)
      .map(chunk => '(' + escapeRegExp(chunk) + ')')
      .join('(\\S*(?:\\s+\\S*)+?)'), 
      ignoreCase ? 'i' : ''
    );
    // для оптимизации неплохо бы завернуть в memoize-one
    const toSomeRegExp = (needle, ignoreCase = true) => new RegExp(
      needle
      .trim()
      .split(/\s+/)
      .map(chunk => '(' + escapeRegExp(chunk) + ')')
      .join('([\\S\\s]*)'), 
      ignoreCase ? 'i' : ''
    );
    
    // Возвращает либо false, либо массив разделённых совпадний
    // smartFind('start found rest', 'found') // ['start ', 'found', ' rest']
    // smartFind('start found rest', 'start') // ['', 'start', ' found rest']
    // удобно для подсвечивания найденного тупо через i % 2
    function smartFind(haystack, needle) {
      if (!haystack) return false;
      if (!needle) return ['', haystack, ''];
    
      // ищем сначала разделённые пробелами: ва ся => ВАся СЯпкин
      let result = haystack.split(toSpacedRegExp(needle));
      if (result.length > 1) return result;
    
      // ищем хоть какое-то совпадение: ва ся => ВАСЯ пупкин
      result = haystack.split(toSomeRegExp(needle));
      return result.length > 1 && result;
    }

    По ключевым словам "fuzzy search" можно найти куда оптимальнее и красивее вещи, но тут уж сам.:)
    Ответ написан
    Комментировать
  • Как обойти base href без https?

    Aetae
    @Aetae
    Тлен
    Вот например сайт icio.us на http(хз что за сайт, нагуглен из списка "popular websites loaded insecurely") , прекрасно грузит иконку сверху слева.
    Так что это не стандартное поведение браузера.

    Дайте ссылку на ваш сайт или хотя-бы запросите картинку с вашего сервера руками и покажите какие заголовки он отдаёт.

    Пока единственное разумное предположение, что там вместо image/<что-то> идёт какая-то ересь и браузер решает попытать счастья на https. Тогда надо поправить MIME types на сервере.

    Ещё вариант, что на сайте когда-то был https с включенным HSTS. Тогда надо руками удалить из браузера сохранённую метку.

    Но это всё гадание на кофейной гуще.
    Ответ написан
    Комментировать
  • Как правильно типизировать переменную?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Поменяй: props.item.office на 'office' in props.item.
    Ты не можешь обращаться к свойству которого нет сразу во всех типах union'a. Но ты можешь проверить его наличие, а дальше ts, в зависимости от результата, сузит тип до того, в котором оно присутствует.
    Ответ написан
    Комментировать
  • Как правильно использовать в ant design GRID?

    Aetae
    @Aetae
    Тлен
    Судя по документации как-то так:
    <Row justify="space-around">
      <Col flex="none">
        ...
      </Col>
      <Col flex="none">
        ...
      </Col>
    </Row>

    Или, чтоб наверняка:
    <Row>
      <Col span={12}>
        <Row justify="center">
          <Col flex="none">
          ...
          </Col>
        </Row>
      </Col>
      <Col span={12}>
        <Row justify="center">
          <Col flex="none">
          ...
          </Col>
        </Row>
      </Col>
    </Row>


    Но, ИМХО, проще забить на эту устаревшую и ненужную надстройку и написать стили ручками: проще и гибче будет.
    Ответ написан
    Комментировать
  • Проверки доступности стороннего домена со стороны клиента?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Ну стандартный вариант: загрузить то, что можно грузить не напрямую(img\script\video) и проверить onload\onerror.
    Условно так:
    Ответ написан
    Комментировать
  • Как конвертировать GoogleMaps координаты в 2GIS координаты и наоборот?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Преобразует любые на входе в универсальные:
    class CompatibleBounds {
      northEast = [0, 0];
      southWest = [0, 0];
    
      constructor(bounds) {
        Object.assign(this, bounds);
      }
    
      static new(bounds) {
        return new this(bounds);
      }
    
      get south(){ return this.southWest[1] }
      get west(){ return this.southWest[0] }
      get north(){ return this.northEast[1] }
      get east(){ return this.northEast[0] }
      set south(value){ this.southWest[1] = value }
      set west(value){ this.southWest[0] = value }
      set north(value){ this.northEast[1] = value }
      set east(value){ this.northEast[0] = value }
    }
    
    const compatibleBounds = CompatibleBounds.new({
      "south": 43.106491921792255,
      "west": 76.71745650634767,
      "north": 43.4065384633472,
      "east": 77.13974349365236
    });
    // или
    const compatibleBounds = CompatibleBounds.new({
      "northEast": [
        76.92894332280319,
        43.25695003829279
      ],
      "southWest": [
        76.92825667730312,
        43.256449960663694
      ]
    });
    
    // на выходе универсальный динамический объект:
    compatibleBounds.southWest = [1, 2];
    console.log(compatibleBounds.south); // 2
    
    compatibleBounds.south = 3
    console.log(compatibleBounds.southWest); // [1, 3]

    Но если действие требуется одноразовые, то лучше руками перегнать один раз.:)
    Ответ написан
    Комментировать
  • Встретил странный хэлпер в коде одного проекта, зачем он может использоваться?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Как уже сказали в комментах: создаёт регулярку с помощью которой можно найти отдельно-стоящее переданное слово(в начале строки, в конце или между пробелами).
    Что не сказали:
    1. Переданное слово не экранируется на спецсимволы регулярных выражений, потому внезапно может сломаться.
    2. Не учитывает знаки препинания(возможно не нужно, если задача специфичкская).
    Ответ написан
  • Проблема с React children?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Делая так:
    const ThemeProvider: FC = ...;
    Ты говоришь ts, что у тебя ThemeProvider имеет тип FC, и пофиг что ты там дальше пишешь. Тип FC по умолчанию не имеет children.

    Пиши либо так:
    const ThemeProvider: FC<{children: ...}> = ...;

    Либо так:
    const ThemeProvider = ({ children }: ...) => ...;
    * Кстати обрати внимание на деструктуризацию, в react component всегда приходят props, children это поле props, а не верхний аргумент.

    Либо так:
    const ThemeProvider: FC<PropsWithChildren> = ...
    * PropsWithChildren - тип помощник, добавляющий children к объекту, например
    PropsWithChildren<{
     prop2: string; 
     prop3: number
    }>
    но без дженерика просто отдаёт тип вида
    {
        children?: ReactNode | undefined;
    }
    Ответ написан
  • Как типизировать числа с точкой и тире?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    В принципе ts позволяет при желании извратиться и побуквенно наклепать нужные типы:
    type Lettrer = 'a' | 'b' | ...
    type Digit = 1 | 2 | ...
    ...

    Но делать так, очевидно, не стоит. :)
    Оставьте просто string и просто number.
    Разве что для удобства чтения и понимания (а также как задел на случай если ts поумнеет в будущем и сможет в более сложные типы) сделайте так:
    type ZipCode = string;
    type GeoCoord = number;
    Ответ написан
  • Как заставить Nuxt Image работать с изображениями из папки assets?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    С одной стороны для кастомных компонентов тебе потребовался бы transformAssetUrls. Однако открыв доки я вижу там:
    Converts src to provider optimized URLs

    В связи с чем вопрос: а путь то такой вообще работает?
    Что будет в img если ты делаешьimport img from '~/assets/images/header.jpg'?
    Ответ написан
    3 комментария
  • Как правильно сверстать перевернутый элемент?

    Aetae
    @Aetae
    Тлен
    Очевидно transform: rotate(-90deg); и какой-нить transform-origin, наиболее удобный.
    Условно так:

    Других (адекватных) вариантов собственно и нет.
    Ответ написан
    3 комментария
  • Как загрузить картинку в VUE3?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Подстановка путей к динамическим ассетам осуществляется на этапе сборки. Со строками из js сборка напрямую не работает.

    1. Ты можешь сделать так:
    import Wordpress from '../assets/wordpress-logotype-wmark.png';
    import Bitrix from '@/assets/logotip/1c_bitrix_logo.svg.png';
    const brandImgs = {
      '1C Bitrix': Bitrix,
      Wordpress,
    };

    По сути сделать руками то, что делает сборщик vue с src под капотом.

    2. Ты можешь просто сразу положить иконки в папку /public и указывать не относительные пути в рамках проекта, а абсолютные от корня:
    const brandImgs = {
      '1C Bitrix': '/logotip/1c_bitrix_logo.svg.png',
      'Wordpress': '/logotip/wordpress-logotype-wmark.png',
     };


    3. Ты можешь использовать динамический import().

    4. Ты можешь использовать import.meta.glob в vite или require.context в webpack.
    (Тут стоит помнить, что все ограничения упомянутые для п.3 применимы и здесь.)
    Ответ написан
  • Как внутри state использовать связанные элементы?

    Aetae
    @Aetae
    Тлен
    Используй getters, оно именно для этого и предназначено. Точно также как computed в самом vue.
    export default createStore({
      state: {
        list1: [],
      },
      getters: {
        list2(state) {
          return state.list1.filter(...) 
        }
      }
    })


    P.S. И да, нахрен vuex, используй pinia.
    Ответ написан
    Комментировать
  • Flex-grow 1 не работает, что делать?

    Aetae
    @Aetae
    Тлен
    Ну так а с чего бы ему что-то прижимать? Они вообще в разных блоках и никак не связаны.
    Ну и flex-grow это не про "прижимание", это про "заполнение имеющегося места".

    Чтобы что-то "прижимало" .twitter_swipe тебе надо .twitter__row слать flex column, не забыть задать высоту и задать уже для .twitter__body flex-grow.
    Ответ написан
    1 комментарий
  • Не могу понять, что не так с innerHTML?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Судя по ошибкам "JSX expressions must have one parent element," и "Uncaught SyntaxError: Unexpected token '<'" у вас где-то кусок html кода вне строки.
    Т.е. прям <какоц-то тег> ... вместо '<какоц-то тег> ...'.
    Код из вопроса должен работать без проблем.
    Ответ написан
    Комментировать
  • Как удалить теги style?

    Aetae
    @Aetae
    Тлен
    Почему ты не можешь повлиять на бэкэнд? Парсишь небось?
    Причём тут реакт? Реакт рисует элементы и стили на лету, а не получает их с бэкэннда.

    Если таки с бэка приходит html строка, которая потом вставляется через dangerouslySetInnerHTML то предварительно её почистить можно так:
    function removeStyles(html) {
      const container = document.createElement('div');
      container.innerHTML = html;
      container.querySelectorAll('style').forEach(
        style => style.remove()
      );
      return container.innerHTML;
    }


    Если ты пуляешь напрямую чужой реакт код, то тут два варианта:
    1. Делать как указал Даниил , только при этом ещё и динамически, дожидаясь пока реакт их нарисует, для чего придётся использовать MutationObserver или банальный setTimeout. Однако в таком случае стили могут успеть отрисоваться до удаления, из-за чего может происходить мерцание.
    2. Лезть глубже в исходники и патчить: подменять react функции работы со стилями, или даже тупо document.createElement, отфильтровая ненужный style. Но всё это уже требует понимания.:)
    Ответ написан
    Комментировать
  • Как правильно реализовать передачу данных между не связанными друг с другом компонентами в vue3?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Если ты не используешь SSR, то тебе достаточно просто reactive/ref объекта, чтоб получить эрзац-стор, тупо:
    // где-нибудь 
    export const basket = reactive([]); // или ref([]) по вкусу. 
    // везде где надо
    import { basket } from './...'

    Реактивность будет прекрасно работать.

    Почему кто-то использует специальные store если можно делать так? Потому что сторы учитывают работу в режиме SSR, а также позволяют удобную отладку в случае множества запутанных связей.
    Вам я бы тоже рекомендовал использовать таки store - только pinia, а не vuex. Не вижу причин его не использовать.

    По поводу EventBus: с одной стороны новичку её использовать категорически не рекомендуется, т.к. работа со store куда удобнее, очевиднее и надёжнее. Однако и совсем отрицать её использование тоже не следует, шина отлично подходит для случаев когда мы имеем дело именно с событиями, а не изменением состояния. Т.е. послать какой-нить notification или лог - самое оно, использовать для изменения basket, как в вашем случае - нет.
    Ответ написан
    1 комментарий