Ответы пользователя по тегу Vue.js
  • Почему vue-router не меняет данные в компоненте?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Потому что экземпляр компонента заново не создаётся при смене значений параметров. За ними надо следить:

    watch: {
      '$route.params.slug': {
        immediate: true,
        handler() {
          // сюда переносите код из created
        },
      },
    },
    Ответ написан
    1 комментарий
  • Как скрыть элемент на определённом роуте?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <div v-if="$route.name !== 'signup'">hello, world!!</div>

    или

    <div v-if="$route.path !== '/signup'">hello, world!!</div>
    Ответ написан
    1 комментарий
  • Как использовать keep-alive с vuikit tabs?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Свойство isEmpty, управляющее отображением избранного, не меняет своего значения при изменениях этого списка, а должно. Очевидно, его следует сделать вычисляемым:

    computed: {
      isEmpty() {
        return !this.$store.state.wishlistIds.length;
      },
      ...
    Ответ написан
    Комментировать
  • Как оптимизировать несложное vue приложение?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Плохо:

    <div class="color-label red" @click="color = '#FB253E', textColor = '#ffffff' , strokeColor = '#ffffff';"></div>
    <div class="color-label green" @click="color = '#19AD6A' ,textColor = '#ffffff' , strokeColor = '#ffffff';"></div>
    <div class="color-label orange" @click="color = '#FC6621' ,textColor = '#ffffff' , strokeColor = '#ffffff';"></div>
    <div class="color-label blue" @click="color = '#1386a3' ,textColor = '#ffffff' , strokeColor = '#ffffff';"></div>
    <div class="color-label yellow" @click="color = '#FFED00' ,textColor = '#111111' , strokeColor = '#111111';"></div>
    <div class="color-label lightgreen" @click="color = '#00ff00' ,textColor = '#111111' , strokeColor = '#111111';"></div>
    <div class="color-label white" @click="color = '#ffffff' ,textColor = '#111111' , strokeColor = '#111111';"></div>

    Лучше:

    <div
      v-for="n in colors"
      :class="[ 'color-label', n.name ]"
      @click="onColorClick(n.values)"
    ></div>

    data: () => ({
      colors: [
        { values: [ '#FB253E', '#FFF', '#FFF' ], name: 'red' },
        { values: [ '#19AD6A', '#FFF', '#FFF' ], name: 'green' },
        { values: [ '#FC6621', '#FFF', '#FFF' ], name: 'orange' },
        { values: [ '#1386A3', '#FFF', '#FFF' ], name: 'blue' },
        { values: [ '#FFED00', '#111', '#111' ], name: 'yellow' },
        { values: [ '#00FF00', '#111', '#111' ], name: 'lightgreen' },
        { values: [ '#FFFFFF', '#111', '#111' ], name: 'white' },
      ],
      ...
    }),
    methods: {
      onColorClick([ color, textColor, strokeColor ]) {
        Object.assign(this, { color, textColor, strokeColor });
      },
      ...
    },


    Плохо:

    <tspan x="0" y="-10" text-anchor="middle" alignment-baseline="middle" font-family="'Swiss721BT-RomanCondensed'" :style="{ 'font-size': firstLineFontSize }">{{ firstLine }}</tspan>
    <tspan x="0" y="17" text-anchor="middle" alignment-baseline="middle" font-family="'Swiss721BT-RomanCondensed'" :style="{ 'font-size': secondLineFontSize }">{{ secondLine }}</tspan>
    <tspan x="-2" y="45" text-anchor="middle" alignment-baseline="middle" font-family="'Swiss721BT-RomanCondensed'" :style="{ 'font-size': thirdLineFontSize }">{{ thirdLine }}</tspan></text>
    ...
    <input type="text" placeholder="enter 1 text line" @input="changeFirstLine">
    <input type="number" value='25' @input="changeFirstLineFontSize"><span> px </span>
    <input type="text" placeholder="enter 2 text line" @input="changeSecondLine">
    <input type="number" value='18' @input="changeSecondLineFontSize"><span> px </span>
    <input type="text" placeholder="enter 2 text line" @input="changeThirdLine">
    <input type="number" value='18' @input="changeThirdLineFontSize"><span> px </span>

    data: {
      firstLine: 'Your',
      secondLine: 'custom',
      thirdLine: 'text',
      firstLineFontSize: '25',
      secondLineFontSize: '18',
      thirdLineFontSize: '18',
      ...
    },
    methods: {
      changeFirstLine: function(event) {
          this.firstLine = event.target.value;
      },
      changeSecondLine: function(event) {
          this.secondLine = event.target.value;
      },
      changeThirdLine: function(event) {
          this.thirdLine = event.target.value;
      },
      changeFirstLineFontSize: function(event) {
          this.firstLineFontSize = event.target.value;
      },
      changeSecondLineFontSize: function(event) {
          this.secondLineFontSize = event.target.value;
      },
      changeThirdLineFontSize: function(event) {
          this.thirdLineFontSize = event.target.value;
      },
      ...

    Лучше:

    <tspan
      v-for="n in lines"
      v-text="n.text || n.placeholder"
      :x="n.x"
      :y="n.y"
      :style="{ 'font-size': n.fontSize }"
      text-anchor="middle"
      alignment-baseline="middle"
      font-family="'Swiss721BT-RomanCondensed'"
    ></tspan>
    ...
    <template v-for="(n, i) in lines">
      <input type="text" v-model="n.text" :placeholder="`enter ${i + 1} text line`">
      <input type="number" v-model="n.fontSize"><span> px </span>
    </template>

    data: () => ({
      lines: [
        { x:  0, y: -10, fontSize: 25, placeholder: 'Your' },
        { x:  0, y:  17, fontSize: 18, placeholder: 'custom' },
        { x: -2, y:  45, fontSize: 18, placeholder: 'text' },
      ],
      ...
    }),
    Ответ написан
    Комментировать
  • Как выводить дочерние элементы из массива в treeview (vuetify)?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сделаем функцию, которая будет осуществлять рекурсивный поиск:

    const find = (arr, id) =>
      (Array.isArray(arr) ? arr : []).reduce((found, n) =>
        found || (n.id === id ? n : find(n.children, id))
      , null);

    И, используя её, перепишем вычисляемое свойство:

    selected() {
      return this.active.length
        ? find(this.users, this.active[0])
        : null;
    },

    UPD. Почитал документацию - оказывается, можно всё сделать гораздо проще. Указываем для treeview параметр return-object - тогда в active вместо ключей будут объекты. Соответственно, искать ничего не надо, вычисляемое свойство сократится до

    selected() {
      return this.active[0];
    },
    Ответ написан
    1 комментарий
  • Как правильно делать такие компоненты и как они называются?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Как называются - да без понятия, обычные компоненты:

    const Component = Vue.extend(...);

    Экземпляры создаёте не через шаблон/render-функцию других компонентов, а вручную вызываете конструктор и добавляете корневой элемент куда там вам надо:

    document.body.appendChild(new Component(...).$mount().$el);

    Удаление - так же вручную, вызываете метод $destroy и удаляете корневой элемент из DOM.
    Ответ написан
  • Select/option во Vue computed. Как использовать?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Добавляете свойство, которое будет представлять выбранный пункт select'а. Вместо метода getMonthRate делаете вычисляемое свойство:

    <select v-model="selected">
      <option v-for="item in options" :value="item.value">
        {{ item.title }}
      </option>
    </select>

    data: () => ({
      selected: null,
      ...
    }),
    computed: {
      monthRate() {
        if (this.selected === 'year') {
          return this.percent / 12 / 100;
        } else if (this.selected === 'month') {
          return this.percent / 100;
        } else {
          return 0;
        }
      },
    },

    UPD.

    нужно, чтобы в зависимости от выбранной опции, функция срабатывала по разной формуле

    А насколько разной? То, что есть сейчас, можно значительно упростить: в качестве value вместо строк будут числа, напрямую подставляемые в формулу - 1/12 для year, 1 для month, 0 для остальных. Тогда вычисляемое свойство станет гораздо короче:

    monthRate() {
      return this.percent * this.selected / 100;
    },
    Ответ написан
    5 комментариев
  • Как добавить стиль при нажатии на элемент?

    0xD34F
    @0xD34F Куратор тега Vue.js
    .dropdown-checkbox ul.opened {
      display: block;
    }

    <label @click="opened = !opened">click me</label>
    <ul :class="{ opened }">
      ...

    data: () => ({
      opened: false,
    }),
    Ответ написан
    5 комментариев
  • Как использовать vue-i18n внутри script?

    0xD34F
    @0xD34F Куратор тега Vue.js
    computed: {
      msg() {
        return this.$t('welcomeMsg');
      },
    },
    Ответ написан
    Комментировать
  • Как заставить beforeRouter дождаться пока в firebase подтвердит авторизацию?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Поменяйте порядок действий - сначала авторизация, потом создание экземпляра vue:

    firebase.auth().onAuthStateChanged(user => {
      if (user) {
        store.dispatch('loggedUser', user);
      }
    
      new Vue(...);
    });
    Ответ написан
    1 комментарий
  • Почему внутри компонента не выводится свойство, а за пределами все норм?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <script type="text/x-template" id="tree-template">
        {{ item }}
    </script>

    Что, просто текст? Нет, так не будет. Должен быть какой-то элемент. Сделайте li - вы же внутри ul пытаетесь их выводить:

    <script type="text/x-template" id="tree-template">
      <li>{{ item }}</li>
    </script>

    <ul v-for="item in items" :key="item.id">
                <tree-items
                        :item="item"
                ></tree-items>
            </ul>

    Множество списков с одним элементом? Может, должен быть один список с множеством элементов? - переносим v-for внутрь списка (кстати, а какого чёрта в имени компонента элемента списка множественное число? почему items, а не item?):

    <ul>
      <tree-items
        v-for="item in items"
        :key="item.id"
        :item="item"
      ></tree-items>
    </ul>
    Ответ написан
  • Как создать вложенный список из объекта Vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Нужны отдельные компоненты для страны, региона и города - компонент страны выводит список своих регионов, компонент региона список городов. Например. Или, можно делать компоненты не под отдельные элементы, а под списки - список стран, список регионов, список городов - будет примерно то же самое.
    Ответ написан
    Комментировать
  • Как добавить карту от Leaflet через Vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <div ref="map">

    mounted() {
      this.map = L.map(this.$refs.map).setView([ 55.75222, 37.61556 ], 13);
      ...
    Ответ написан
  • Как повесить клик на строчку в таблице?

    0xD34F
    @0xD34F Куратор тега Vue.js
    <v-data-table @click:row="onClickRow">

    methods: {
      onClickRow(item) {
        console.log(item);
      },
      ...
    Ответ написан
    2 комментария
  • Как каждому из экземпляров Vue назначить отдельный Store?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Если воспользуетесь конструктором Vuex.Store более одного раза, вас за это в тюрьму не посадят. Так что вам ничего не мешает создать несколько разных сторов, свой для каждого экземпляра Vue.

    А если их структура должна быть идентична - сделайте функцию, которая будет создавать стор и вместо

    new Vue({
      store: store,
      ...

    будет

    new Vue({
      store: createStore(),
      ...

    https://jsfiddle.net/25L08xj1/
    Ответ написан
    Комментировать
  • Как управлять параметром для отдельного элемента DOM из Vue.js компонента?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Сделайте отдельный компонент для этих секций, со свойством isActive - у каждого экземпляра оно будет собственное. Или этих isActive'ов у вас должен быть массив, длина которого равна количеству секций. Или добавьте свойство isActive элементам sections - каждому.
    Ответ написан
    5 комментариев
  • Как отрефакторить computed методы во Vue?

    0xD34F
    @0xD34F Куратор тега Vue.js
    передавать параметры <...> оставив в computed

    А смысл? Будет computed свойство, значение которого является функцией. Никакого кеширования, только усложнение кода. Делайте обычный метод:

    methods: {
      filterHeroes(attr) {
        const s = this.searchHeroesString.toLowerCase();
        return this.heroes.filter(n => n.hero_attribute === attr && n.name.toLowerCase().includes(s));
      },
    Ответ написан
    Комментировать
  • Как сделать скрытие блока, при клике на любую область?

    0xD34F
    @0xD34F Куратор тега Vue.js
    data: () => ({
      active: false,
    }),
    created() {
      const onClick = e => this.active = this.$refs.block.contains(e.target) && this.active;
      document.addEventListener('click', onClick);
      this.$on('hook:beforeDestroy', () => document.removeEventListener('click', onClick));
    },

    <button @click.stop="active = !active">click me</button>
    <div :class="{ active }" ref="block">hello, world!!</div>
    Ответ написан
    1 комментарий
  • Как при клике на кнопку в блоке открывать модальное окно/выезжающий сайдбар с данными того блока, в котором находиться кнопка?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Добавляете в стейт свойство, которое будет представлять выбранный блок:

    state: {
      opened: null,
      ...

    В экземпляры компонента Trigger передавайте соответствующие им блоки:

    <Trigger :block="block">

    props: [ 'block' ],

    Также, Trigger должен знать, какой блок открыт:

    computed: mapState([ 'opened' ]),

    Чтобы можно было назначить класс кнопке:

    :class="{ 'active' : block === opened }"

    При клике на которую следует передавать блок в мутацию:

    @click="toggleNav(block)"

    Мутация же будет устанавливать значение выбранного блока:

    toggleNav(state, block) {
      state.opened = state.opened === block ? null : block;
    },

    Это если оно действительно toggle. Если просто открытие - тогда достаточно state.opened = block (название мутации в этом случае конечно следует поменять).

    Мутация, отвечающая за закрытие, будет выглядеть так:

    closeSidebarPanel(state) {
      state.opened = null;
    },

    Геттер isNavOpen тоже изменится:

    isPanelOpen(state) {
      return !!state.opened;
    },

    Ну и наконец, можно что-нибудь вывести в Sidebar, например:

    <span v-if="isPanelOpen">{{ $store.state.opened.bName }}</span>

    Но если Sidebar предназначен конкретно для этих блоков, наверное, разумнее будет, чтобы он сам знал, кто сейчас открыт. В Sidebar'е цепляете opened к слоту:

    <slot :block="$store.state.opened"></slot>

    Соответственно, в родительском компоненте:

    <template #default="{ block }">
      <div class="sidebar-panel-settings">
        <div class="setting-block">
          {{ block.bName }}
        </div>
      </div>
    </template>
    Ответ написан
    1 комментарий
  • Как вывести data-attr?

    0xD34F
    @0xD34F Куратор тега Vue.js
    Вам это не надо, не на jquery же пишите. Пусть выбранным значением будет сам элемент массива deliveryPrice, а не какое-то из его свойств:

    <select v-model="selected">
      <option v-for="n in deliveryPrice" :value="n">{{ n.city }}</option>
    </select>

    Ну и выводите чего хотите без проблем:

    <p>{{ selected.city }}</p>
    <p>{{ selected.priceFrom }}</p>


    Если вдруг напрягает [object Object], отображаемый в качестве value в разметке, то можно сделать computed свойство, которое будет представлять выбранный элемент, оставив в v-model строковую переменную:

    <select v-model="city">
      <option v-for="n in deliveryPrice">{{ n.city }}</option>
    </select>

    computed: {
      selected() {
        return this.deliveryPrice.find(n => n.city === this.city);
      },
    },
    Ответ написан
    1 комментарий