Как использовать динамическое свойство объекта из хранилища в качестве v-модели?

Я оборачиваю голову вокруг этого, и я не могу понять, как это сделать.

Как я могу привязать входные данные к свойству объекта хранилища? Смысл: мой компонент знает только объект хранилища, но не знает заранее, какие свойства содержит объект.

Возьмите этот пример:

Vue.component('os-choice', {
  template: `
    <div>
      <h5>Select OS</h5>
  
      <div>
        <label class = "checkbox">
          <input type = "checkbox" value = "linux" v-model = "linux">
            Linux
        </label>
      </div>

      <div>
        <label class = "checkbox">
          <input type = "checkbox" value = "macos" v-model = "macos">
            MacOS
        </label>
      </div>

      <div>
        <label class = "checkbox">
          <input type = "checkbox" value = "windows" v-model = "windows">
            Windows
        </label>
      </div>

    </div>
  `,
  computed: {
    linux: {
      get() {
        return store.state.linux;
      },
      set(val) {
        store.commit('updateLinux', {
          linux: val
        });
      }
    },
    macos: {
      get() {
        return store.state.macos;
      },
      set(val) {
        store.commit('updateMacos', {
          macos: val
        });
      }
    },
    windows: {
      get() {
        return store.state.windows;
      },
      set(val) {
        store.commit('updateWindows', {
          windows: val
        });
      }
    },
  }  
});


Vue.component('os-choice2', {
  template: `
    <div>
      <h5>Select OS</h5>
  
        <div v-for = "(value,index) in os" :key = "index">
          <label class = "checkbox">
            <input type = "checkbox" value = "index" v-model = "value">
              {{index}}
          </label>
        </div>

      </div>

    </div>
  `,
  computed: {
    os: {
      get(){ return store.state.os; },
      set(event){
        var name = event.target.value;
        var value = event.target.checked;
        store.commit('updateOs', {name: name, value: value});
      }
    },
  }  
});


 const store = new Vuex.Store({
  state: {
    // initial state
    linux: true,
    macos: true,
    windows: false,
    os: {
      linux: true,
      macos: true,
      windows: false,
    }
  },
  mutations: {
    updateLinux(state, payload) {
      console.info('STORE: updated linux');
      state.linux = payload.linux;
    },
    updateMacos(state, payload) {
      console.info('STORE: updated MacOS');
      state.macos = payload.macos;
    },
    updateWindows(state, payload) {
      console.info('STORE: updated Windows');
      state.windows = payload.windows;
    },
    updateOs(state, payload) {
      console.info('STORE: updated OS');
      state.os[payload.name] = payload.value;
    }
  }
});



var app = new Vue({
  el: "#app",


  
})
.row{
  width: 100%;
}
.column{
  width: 50%;
}
<script src = "https://cdn.jsdelivr.net/npm/vue"></script>
<script src = "https://unpkg.com/[email protected]/dist/vuex.js"></script>

<div id = "app" style = "text-align:center;">
  <div class = "row">
    <div class = "column">
      <os-choice></os-choice>
    </div>
    <div class = "column">
      <os-choice2></os-choice2>
    <div>
  </div>
</div>

Первый компонент работает отлично. Второй компонент не обновляет хранилище: он генерирует ошибку «[vuex] Не изменять состояние хранилища vuex вне обработчиков мутаций».

Я думаю, что понимаю, почему это происходит: поскольку вычисляемое свойство компонента указывает на объект (а не на изменяемое свойство), v-model попытается изменить глубокое свойство, тем самым заставив изменить хранилище, которое вызовет ошибка еще до того, как компонент вызовет метод set() для объекта, верно?

Итак, что я хотел бы знать, так это то, как правильно это сделать?

Мой реальный сценарий заключается в том, что я создаю динамический фильтр с флажками, и во время выполнения я не знаю, сколько у него будет опций. Это означает, что я пройдусь по своим параметрам, чтобы создать флажки, но тогда привязка данных должна быть в форме «значения []». И тут начинаются мои головные боли.

Спасибо всем заранее

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
0
736
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Из документации VueJs:

Custom events can also be used to create custom inputs that work with v-model. Remember that:

 <input v-model = "searchText">

does the same thing as:

 <input   v-bind:value = "searchText"   v-on:input = "searchText =
 $event.target.value"
 >

When used on a component, v-model instead does this:

 <custom-input   v-bind:value = "searchText"   v-on:input = "searchText =
 $event"
 ></custom-input>

Таким образом, вместо использования v-model вы можете использовать value в качестве v-bind:value = "value" и отобразить событие для соответствующего обновления магазина, например: v-on:input = "store.commit('store.commit('updateOs', event.target.value)"

Другой компонент работает, поскольку вы следуете именно тому, что рекомендует делать Vuex: https://vuex.vuejs.org/guide/forms.html

Но на v-for вы используете модель магазина напрямую.

Может быть много способов справиться с этим. Другое решение, которое я могу придумать, состоит в том, чтобы поддерживать модель привязки компонента вместо прямой привязки его к хранилищу и использовать watch для синхронизации с хранилищем.

Reuel Ribeiro 29.05.2019 03:26

Спасибо за ваш ответ @Reuel. Это ответ на мой вопрос. Я делал что-то подобное раньше, но у меня возникла проблема с начальными значениями, потому что они не загружаются во время выполнения, мне нужно ждать, пока значение будет готово. Но я, должно быть, делаю что-то не так, потому что я только что попробовал ваше предложение на своей кодовой ручке, и оно работает. Если хотите проверить: codepen.io/oscarcarvalho/pen/GaXgPg <os-choice3> теперь делает то, что мне нужно. Спасибо

RAMIREZ 29.05.2019 11:10

Другие вопросы по теме