如何使用VueJS将数据正确传递给兄弟组件?

时间:2018-01-10 15:25:05

标签: javascript vue.js vuejs2

我们说我有CountrySelectCitySelect,其中CountrySelect列出了所有国家/地区,CitySelect仅列出了当前所选国家/地区的城市...

通过新选择的国家/地区的正确方法是什么?正如我在vuejs文档中读到的那样:

  

在Vue中,父子组件关系可以概括为道具向下,事件向上。父母通过道具将数据传递给孩子,孩子通过事件向父母发送消息。让我们看看他们下一步的工作方式。

所以在这种情况下,我会检测CountrySelect和火灾事件changed内部的选择框的变化,以及国家对象。然后CountrySelect的父组件将侦听此事件,然后在发生这种情况时将更新其属性country。属性country是&#34;观察到的&#34;在父组件中并更改其值将导致DOM更新,因此名为<city-select>的{​​{1}}标记上的HTML属性将更改。但是,我如何检测country组件的属性更改,因为我需要通过AJAX重新加载城市。我想将CitySelect属性放在country中的watch对象中,但这对我来说似乎不是一个优雅的解决方案,它不会让人觉得这样做... ... / p>

CitySelect

我认为其他方式是在父母那样做这样的事情:

<template>
    <parent>
        <country-select name="country_id" v-model="country"></country-select>
        <city-select name="city_id" :country="country" v-model="city"></city-select>
    </parent>
<template>

<script>
    export default {
        data: function() {
            return {
                country: null,
                city: null,
            };
        }
    }
</script>

或:

this.$refs.citySelect.emit('countryChanged', this.country)

我不知道这两个是否可能......那么this.$refs.citySelect.countryChanged(this.country) 组件告诉其兄弟组件CountrySelect更新城市列表的正确方法是什么......

1 个答案:

答案 0 :(得分:3)

country作为属性传递给CitySelect组件,您已经做了您需要做的事情。 country更改后,更改后的值将传递给CitySelect组件。您只需确保CitySelect组件了解更改。

这是一个有效的例子。

&#13;
&#13;
console.clear()

// Simulated service for retrieving cities by country
const CityService = {
  cities: [
    {id: 1, country: "USA", name: "New York"},
    {id: 2, country: "USA", name: "San Francisco"},
    {id: 3, country: "USA", name: "Boston"},
    {id: 4, country: "USA", name: "Chicago"},
    {id: 5, country: "England", name: "London"},
    {id: 6, country: "England", name: "Bristol"},
    {id: 7, country: "England", name: "Manchester"},
    {id: 8, country: "England", name: "Leeds"},
  ],
  getCities(country){
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(this.cities.filter(city => city.country === country)), 250)
    })
  }
}

Vue.component("CountrySelect",{
  props: ["value"],
  template: `
  <select v-model="selectedCountry">
    <option v-for="country in countries" :value="country">{{country}}</option>
  </select>
  `,
  data(){
    return {
      countries: ["USA", "England"]
    }
  },
  computed:{
    selectedCountry:{
      get(){return this.value},
      set(v){this.$emit('input', v)}
    }
  }
})

Vue.component("CitySelect", {
  props: ["value", "country"],
  template: `
  <select v-model="selectedCity">
    <option v-for="city in cities" :value="city">{{city.name}}</option>
  </select>
  `,
  data(){
    return {
      cities: []
    }
  },
  computed:{
    selectedCity:{
      get(){return this.value},
      set(v){this.$emit('input', v)}
    }
  },
  watch:{
    country(newCountry){
      // simulate an AJAX call to an external service
      CityService.getCities(newCountry).then(cities => this.cities = cities)
    }
  }
})

new Vue({
  el: "#app",
  data:{
    country: null,
    city: null
  }
})
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
  <country-select v-model="country"></country-select>
  <city-select :country="country" v-model="city"></city-select>
  <hr>
  Selected Country: {{country}} <br>
  Selected City: {{city}}
</div>
&#13;
&#13;
&#13;