我在用javascript写一个记忆游戏。我已经为卡片制作了一个网络组件,<memory-card>和一个网络组件来包含卡和处理游戏状态<memory-game>。<memory-card>类包含翻转时的图像路径、作为卡背面显示的默认图像、其翻转状态和处理状态与图像之间切换的onclick函数。
<memory-game>类有一个设置器,它接收要生成<memory-cards>的图像数组。在<memory-game>类中处理更新游戏状态的最佳方法是什么?我应该在<memory-card>元素上附加一个额外的事件侦听器,还是有更好的方法来解决它?我希望<memory-card>元素像现在这样只处理它们自己的功能(即点击时根据状态更改图像)。
memory-game.js
class memoryGame extends HTMLElement {
constructor () {
super()
this.root = this.attachShadow({ mode: 'open' })
this.cards = []
this.turnedCards = 0
}
flipCard () {
if (this.turnedCards < 2) {
this.turnedCards++
} else {
this.turnedCards = 0
this.cards.forEach(card => {
card.flipCard(true)
})
}
}
set images (paths) {
paths.forEach(path => {
const card = document.createElement('memory-card')
card.image = path
this.cards.push(card)
})
}
connectedCallback () {
this.cards.forEach(card => {
this.root.append(card)
})
}
}
customElements.define('memory-game', memoryGame)memory-card.js
class memoryCard extends HTMLElement {
constructor () {
super()
this.root = this.attachShadow({ mode: 'open' })
// set default states
this.turned = false
this.path = 'image/0.png'
this.root.innerHTML = `<img src="${this.path}"/>`
this.img = this.root.querySelector('img')
}
set image (path) {
this.path = path
}
flipCard (turnToBack = false) {
if (this.turned || turnToBack) {
this.turned = false
this.img.setAttribute('src', 'image/0.png')
} else {
this.turned = true
this.img.setAttribute('src', this.path)
}
}
connectedCallback () {
this.addEventListener('click', this.flipCard())
}
}
customElements.define('memory-card', memoryCard)在Supersharp的应答之后实现自定义事件
内存卡(提取)
connectedCallback () {
this.addEventListener('click', (e) => {
this.flipCard()
const event = new CustomEvent('flippedCard')
this.dispatchEvent(event)
})
}内存-game.js(提取)
set images (paths) {
paths.forEach(path => {
const card = document.createElement('memory-card')
card.addEventListener('flippedCard', this.flipCard.bind(this))
card.image = path
this.cards.push(card)
})
}发布于 2019-01-02 13:07:08
在<memory-card>中
CustomEvent()创建并使用dispatchEvent()分派自定义事件在<memory-game>中
addEventListener()收听您的自定义事件因为卡是嵌套在游戏中,事件将自然气泡到容器。
这样,两个自定义元素将保持松散耦合。
发布于 2019-01-09 12:35:38
超级尖锐的答案不是100%正确的。
click事件在DOM中冒泡,但是CustomEvents (在shadowDOM中)没有
Why firing a defined event with dispatchEvent doesn't obey the bubbling behavior of events?
因此,您必须自己添加bubbles:true:
[yoursender].dispatchEvent(new CustomEvent([youreventName], {
bubbles: true,
detail: [yourdata]
}));更多:https://javascript.info/dispatch-events
注意:detail可以是一个函数:How to communicate between Web Components (native UI)?
一个基于事件的编程挑战
this.cards.forEach(card => {
card.flipCard(true)
})首先,this.cards并不是必需的,因为所有卡都可以在[...this.children]中使用。
!!请记住,在JavaScript对象中是通过引用传递的,因此您的this.cards指向的正是--相同的 DOM子
你在这里有依赖性,
游戏需要了解卡片中的.flipCard方法。
►让你的记忆游戏发送一个事件,每个卡都会接收到
提示:每张卡片都需要在游戏DOM级别“监听”才能接收冒泡事件
在我的代码中,整个循环是:
game.emit('allCards','close');
卡片负责收听正确的EventListener
(附于card.parentNode)
这样,你的游戏中有多少张(或什么牌)就不重要了。
DOM是您的数据结构。
如果你的游戏不再关心它有多少或有多少DOM子,
而且它没有对已经拥有的元素进行任何记账,
洗牌成了小菜一碟:
shuffle() {
console.log('► Shuffle DOM children');
let game = this,
cards = [...game.children],//create Array from a NodeList
idx = cards.length;
while (idx--) game.insertBefore(rand(cards), rand(cards));//swap 2 random DOM elements
}我的全局rand函数,从数组或数字生成随机值
rand = x => Array.isArray(x) ? x[rand(x.length)] : 0 | x * Math.random(),额外挑战
如果你的基于事件的编程是正确的,
然后用创建一个内存游戏--三个匹配卡--是另一个小菜一碟。
。。或者4 ..。或N张匹配卡
发布于 2019-01-02 17:14:10
看看您的一些现有代码,了解您尝试过的内容将是非常有帮助的。但是如果没有它,您可以执行@Supersharp建议的操作,也可以让<memory-game>类处理所有事件。
如果您这样做,那么<memory-card>的代码将侦听整个字段中的click事件。它会检查你是否点击了一张仍然朝下的卡片,如果是的话,告诉卡翻转。(通过设置属性或属性,或通过调用<memory-card>元素上的函数。)
所有其余的逻辑都将存在于<memory-game>类中,以确定所选的两张卡是否相同并分配点数等等。
如果您想让卡片处理click事件,那么您将让代码生成一个新的CustomEvent,以指示卡片已经翻转。可能包括网格内卡片的坐标和正在翻转的卡的类型。
然后,<memory-game>类将侦听flipped事件并对该信息进行操作。
不管你怎么做,这并不是真正的问题。这只是你想要对它进行编码的方式,以及你想要的代码如何绑定在一起。如果您从未计划在任何其他游戏中使用此代码,那么这并不重要。
https://stackoverflow.com/questions/54002383
复制相似问题