Ответы пользователя по тегу Vue.js
  • Как прокинуть данные из одного дочернего компонента в другой?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Собственно взаимодействие меж несвязанными компонентами осущетвляется следующими способами:
    1. В простых случаях обычный vue-flow: вверх до общего родителя события через $emit и @on, вниз props.
    2. Общее хранилище в рамках всего приложения: pinia, vuex.
    3. Для связки детей которые не могут жить без конкретного родителя можно использовать: provide \ inject.
    4. Для плотной связки единичных компонентов: просто отдельный reactive объект импортируемый в нужных компонентах. (использовать осторожно при SSR)

    Конкретно тебе, похоже, нужен п.2.
    Ответ написан
  • Как выполнить действие до события DomContentLoaded?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Нет. (с оговорками, но не в твоём случае)

    Просто измени шаблон index.template.html и добавь туда в head тупо
    <script>
    window.YandexRotorSettings = {
            WaiterEnabled: true;
            FailOnTimeout: false;
            NoJsRedirectsToMain:true
    }
    </script>

    (ну либо любой иной шаблон в который ты подключаешь vue)
    Ответ написан
  • Как правильно сделать привязку данных к динамически созданному элементу в Vue?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Если работаешь с vue - тебе не нужно трогать dom руками и наоборот.
    v-html только для статических каких-то данных.

    Вот это вот <b class="aaakjhij" data="hk">jjj!!!!</b> должно быть уже в шаблоне. Если надо по условию - то использовать v-if или v-for если несколько.
    Примерно так:
    <script>
    export default {
      data() {
        return {
          data: 'hk',
          text: 'jjj!!!!',
          show: false
        }
      },
      methods: {
        _jjj(){
          this.show = true
          this.data = 'hk';
          this.text = 'jjj!!!!';
        },
       _kkk(){
          this.data = 'ooooooooooo';
          this.text = 'ha-ha-haaaa!!!'
        }
      }
    }
    </script>
    
    <template>
      <div>
        <b v-if="show" :data="data">{{text}}</b>
      </div>
      <button @click="_jjj">11</button>
      <button @click="_kkk">12</button>
    </template>

    Тебе надо перестать мыслить в jquery и начать мыслить в vue.

    Если всё ещё остаются проблемы - опиши конкретную конечную цель, которой ты хочешь добиться, не в виде кода, а в виде результата и условий.
    Ответ написан
    3 комментария
  • Почему приложение не билдится из-за vue-yandex-maps?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Я, как и сборщик, не вижу экспорта yandexMap и yandexMarker, вижу YandexMap и YandexMarker.
    Ответ написан
    2 комментария
  • Как использовать объект VNodeRef?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Зачем ты огород то городишь?
    :ref="setPostRef"
    -->
    ref="postRefs"

    И всё, в postRefs.value у тебя массив элементов.

    В твоём варианте ты прям в кишки vue лезешь.
    Ответ написан
    Комментировать
  • Можно ли отслеживать css переменные с помощью computed?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Вот по-быстрому накидал в качестви зарядки такой кастомный дерьмохук (который ни в коем случае нельзя использовать в проде, только в целях демонстрации. :) ):
    import { Ref, computed, ref, watch, onMounted, onUnmounted } from 'vue';
    
    function isHTMLElement(arg: unknown): arg is HTMLElement {
      return !!arg && arg instanceof HTMLElement;
    }
    
    function useCSSVariable(
      variable: string,
      el: HTMLElement | Ref<HTMLElement> = document.documentElement
    ) {
      if (!variable.startsWith('--')) variable = `--${variable}`;
      if (!isHTMLElement(el)) watch(el, value => (el = value), { immediate: true });
    
      const prev = ref();
    
      let timeoutId: number;
      const interval = () => {
        const current = isHTMLElement(el)
          ? getComputedStyle(el).getPropertyValue(variable)
          : null;
    
        if (current !== prev.value) prev.value = current;
    
        timeoutId = window.setTimeout(interval, 100);
      };
    
      onMounted(() => {
        interval();
      });
    
      onUnmounted(() => {
        clearTimeout(timeoutId);
      });
    
      return computed<string>({
        set(value) {
          let current: null | string = null;
    
          if (isHTMLElement(el)) {
            el.style.setProperty(variable, value);
            current = el.style.getPropertyValue(variable);
          }
    
          if (prev.value !== current) prev.value = current;
        },
        get() {
          return prev.value;
        }
      });
    }


    Ещё раз - использовать это не надо, это скорее шутка. Что надо - выяснить твою задачу и решать её нормально по-человечески.
    Ответ написан
    Комментировать
  • Почему данные не реактивны?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    В vue 2 добавленые после создания ключи объектов не реактивы из-за технических ограничений. (Раньше это большими буквами в доках писалось).
    Надо использовать this.$set \ Vue.set при добавлении нового ключа.

    В твоём случае можно переделать так:
    const templates = reactive(keyBy(templatesArr, 'id'))
    for (let templateId in templates) {
      const devices = devicesArr.filter(device => device.templateId === templateId)
      Vue.set(templates[templateId], 'devices', devices);
      Vue.set(templates[templateId], 'settings', {});
    }
    
    // либо просто так:
    const templates = keyBy(templatesArr, 'id');
    for (let templateId in templates) {
      const devices = devicesArr.filter(device => device.templateId === templateId)
      Object.assign(templates[templateId], { devices }, {settings: {}})
    }
    reactive(templates);


    P.S. не помню чтоб в vue 2 было reactive, вместо него был Vue.observable. Но может добавили, хз, лень смотреть.:)
    Ответ написан
    Комментировать
  • Каков наилучший способ v-bind для :hover :active и тд, и можно ли вообще так сделать?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Вопрос по большому счёту не относится к vue.

    Решения:
    1. Использовать класс-модификатор, который порасит как надо.
    <template>
      <input class="hover--red"/>
    </template>
    
    <style>
    .hover--red:hover {
      color: #f00
    }
    </style>

    2. Использовать css (не путать с scss) переменные.
    <script setup>
    // ...
    const hoverColor = '#f00'
    </script>
    
    <template>
      <input :style="{'--hover-color': hoverColor}"/>
    </template>
    
    <style>
    input:hover {
      color: var(--hover-color)
    }
    </style>


    ...upd: совсем забыл про такую фичу vue:
    3. Если стили лежат в sfc можно использовать переменные через v-bind в <style>:
    <script setup>
    // ...
    const hoverColor = '#f00'
    </script>
    
    <template>
      <input />
    </template>
    
    <style>
    input:hover {
      color: v-bind(hoverColor)
    }
    </style>

    А забыл я про неё потому, что категорически против такого смешения кода и стилей. Но я не могу вам запретить.:)
    Ответ написан
    1 комментарий
  • Как использовать withDefaults с вложенными обьектами (typescript)?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Значения по умолчанию для этого не предназначены.
    Сделай computed значение в которым смежри входящее с дефалтным как тебе нвдо.
    Ответ написан
    Комментировать
  • Перед тем как изучить Vue 3, стоит ли изучать Vue 2?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Изучать vue 2 стоит только если проект на нём. К сожалёнию vue 3 его уже убил.

    Однако мне есть, что вам посоветовать, с чем встречаются все новички: в vue 3 есть composition api и есть options api. И они работают вместе. НО. Их не надо использовать вместе. Никогда. Если есть setup - не должно быть, например, methods и наоборот. Это вопрос чистоты кода и мышления в одной парадигме.
    Если у вас что-то не получается в одном варианте, что кажется можно легко решить в другом - это говорит только о том, что у вас проблемы с пониманием, и лучше будет задать вопрос тут, чем разводить говнокод.
    Ответ написан
    Комментировать
  • Хочу сделать таблицу на vue3 которая не будет однофайловым компонентом, какой запрос вводить чтобы найти статью описывающую как это сделать?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Цитата из официальной документации:
    If you prefer a plain HTML setup without any build steps, you can use this JSFiddle as your starting point.


    Вот открывать тот филдл:
    код оттуда на всякий случай
    <script type="importmap">
      {
        "imports": {
          "vue": "https://unpkg.com/vue@3/dist/vue.esm-browser.js"
        }
      }
    </script>
    
    <div id="app">{{ message }}</div>
    
    <script type="module">
      import { createApp } from 'vue'
    
      createApp({
        data() {
          return {
            message: 'Hello Vue!'
          }
        }
      }).mount('#app')
    </script>

    И делаешь также у себя.
    А дальше все статьи для однофайловых компонентов подойдут и тебе. Ну и плюс немного знания js для импорта и использования библиотек.

    Единственное, что следует помнить, это то что ты пишешь в html, а потому если в статье кто-то использует компоненты так:
    <SomeComponent :someProp=""val"/>
    то тебе надо ручками сделать так:
    <some-component :some-prop=""val"></some-component>
    Почему? Птому что 1 - html регистронезависимый и SomeComponent читается как somecomponent, а vue такого не знает, 2 - список тэгов которые могут самозакрываться ограничен.
    Ответ написан
    Комментировать
  • Как исправить ошибку TypeError: Cannot create property 'value' on boolean 'false'?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Это так не работает. В шаблоне у тебя все рефы раскрыты -это шаблон, он должен быть простым.

    Делать надо либо так:
    function popupLibraryOpen() {
      isLibraryOpen.value = true
    }
    <MyButton @click="popupLibraryOpen">Библиотека игр</MyButton>

    либо так:
    <MyButton @click="isLibraryOpen = true">Библиотека игр</MyButton>
    Ответ написан
    2 комментария
  • Как вывести template внутри template?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    а) Вынести в отдельный компонент. Чем компоненты меньше - тем лучше для vue. Не стесняйтесь выносить даже одиночный div.
    <div>
      <p>1111</p>
      <v-cost />
    </div>
    <div>
      <p>22222</p>
      <v-cost />
    </div>

    б) Если это какой-то массив данных - используйте v-for:
    <div v-for="{ title } in arr" :key="title">
      <p>{{title}}</p>
      <div class="cost">
        <div class="cost__title">test:</div>
        <div class="cost__number">3 400 </div>
      </div>
    </div>

    с) Если прям очень хочется говнять в рамках одного компонента, это можно сделать с помощью render функции, но там уже никаких шаблонов - чистый код. Тема "продвинутая", и в твоём случае явно не нужная, так разбирайся сам если хочешь.:)
    Ответ написан
    Комментировать
  • Нужно ли в vue для использования однофайловых компонентов использовать сборщик?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Простой ответ: да, нужно.
    Сложный ответ: не обязательно, можно компилировать шаблоны на лету подключив полный бандл vue на страницу, а потому с использованием костылей от сторонних разработчиков или самописных, возможно будет работать и с целыми компонентами, перекладывая вычисления на сторону пользователя. Но делать так не надо.
    Ответ написан
    Комментировать
  • Как использовать :key в пользовательской директиве?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Судя по названию директивы у тебя ошибка в логике:
    if (el === event.target || el.contains(event.target)) {
    ->
    if (el !== event.target && !el.contains(event.target)) {
    ->
    if (!el.contains(event.target)) { 
    // contains работает на самого себя, дополнительно проверять не надо

    Мы ловим клик снаружи, т.е. не равный выбранному элементу, а у тебя ловится клик на самом элементе, т.е. как будто это простой @click.

    Также по-хорошему следует предусмотреть update на случай обновления value, иначе у тебя директива поломается при его реактивном изменении(обычно конечно не меняют, но зачем закладывать бомбу?).
    Ответ написан
    Комментировать
  • Почему возвращает undefined?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    1. Проблема в том, что возвращает твой postForm. Сам по себе приведённых код рабочий. Нужен код postForm.
    2. Хотя приведённый код и рабочий - так писать нельзя: ты используешь либо Options Api, либо Composition Api. Не смешивая. Если есть setup - нет methods, если есть methods - нет setup. Да, оно работает. Но это говно. Как Тесла с дизель-генератором в багажнике.
    Ответ написан
  • Почему .value в nuxt3 выдает не тот результат в консоли?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Во первых: всё зависит от сигнатуры этого вашего useApiFetch, очень многое в vue 3 можно сломать неудачной деструктуризацией. Но допустим сам хук нормальный.
    В таком случае isPending - это ref, а значит он и должен быть прокси, чтоб собственно работала энтая самая реактивность. Чтоб отобразить в консоли чистый объект - есть хэлпер toRaw(только после этого он уже не будет динамическим).

    Далее: если вы выводите в консоль isPending.value - то в консоль, очевидно, попадает значение на момент вызова console.log. Магическим образом прямо в консоли оно уже не изменится.

    Если ты хочешь понаблюдать за изменениями isPending - можешь сделать так:
    watch(isPending, (value) => console.log('watch isPending', value), { immediate: true });


    В заключение предположу, что всё у вас работает как должно, а проблемы с пониманием реактивности vue и асинхронности как таковой.
    Ответ написан
    Комментировать
  • Каким образом вывести (интерполировать) данные из переменных в title?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Ну например глобальный миксин приблизительно такого вида:
    {
      beforeCreate() {
        this._oldTitle = document.title;
      },  
      unmounted() {
        if (this.PAGE_TITLE)
          document.title = this._oldTitle;
      },
      watch: {
        PAGE_TITLE: {
          handler(val, oldVal) {
            if (val)
              document.title = val;
            else
              document.title = this._oldTitle;
          },
          immediate: true
        },
      }
    }

    И в компоненте управляешь просто свойством this.PAGE_TITLE.
    Или в случае composition api:
    const PAGE_TITLE = ref('<title>'); // computed(() => ...)
    // ...
    return { 
      PAGE_TITLE,
      // ...
    }

    и в случае script setup/render:
    + expose({ PAGE_TITLE })

    Особенность в том, что управление title тут заберёт последний загруженный компонент имеющий PAGE_TITLE, что может привести к багам если на одной странице таких окажется два.

    У меня есть где-то самописка которая делает подобное но с учётом роутера и иерархии, и это уже, увы не так просто.:)

    P.S. Вообще на таком примитивном уровне можно просто использовать document.title напрямую и не париться. Подход с миксином имеет смысл если этот title вы используете ещё где-то в приложении глобально.
    Ответ написан
    3 комментария
  • Проект на VueJS контейнер Docker. Почему не запускается?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Очевидно надо достать кусок кода в index-yQz08yST.js:9:2359 (девятая строка 2359 символ) и посмотреть в чём там проблема.
    Навскидку по тексту ошибки могу предположить, что там используется optional chaining (foo?.bar) или nullish coalescing (foo ?? bar), а версия браузера у вас там старая и не поддерживает такой фичи.

    ...upd: судя по user-agent там хром 70, а минимум для этих фич - хром 80.
    Если моё предположение верно(99%), то у вас два варианта: обновить хром на машине, или добавить в билд babel(скорее всего и так добавлен) и прописать в browserlist Chrome <= 70 (а не last 1, что там скорее всего по умолчанию), чтоб при билде он эти фичи заменил на старые альтернативы.
    Ответ написан
    1 комментарий
  • Как написать Vue компонент не для браузера?

    Aetae
    @Aetae Куратор тега Vue.js
    Тлен
    Vue завязан на html+javascript. Даже серверный рендер просто возвращает html-строку. Возможно можно написать собственный рендер vdom-терминал или использовать какой-то имеющийся конвертер html-терминал, но это всё сомнительно и мутно. Вам следует поискать другие инструменты.
    Ответ написан