Потери при инициации V-модели Vue выбирают выбор

У меня проблема с инициализацией Vue для определенных типов элементов html, взгляните на следующий код:

new Vue({
  el: '#app',
  data: {
    test: ''
  }
})
<script src="https://unpkg.com/vue"></script>

<div id="app">
  Without Vue:
  <!-- Non-Vue select defaults to selected value -->
  <select>
    <option>1</option>
    <option selected>2</option>
    <option>3</option>
  </select>

  <br /> 
  <br /> 
  
  With Vue:
  <!-- Vue enabled list loses selection -->
  <select v-model="test">
    <option>1</option>
    <option selected>2</option>
    <option>3</option>
  </select>
</div>

Когда я запускаю Vue, кажется, что любые «выбранные», о которых вы объявляете v-Modal, теряют свое выбранное значение. Это описано в документации:

v-model будет игнорировать начальное значение, отмеченные или выбранные атрибуты, найденные в любых элементах формы. Он всегда будет рассматривать данные экземпляра Vue как источник истины. Вы должны объявить начальное значение на стороне JavaScript внутри параметра данных вашего компонента.

Теперь я могу это сделать, но для каждого выбора мне теперь нужно написать немного JS за пределами Vue, чтобы заполнить / повторно заполнить значение по умолчанию для выбора (путем заполнения свойства «данные» или повторного выбора ранее выбранного значения после замедления Vue).

Есть ли более простой способ сделать это? Может быть, какой-то параметр или тег, который я могу передать во Vue, чтобы «сохранить» значения, унаследованные от начального состояния элемента управления HTML?


person David Rogers    schedule 09.10.2018    source источник
comment
почему бы не присвоить свойству data = test одно значение по умолчанию, такое же, как для одной из опций, например test: 2?   -  person Sphinx    schedule 10.10.2018
comment
Да, я сделал что-то вроде var XXX = $('#XXX').val(); ... vueObject.data = XXX, но в основном то же самое, да, ваш подход, вероятно, сработает лучше, чем более хитрый обходной путь, который я использовал. Я знаю, что есть способы обойти такое поведение, я просто хочу чего-нибудь попроще. С большими пользовательскими формами с множеством выпадающих меню становится утомительно ...   -  person David Rogers    schedule 10.10.2018


Ответы (2)


Чтобы воспользоваться системой реактивности vue, vue нужен полный контроль. Так что выхода нет, вы должны каким-то образом сообщить vue об этих значениях по умолчанию.

Если вы ориентированы на HTML, это будет немного неудобно: вам нужно выбрать элемент dom, чтобы найти его значение по умолчанию и вернуть его в vue. Это сработает, но будет однозначно.

Правильный способ vue - полностью управлять данными и создавать HTML на основе данных. Например, если в вашей форме есть 2 поля выбора, то с помощью vue вы должны определить данные для всех option, которые у вас есть, и использовать эти данные для создания этих элементов с нуля (обратите внимание, что я использую здесь формат Single File Component):

<template>
  <div>
    <Select :items="list1"/>
    <Select :items="list2"/>
  </div>
</template>
<script>
import Select from './components/Select.vue';

export default {
  data() {
    return {
      list1: [
        { id: 1, name: "spoon" },
        { id: 2, name: "fork", preselect: true },
        { id: 3, name: "knife" }
      ],
      list2: [
        { id: 4, name: "macbook" },
        { id: 5, name: "dell" },
        { id: 6, name: "lenovo", preselect: true }
      ]
    };
  },
  components: { Select }
};
</script>

И вот код для компонента <Select> (обратите внимание, что это настраиваемый компонент Vue, поскольку он начинается с заглавной буквы S). Этот компонент получит свойство items и автоматически вычислит выбранное значение из данных элементов:

<template>
  <select v-model="selected">
    <option 
      v-for="item of items"
      :key="item.id"
      :value="item.id">
        {{ item.name }}
    </option>
  </select>
</template>
<script>
export default {
  props: ["items"],
  data() {
    return {
      // pre-select item from 'items'
      selected: this.items.filter(item => item.preselect)[0].id
    };
  }
};
</script>

После этого элемент fork и элемент lenovo будут предварительно выбраны в соответствии с данными. Вы также можете увидеть рабочий пример в этой codeandbox.

person b0nyb0y    schedule 10.10.2018
comment
Да, это было бы здорово, если бы я не пытался реализовать поверх устаревшего приложения веб-форм, прямо сейчас моя задача - поставить vue поверх кучи asp: DropDownList, возможно, мне нужно будет все это переделать ... - person David Rogers; 10.10.2018
comment
@DavidRogers, я чувствую твою боль. Когда вы когда-нибудь решите перейти на полноценный идиоматический Vue, если вы также выполняли веб-скрейпинг / тестирование e2e с selenium или puppeteer, вы определенно можете создать сценарий, чтобы найти все элементы <input> или <select> и построить данные оттуда. Для больших форм в действительно большом устаревшем приложении слишком сложно создавать JSON вручную. - person b0nyb0y; 10.10.2018

Ответ @ b0nyb0y технически верен, но, поскольку он не решает мою конкретную проблему, я полагаю, что включил бы здесь свой хакерский обходной путь для дальнейшего использования (работает только для выбранных):

var itemsToRestore = [];
$('select[v-model]').each(function (index, value) {
    itemsToRestore.push({
        vModelProperty: $(value).attr("v-model"),
        selectedValue: $(value).val()
    });
});

var thisVue = new Vue({
    //Put your vue code here
});

itemsToRestore.forEach(function (value) {
    thisVue[value.vModelProperty] = value.selectedValue;
});
person David Rogers    schedule 10.10.2018