首页 > 解决方案 > Vue 组件数据对象属性的行为不符合预期 [已解决]

问题描述

我有一个带有子组件的应用程序,它调用 api 以获取球员的赛季统计数据。您单击玩家姓名,我会从父组件向子组件发出单击事件。问题是当您从父级单击 Players name 时,子组件的所有实例都会显示出来。我只想要一个球员。我想是因为我通过在 child 中切换 this.showComponent 为每个孩子都有一个 showComponent 实例会得到我预期的行为,但没有。代码:父-

methods: {
        emitPlayerSeasonStatsClicked: function(event) {
        const target = event.target;
        EventBus.$emit("showPlayerTemplateClicked", target);
      }
    },
    template: `




                                                        <div v-for="playerStats in props_box_game_scores[index].data.gameboxscore.awayTeam.awayPlayers.playerEntry">
                                                                <tr v-if="playerStats.player.Position === 'P'" class="d-flex" v-bind:data-player-id="playerStats.player.ID">
                                                                    <td class="col-4 justify-content-center" scope="row" title="Click for Season Stats">
                                                                        {{playerStats.player.FirstName}} {{playerStats.player.LastName}} 
                                                                    <span v-if="playerStats.stats.Wins['#text'] === '1'">(W)</span> 
                                                                    <span v-else-if="playerStats.stats.Losses['#text'] === '1'">(L)</span> 
                                                                    <span v-else-if="playerStats.stats.Saves['#text'] === '1'">(S)</span>  
                                                                    </td>

                                                                    <td class="col-2 justify-content-center" justify-content="center">
                                                                        {{playerStats.stats.InningsPitched['#text']}}</td>
                                                                    <td class="col-2 justify-content-center">{{playerStats.stats.RunsAllowed['#text']}}</td>
                                                                    <td class="col-2 justify-content-center">{{playerStats.stats.PitcherStrikeouts['#text']}}</td>
                                                                    <td class="col-2 justify-content-center">{{playerStats.stats.EarnedRunAvg['#text']}}
                                                                    </td>
                                                                </tr>

                                                                <pitcher-season-stats v-bind:props_player_id="playerStats.player.ID"></pitcher-season-stats>

                                                        </div>

孩子-

cumlativeStats: Vue.component("player-season-stats", {
    props: ["props_player_id"],
    data: function() {
      return {
        Hits: "",
        HR: "",
        RBI: "",
        BattingAvg: "",
        showComponent: false
      };
    },
    mounted: function() {
      EventBus.$on("showPlayerTemplateClicked", function(data) {
        this.showComponent = !this.showComponent;
      });
    },
    methods: {
      retrievePlayerStats: function(playerId) {
        const url = `https://api.mysportsfeeds.com/v1.2/pull/mlb/2019-regular/cumulative_player_stats.json?player=`;
        const params = {
          playerstats: "AB,H,HR,RBI,AVG",
          force: true
        };

...
template: `
      <tr class="d-flex" v-if:showComponent>
        <td @click="retrievePlayerStats(props_player_id)" class="col-4 justify-content-center" scope="row">
            Season Stats</td>
        </td>
        <td class="col-2 justify-content-center" justify-content="center">
          {{ Hits }}</td>
        <td class="col-2 justify-content-center">{{ HR }}</td>
        <td class="col-2 justify-content-center"> {{ BattingAvg }}</td>
        <td class="col-2 justify-content-center">{{ RBI }}</td>
      </tr>
    ` // End template
  })

欢迎任何建议。抱歉格式化。

**

更新的工作解决方案:

**

家长:

methods: {
emitPlayerSeasonStatsClicked: function($event) {
        let playerId = $event.target.dataset.playerId;
        EventBus.$emit("showPlayerTemplateClicked", playerId);
      }
 }
....

<table @click="emitPlayerSeasonStatsClicked($event)" class="table table-striped table-bordered table-hover table-sm collapse" v-bind:class="'multi-collapse-' + index">

<tr v-if="playerStats.stats.AtBats['#text'] > 0" class="d-flex">
 <td class="col-4 justify-content-center" :data-player-id='playerStats.player.ID' scope="row" title="Click for Season Stats">
                                                                        {{playerStats.player.FirstName}} {{playerStats.player.LastName}} ({{playerStats.player.Position}})</td>

孩子:

mounted: function() {
      EventBus.$on(
        "showPlayerTemplateClicked",
        this.onShowPlayerTemplateClicked
      );
    },
    methods: {
      onShowPlayerTemplateClicked: function(playerId) {
        if (playerId === this.props_player_id) {
          this.loading = true;
          this.showComponent = !this.showComponent;
          this.retrievePlayerStats(playerId);
        }
      },



template: `
      <transition name="fade">
        <tr class="d-flex" v-if="showComponent">
          <td  v-if="!loading" class="col-4 justify-content-center" scope="row">
              Season Stats</td>
          </td>
          <td class="col-2 justify-content-center" justify-content="center">
            {{ Hits }}</td>
          <td class="col-2 justify-content-center">{{ HR }}</td>
          <td class="col-2 justify-content-center"> {{ BattingAvg }}</td>
          <td class="col-2 justify-content-center">{{ RBI }}</td>
        </tr>
      </transition>

    ` // End template
  })
};

标签: vue.jsvue-component

解决方案


提供的代码实际上并没有调用emitPlayerSeasonStatsClicked,但我认为应该继续<td>包含名称。

如果你这样写点击监听器:

<td
  class="col-4 justify-content-center"
  scope="row"
  title="Click for Season Stats"
  @click="emitPlayerSeasonStatsClicked(playerStats.player.ID)"
>

然后将 id 作为事件总线发出的事件的一部分包含在内:

emitPlayerSeasonStatsClicked: function(playerId) {
  EventBus.$emit("showPlayerTemplateClicked", playerId);
}

在mounted中听这个将是:

mounted: function() {
  EventBus.$on("showPlayerTemplateClicked", this.onShowPlayerTemplateClicked);
},

用方法:

methods: {
  onShowPlayerTemplateClicked: function(playerId) {
    if (playerId === this.props_player_id) {
      this.showComponent = !this.showComponent;
    }
  }
}

假设玩家 ID 是唯一的,应该足以让它工作。

然而...

  1. 将数据传递给孩子的事件总线的选择似乎很糟糕。有几种方法可以做到这一点。一种方法是仅在显示时创建它(外部v-if)。另一个是使用道具。还有一个是使用 refs 来调用孩子的方法。
  2. 我不明白你的代码是如何切换任何东西的。this监听器的值mounted不会是组件。我已经通过将它移动到一个方法来解决这个问题,Vue 将正确绑定该方法。将其移至方法的另一个原因是它允许您在组件被销毁时删除侦听器。
  3. v-if:showComponent不是一回事。我认为应该是v-if="showComponent"
  4. 您的<tr>元素似乎是元素的直接子<div>元素。这不是表格的正确 HTML。

推荐阅读