简体   繁体   English

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

[英]How to properly pass data to sibling component using VueJS?

Let's say I have CountrySelect and CitySelect , where in CountrySelect are listed all countries and in CitySelect are only listed those cities of currently selected country... 比方说,我有CountrySelectCitySelect ,在CountrySelect列出的所有国家和CitySelect只列出的目前选定的国家的这些城市...

What would the proper way to pass newly selected country. 通过新选择的国家/地区的正确方法是什么? As I have read in vuejs documentation: 正如我在vuejs文档中阅读的:

In Vue, the parent-child component relationship can be summarized as props down, events up. 在Vue中,父子组件关系可以概括为道具下降,事件上升。 The parent passes data down to the child via props, and the child sends messages to the parent via events. 父级通过道具将数据传递给子级,而子级则通过事件将消息发送给父级。 Let's see how they work next. 让我们看看它们接下来如何工作。

So in this case, I would detect change of select box inside of CountrySelect and fire event changed and along with it a country object. 因此,在这种情况下,我将检测到CountrySelect内的选择框发生了changed ,并且触发了火灾事件以及一个国家对象。 Then the parent component of CountrySelect would listen for this event and then when that happens will update its attribute country . 然后, CountrySelect的父组件将侦听此事件,然后在发生该事件时将更新其属性country Attribute country is "observed" in parent component and changing its value will cause for DOM to update, so HTML attribute on <city-select> tag called country would change. 在父组件中“观察到”属性country ,更改其值将导致DOM更新,因此<city-select>标记上称为country HTML属性将发生更改。 But then how would I detect property change of CitySelect component, since I need to reload cities via AJAX. 但是然后我将如何检测CitySelect组件的属性变化,因为我需要通过AJAX重新加载城市。 I think of putting country property in watch object in CitySelect but that does not seems like an elegant solution to me, it doesn't feels quire right to do... 我认为把的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>

Other way around that I think is if do something like this in parent: 我认为的另一种解决方法是是否在父级中执行以下操作:

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

or: 要么:

this.$refs.citySelect.countryChanged(this.country)

I do not know if these two are possible... So what would be the correct way for CountrySelect component to tell to its sibling component CitySelect to update cities list... 我不知道这两位是可能的...那么,什么是正确的方式CountrySelect组件告诉给其兄弟组件CitySelect更新城市列表...

By passing country as a property to your CitySelect component, you are already doing what you need to do. 通过将country作为属性传递给CitySelect组件,您已经在做您需要做的事情。 When country changes, the changed value will be passed to the CitySelect component. country更改时,更改后的值将传递到CitySelect组件。 You simply need to make sure your CitySelect component is aware of the changes. 您只需要确保CitySelect组件知道更改即可。

Here is a working example. 这是一个工作示例。

 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> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM