如何在使用 $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可以玩。
制作剪刀石头布游戏,想让电脑随机选择一手牌。到目前为止,一切都很好。
我希望当 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可以玩。