[Vue warn]: Duplicate keys found during update: Make sure keys are unique
[Vue warn]: Duplicate keys found during update: Make sure keys are unique
我正在 Vue 中构建一个井字游戏,当我尝试重置棋盘时遇到此错误。
[Vue 警告]:更新期间发现重复键:“确保键是唯一的。”
棋盘在视觉上开始变形。我在屏幕上出现额外的方块。
我错过了什么?我的状态设置正确吗?
<template>
<h2>{{ msg }}</h2>
<h2 v-if="winner" >Winner: {{ winner }}</h2>
<h2 v-else>Player Move: {{ turn }}</h2>
<div id="board">
<div class="square" v-for="(square, index) in squares" :key="square" @click="takeTurn(index)">
{{ square }}
</div>
</div>
<button @click="reset">
Reset
</button>
</template>
<script>
import { ref, computed } from 'vue'
export default {
name: 'MainBoard',
props: {
msg: String // Vue has prop typechecking by default
},
setup () {
const turn = ref('X') // player first turn
const squares = ref([])
for (let i = 0; i <= 8; i++) squares.value.push('') // make a blank board}
console.log('squares value: ' + squares.value)
const winner = computed(() => checkForWinner(squares.value.flat())) // check 4 winner everytime board changes
console.log('computed:' + squares.value.flat())
function checkForWinner (value) {
console.log('check4Winner: ' + value)
// NOTE: in this version we have a
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8], // horizontal wins
[0, 3, 6],
[1, 4, 7],
[2, 5, 8], // vertical wins
[0, 4, 8],
[2, 4, 6] // cross wins
]
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i]
if (
value[a] &&
value[a] === value[b] &&
value[a] === value[c]
) {
console.log('value[a]: ' + value[a])
return value[a]
}
}
return null
}
function checkForTieGame () {
// make it a boolean
// let isTie = true
// check each space on the board
squares.value.forEach((s) => {
// if a space is available
// if (s === null) isTie = false
})
// if tie is true, end the game
// if (isTie === true) gameOver.value = true
}
function takeTurn (n) {
console.log('takeTurn value: ' + n)
if (winner.value) return
squares.value[n] = turn.value
checkForTieGame()
turn.value = turn.value === 'X' ? 'O' : 'X'
console.log('player: ' + turn.value)
}
function reset () {
turn.value = 'O'
console.log(squares.value.length)
squares.value = squares.value.map((square) => '')
// for (let i = 0; i <= 8; i++) squares.value.push('') // make a blank board
}
return { squares, turn, winner, checkForWinner, takeTurn, reset }
}
}
</script>
<style scoped>
button{
margin-top: 40px;
}
#board {
border: 1px solid darkred;
height: 400px;
width: 400px;
margin:0 auto;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.square {
background: #fff;
border: 1px solid #999;
/*float: left;*/
font-size: 70px;
font-weight: bold;
line-height: 34px;
height: 100px;
width: 100px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
}
</style>
感谢您的宝贵时间
将 v-for 循环中的键设置为唯一(索引),因此将 :key="square"
替换为 :key="index"
const { ref, computed } = Vue
const app = Vue.createApp({
props: {
msg: String // Vue has prop typechecking by default
},
setup () {
const turn = ref('X') // player first turn
const squares = ref([])
for (let i = 0; i <= 8; i++) squares.value.push('') // make a blank board}
console.log('squares value: ' + squares.value)
const winner = computed(() => checkForWinner(squares.value.flat())) // check 4 winner everytime board changes
console.log('computed:' + squares.value.flat())
function checkForWinner (value) {
console.log('check4Winner: ' + value)
// NOTE: in this version we have a
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8], // horizontal wins
[0, 3, 6],
[1, 4, 7],
[2, 5, 8], // vertical wins
[0, 4, 8],
[2, 4, 6] // cross wins
]
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i]
if (
value[a] &&
value[a] === value[b] &&
value[a] === value[c]
) {
console.log('value[a]: ' + value[a])
return value[a]
}
}
return null
}
function checkForTieGame () {
// make it a boolean
// let isTie = true
// check each space on the board
squares.value.forEach((s) => {
// if a space is available
// if (s === null) isTie = false
})
// if tie is true, end the game
// if (isTie === true) gameOver.value = true
}
function takeTurn (n) {
console.log('takeTurn value: ' + n)
if (winner.value) return
squares.value[n] = turn.value
checkForTieGame()
turn.value = turn.value === 'X' ? 'O' : 'X'
console.log('player: ' + turn.value)
}
function reset () {
turn.value = 'O'
squares.value = Array(9).fill('');
}
return { squares, turn, winner, checkForWinner, takeTurn, reset }
}
})
app.mount('#demo')
button{
margin-top: 40px;
}
#board {
border: 1px solid darkred;
height: 200px;
width: 200px;
margin:0 auto;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.square {
background: #fff;
border: 1px solid #999;
/*float: left;*/
font-size: 70px;
font-weight: bold;
line-height: 34px;
height: 50px;
width: 50px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
}
<script src="https://unpkg.com/vue@3.2.29/dist/vue.global.prod.js"></script>
<div id="demo">
<h2>{{ msg }}</h2>
<h2 v-if="winner" >Winner: {{ winner }}</h2>
<h2 v-else>Player Move: {{ turn }}</h2>
<div id="board">
<!-- index is unique -->
<div class="square" v-for="(square, index) in squares" :key="index" @click="takeTurn(index)">
{{ square }}
</div>
</div>
<button @click="reset">
Reset
</button>
</div>
我正在 Vue 中构建一个井字游戏,当我尝试重置棋盘时遇到此错误。
[Vue 警告]:更新期间发现重复键:“确保键是唯一的。”
棋盘在视觉上开始变形。我在屏幕上出现额外的方块。
我错过了什么?我的状态设置正确吗?
<template>
<h2>{{ msg }}</h2>
<h2 v-if="winner" >Winner: {{ winner }}</h2>
<h2 v-else>Player Move: {{ turn }}</h2>
<div id="board">
<div class="square" v-for="(square, index) in squares" :key="square" @click="takeTurn(index)">
{{ square }}
</div>
</div>
<button @click="reset">
Reset
</button>
</template>
<script>
import { ref, computed } from 'vue'
export default {
name: 'MainBoard',
props: {
msg: String // Vue has prop typechecking by default
},
setup () {
const turn = ref('X') // player first turn
const squares = ref([])
for (let i = 0; i <= 8; i++) squares.value.push('') // make a blank board}
console.log('squares value: ' + squares.value)
const winner = computed(() => checkForWinner(squares.value.flat())) // check 4 winner everytime board changes
console.log('computed:' + squares.value.flat())
function checkForWinner (value) {
console.log('check4Winner: ' + value)
// NOTE: in this version we have a
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8], // horizontal wins
[0, 3, 6],
[1, 4, 7],
[2, 5, 8], // vertical wins
[0, 4, 8],
[2, 4, 6] // cross wins
]
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i]
if (
value[a] &&
value[a] === value[b] &&
value[a] === value[c]
) {
console.log('value[a]: ' + value[a])
return value[a]
}
}
return null
}
function checkForTieGame () {
// make it a boolean
// let isTie = true
// check each space on the board
squares.value.forEach((s) => {
// if a space is available
// if (s === null) isTie = false
})
// if tie is true, end the game
// if (isTie === true) gameOver.value = true
}
function takeTurn (n) {
console.log('takeTurn value: ' + n)
if (winner.value) return
squares.value[n] = turn.value
checkForTieGame()
turn.value = turn.value === 'X' ? 'O' : 'X'
console.log('player: ' + turn.value)
}
function reset () {
turn.value = 'O'
console.log(squares.value.length)
squares.value = squares.value.map((square) => '')
// for (let i = 0; i <= 8; i++) squares.value.push('') // make a blank board
}
return { squares, turn, winner, checkForWinner, takeTurn, reset }
}
}
</script>
<style scoped>
button{
margin-top: 40px;
}
#board {
border: 1px solid darkred;
height: 400px;
width: 400px;
margin:0 auto;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.square {
background: #fff;
border: 1px solid #999;
/*float: left;*/
font-size: 70px;
font-weight: bold;
line-height: 34px;
height: 100px;
width: 100px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
}
</style>
感谢您的宝贵时间
将 v-for 循环中的键设置为唯一(索引),因此将 :key="square"
替换为 :key="index"
const { ref, computed } = Vue
const app = Vue.createApp({
props: {
msg: String // Vue has prop typechecking by default
},
setup () {
const turn = ref('X') // player first turn
const squares = ref([])
for (let i = 0; i <= 8; i++) squares.value.push('') // make a blank board}
console.log('squares value: ' + squares.value)
const winner = computed(() => checkForWinner(squares.value.flat())) // check 4 winner everytime board changes
console.log('computed:' + squares.value.flat())
function checkForWinner (value) {
console.log('check4Winner: ' + value)
// NOTE: in this version we have a
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8], // horizontal wins
[0, 3, 6],
[1, 4, 7],
[2, 5, 8], // vertical wins
[0, 4, 8],
[2, 4, 6] // cross wins
]
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i]
if (
value[a] &&
value[a] === value[b] &&
value[a] === value[c]
) {
console.log('value[a]: ' + value[a])
return value[a]
}
}
return null
}
function checkForTieGame () {
// make it a boolean
// let isTie = true
// check each space on the board
squares.value.forEach((s) => {
// if a space is available
// if (s === null) isTie = false
})
// if tie is true, end the game
// if (isTie === true) gameOver.value = true
}
function takeTurn (n) {
console.log('takeTurn value: ' + n)
if (winner.value) return
squares.value[n] = turn.value
checkForTieGame()
turn.value = turn.value === 'X' ? 'O' : 'X'
console.log('player: ' + turn.value)
}
function reset () {
turn.value = 'O'
squares.value = Array(9).fill('');
}
return { squares, turn, winner, checkForWinner, takeTurn, reset }
}
})
app.mount('#demo')
button{
margin-top: 40px;
}
#board {
border: 1px solid darkred;
height: 200px;
width: 200px;
margin:0 auto;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.square {
background: #fff;
border: 1px solid #999;
/*float: left;*/
font-size: 70px;
font-weight: bold;
line-height: 34px;
height: 50px;
width: 50px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
}
<script src="https://unpkg.com/vue@3.2.29/dist/vue.global.prod.js"></script>
<div id="demo">
<h2>{{ msg }}</h2>
<h2 v-if="winner" >Winner: {{ winner }}</h2>
<h2 v-else>Player Move: {{ turn }}</h2>
<div id="board">
<!-- index is unique -->
<div class="square" v-for="(square, index) in squares" :key="index" @click="takeTurn(index)">
{{ square }}
</div>
</div>
<button @click="reset">
Reset
</button>
</div>