Использование v-модели с выбором в качестве внешнего компонента - PullRequest
0 голосов
/ 04 июня 2018

Я хочу создать компонент selectbox, который имеет предопределенную разметку и должен использоваться везде в моей системе.
Я испытываю трудности с пониманием свойства v-model и того, как оно может синхронизировать предопределенное значение, полученное изродительский компонент и внутреннее значение selectbox.

Вот мой пример: http://jsfiddle.net/eywraw8t/60103/

Я бы хотел, чтобы мой корневой компонент предварительно выбрал значение, которое компонент Selectbox может изменить.Мой пример работает, как и ожидалось, но использование события $emit в окне выбора кажется неправильным, как я это делаю.

const Selectbox = {
    props: {
        value: String
    },

    methods: {
        select($event, value) {
        	// The example works but having
            // $event.target.value here seems very wrong
            this.$emit('input', $event.target.value);
        }
    },
    
    template: `
        <div>
            <select :value="value" @change="select($event, value)">
                <option value="1">Option 1</option>
                <option value="2">Option 2</option>
                <option value="3">Option 3</option>
            </select>
            <div>The value is {{ value }}.</div>
        </div>`
};

new Vue({
  el: "#app",
  components: { Selectbox },
  data: () => ({
  	selectboxValue: 1
  }),
  template: `
    <div>
        <selectbox v-model="selectboxValue" />
    </div>
  `
})
body {
  padding: 50px;
}

label {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
</div>

1 Ответ

0 голосов
/ 04 июня 2018

Как я уже упоминал в комментарии выше, вы, по сути, делаете все правильно, но передаете некоторые аргументы методу select, который вам на самом деле не нужен.В случае события change элемента select в вашем компоненте вам не нужно ничего передавать, поскольку объект event будет автоматически передан, если вы просто укажете функцию.

В вашем шаблоне:

<select :value="value" @change="select">

И ваш обработчик событий:

select(evt) {
  this.$emit('input', evt.target.value);
}

const Selectbox = {
    props: {
        value: String
    },

    methods: {
        select(evt) {
            this.$emit('input', evt.target.value);
        }
    },
    
    template: `
        <div>
            <select :value="value" @change="select">
                <option value="1">Option 1</option>
                <option value="2">Option 2</option>
                <option value="3">Option 3</option>
            </select>
            <div>The value is {{ value }}.</div>
        </div>`
};

new Vue({
  el: "#app",
  components: { Selectbox },
  data: () => ({
  	selectboxValue: 1
  }),
  template: `
    <div>
        <selectbox v-model="selectboxValue" />
    </div>
  `
})
body {
  padding: 50px;
}

label {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
</div>

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

<select v-model="selected">
  <option value="1">Option 1</option>
  <option value="2">Option 2</option>
  <option value="3">Option 3</option>
</select>

И вычисляется так:

computed:{
  selected:{
    get() {return this.value},
    set(v) {this.$emit('input', v)}
  }
},

const Selectbox = {
    props: {
        value: String
    },
    computed:{
    	selected:{
      	get() {return this.value},
        set(v) {this.$emit('input', v)}
      }
    },
    template: `
    <div>
        <select v-model="selected">
            <option value="1">Option 1</option>
            <option value="2">Option 2</option>
            <option value="3">Option 3</option>
        </select>
        <div>The value is {{ value }}.</div>
    </div>`
};

new Vue({
  el: "#app",
  components: { Selectbox },
  data: () => ({
  	selectboxValue: 1
  }),
  template: `
  	<div>
    	<selectbox v-model="selectboxValue" />
    </div>
  `
})
body {
  padding: 50px;
}

label {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
</div>
...