【问题标题】:How to properly pass data to sibling component using VueJS?如何使用 VueJS 正确地将数据传递给兄弟组件?
【发布时间】:2018-01-10 15:25:04
【问题描述】:

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

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

在Vue中,父子组件关系可以概括为props down,events up。父级通过 props 向下传递数据给子级,子级通过事件向父级发送消息。让我们看看它们接下来是如何工作的。

所以在这种情况下,我会检测到 CountrySelect 内的选择框的变化和触发事件 changed 以及一个国家对象。然后CountrySelect 的父组件将侦听此事件,然后在发生这种情况时更新其属性country。属性country 在父组件中被“观察到”,更改其值将导致DOM 更新,因此<city-select> 标记上称为country 的HTML 属性会更改。但是我将如何检测CitySelect 组件的属性变化,因为我需要通过 AJAX 重新加载城市。我想将country 属性放在watch 对象中的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 组件告诉其兄弟组件CitySelect 更新城市列表的正确方法是什么...

【问题讨论】:

    标签: javascript vue.js vuejs2


    【解决方案1】:

    通过将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>

    【讨论】:

    • 因此您创建了使用country 属性的计算属性,因为这样,每次更改country 时都会重新计算filteredCities,因为它依赖于它?当filteredCities 被重新计算时,DOM 被更新......但我想使用 AJAX,在这种情况下,我将如何根据国家 ID(/api/lists/countries/3/cities)获取新的城市列表......?
    • @clzola 我只是在处理这个问题 :) 使用模拟 AJAX 调用进行了更新。
    • 啊哈,就像我在问题中提到的那样,“观看”属性:D 谢谢
    • @clzola 我认为手表是这里最合适的方式。您可以使用计算值,但异步计算值通常不是一个好主意。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-10
    • 2018-08-13
    • 2020-09-02
    • 2018-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多