首页 文章

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

提问于
浏览
1

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

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

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

所以在这种情况下,我会检测 CountrySelect 内的选择框的更改并触发事件 changed 以及国家对象 . 然后 CountrySelect 的父组件将侦听此事件,然后当发生这种情况时将更新其属性 country . 属性 country 在父组件中是"observed",更改其值将导致DOM更新,因此 <city-select> 标记上的HTML属性( country )将更改 . 但是,我将如何检测 CitySelect 组件的属性更改,因为我需要通过AJAX重新加载城市 . 我想在 CitySelect 中将 country 属性放在 watch 对象中,但这对我来说似乎不是一个优雅的解决方案,它不会让人觉得这样做是正确的...

<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 组件告诉其兄弟组件 CitySelect 更新城市列表的正确方法是什么...

1 回答

  • 3

    通过将 country 作为属性传递给 CitySelect 组件,您已经在做您需要做的事情 . 当 country 更改时,更改的值将传递给 CitySelect 组件 . 您只需确保 CitySelect 组件了解更改 .

    这是一个有效的例子 .

    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
      }
    })
    
    <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>
    

相关问题