如何在使用 $refs 回调时监听 vue 事件

how to listen to vue events when callback with $refs

制作剪刀石头布游戏,想让电脑随机选择一手牌。到目前为止,一切都很好。 我希望当 player/human 也选择了一只手时,计算机会被 v-on:humanChoosedHand="startGame()" 之类的事件侦听器触发以选择一只手。 当我为人类选择一只手时,我可以检查并看到事件 humanChoosedHand 被触发,但是 parent GameField.vue 没有监听 代码如下所示:

parentGameField.vue

<template>
  <div id="game-field">
    <button class="btn btn-primary" @click="startGame()">Start</button>

    <div class="row">
      <div class="col-md-6 pt-5">
        <Human></Human>
      </div>
      <div class="col-md-6 pt-5">
        <Computer ref="computer" v-on:humanChoosedHand="startGame()"></Computer>
      </div>
    </div>
  </div>
</template>

<script>
import Human from './Human.vue'
import Computer from './Computer.vue'
export default {
  data: () => {
    return {
      score: [
        {
          human: 0
        },
        {
          computer: 0
        }
      ]
    }
  },
  components: {
    Human,
    Computer
  },
  props: {
    difficulty: String
  },
  methods: {
    startGame () {
      console.log('Game Started')
      // this.$refs.computer.shuffleAnimation()
      this.$refs.computer.setRandomHand() //<-----
      // listen to emit here, not in html template
    },
    testFunction () {
      console.log('test')
    }
  }
}
</script>

<style lang="scss">
#game-field {
  .far {
    cursor: pointer;
    font-size: 300px;
    width: 350px;
    height: 350px;
  }

  .row {
    margin: 0 0 0 0;

    .select-hand {
      position: relative;
      left: 60px;
      .far {
        font-size: 80px;
        height: 0;
        width: 0;
      }
      .far:hover {
        color: $orange;
      }
    }
  }

  .btn-primary {
    background-color: $orange;
    border-color: $orange;
    position: relative;
    top: 50%;
    left: 50%;
    transform: translate(-50%, 30%);
  }
  .btn-primary:focus {
    background-color: $orange;
    border-color: $black !important;
    box-shadow: 0 0 0 0.2rem rgba(255, 51, 0, 0.644);
  }
}
</style>

然后 child Computer.vue:

<template>
  <div id="computer">
    <div class="text-center">
      <div class="h2 mb-5">Computer</div>
      <i class="far" :class="playIcon"></i>
      <div class="hand h3 mt-4">{{ activeHand }}</div>
    </div>
  </div>
</template>

<script>
export default {
  data: () => {
    return {
      winCounter: 0,
      activeHand: 'I am ready',
      playIcon: '',
      hands: [
        {
          name: 'Rock',
          strength: 'scissor',
          weakness: 'paper',
          icon: 'fa-hand-rock'
        },
        {
          name: 'Paper',
          strength: 'rock',
          weakness: 'scissor',
          icon: 'fa-hand-paper'
        },
        {
          name: 'Scissor',
          strength: 'paper',
          weakness: 'rock',
          icon: 'fa-hand-scissors'
        }
      ]
    };
  },
  methods: {
    setRandomHand() {
      // THIS SHOULD LISTEN TO THE 'humanChoosedHand' 
      // and should gets triggered by a 'ref.computer.setRandomHand' then
      console.log('computer listens');

      let choosedHand = Math.round(Math.random() * 2);
      this.activeHand = this.hands[choosedHand].name;
      this.playIcon = this.hands[choosedHand].icon;
      this.$emit('computerChoosedHand', this.activeHand.toLowerCase());
    }
    // shuffleAnimation () {
    //   setInterval(() => {
    //     let shuffle = Math.round(Math.random() * 2)
    //     this.activeHand = this.hands[shuffle].name
    //     this.playIcon = this.hands[shuffle].icon
    //   }, 100)
    // }
  }
};
</script>

<style lang="scss">
#computer .far {
  transform: rotate(-90deg);
}
</style>

GameField 的其他 child - Human.vue

<template>
  <div id="human">
    <div class="text-center">
      <div class="h2 mb-5">Human</div>
      <i class="far" :class="playIcon"></i>
      <div class="h3 mt-4">{{ activeHand }}</div>
      <div class="row select-hand mt-4">
        <div class="col-md-4">
          <i class="far fa-hand-rock" @click="setHand(hands[0])"></i>
        </div>
        <div class="col-md-4">
          <i class="far fa-hand-paper" @click="setHand(hands[1])"></i>
        </div>
        <div class="col-md-4">
          <i class="far fa-hand-scissors" @click="setHand(hands[2])"></i>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data: () => {
    return {
      winCounter: 0,
      activeHand: 'Choose a Hand',
      playIcon: '',
      hands: [
        {
          name: 'Rock',
          strength: 'scissor',
          weakness: 'paper',
          icon: 'fa-hand-rock'
        },
        {
          name: 'Paper',
          strength: 'rock',
          weakness: 'scissor',
          icon: 'fa-hand-paper'
        },
        {
          name: 'Scissor',
          strength: 'paper',
          weakness: 'rock',
          icon: 'fa-hand-scissors'
        }
      ]
    }
  },
  methods: {
    setHand (hand) {
      this.activeHand = hand.name
      this.playIcon = hand.icon
      this.$emit('humanChoosedHand', this.activeHand.toLowerCase())
    }
  }
}
</script>

<style lang="scss">
#human .far {
  transform: rotate(90deg);
}
</style>

可能无法监听一个事件然后$ref.component.callFunction()

Gamefield 没有正确收听,因为您的代码中缺少一些代码。您需要在标签中添加@humanChoosedHand

<Human @humanChoosedHand="triggerComputer"></Human>

现在可以正确监听 humanChoosedHand

的变化

现在triggerComputer可以从Gamefield触发电脑功能:

triggerComputer() {
  this.$refs.computer.setRandomHand();
}

因此从 Computer 标签中删除 v-on:humanChoosedHand="startGame()"

这里有一个SANDBOX可以玩。