首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >嵌套web组件和事件处理

嵌套web组件和事件处理
EN

Stack Overflow用户
提问于 2019-01-02 06:54:21
回答 3查看 4.7K关注 0票数 5

我在用javascript写一个记忆游戏。我已经为卡片制作了一个网络组件,<memory-card>和一个网络组件来包含卡和处理游戏状态<memory-game><memory-card>类包含翻转时的图像路径、作为卡背面显示的默认图像、其翻转状态和处理状态与图像之间切换的onclick函数。

<memory-game>类有一个设置器,它接收要生成<memory-cards>的图像数组。在<memory-game>类中处理更新游戏状态的最佳方法是什么?我应该在<memory-card>元素上附加一个额外的事件侦听器,还是有更好的方法来解决它?我希望<memory-card>元素像现在这样只处理它们自己的功能(即点击时根据状态更改图像)。

memory-game.js

代码语言:javascript
复制
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

代码语言:javascript
复制
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的应答之后实现自定义事件

内存卡(提取)

代码语言:javascript
复制
connectedCallback () {
    this.addEventListener('click', (e) => {
      this.flipCard()
      const event = new CustomEvent('flippedCard')
      this.dispatchEvent(event)
    })
  }

内存-game.js(提取)

代码语言:javascript
复制
  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)
    })
  }
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-01-02 13:07:08

<memory-card>

  • 使用CustomEvent()创建并使用dispatchEvent()分派自定义事件

<memory-game>

  • 使用addEventListener()收听您的自定义事件

因为卡是嵌套在游戏中,事件将自然气泡到容器。

这样,两个自定义元素将保持松散耦合。

票数 6
EN

Stack Overflow用户

发布于 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

代码语言:javascript
复制
[yoursender].dispatchEvent(new CustomEvent([youreventName], {
                                                  bubbles: true,
                                                  detail: [yourdata]
                                                }));

更多:https://javascript.info/dispatch-events

注意:detail可以是一个函数:How to communicate between Web Components (native UI)?

一个基于事件的编程挑战

代码语言:javascript
复制
   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子,

而且它没有对已经拥有的元素进行任何记账,

洗牌成了小菜一碟:

代码语言:javascript
复制
  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函数,从数组或数字生成随机值

代码语言:javascript
复制
  rand = x => Array.isArray(x) ? x[rand(x.length)] : 0 | x * Math.random(),

额外挑战

如果你的基于事件的编程是正确的,

然后用创建一个内存游戏--三个匹配卡--是另一个小菜一碟。

。。或者4 ..。或N张匹配卡

票数 2
EN

Stack Overflow用户

发布于 2019-01-02 17:14:10

看看您的一些现有代码,了解您尝试过的内容将是非常有帮助的。但是如果没有它,您可以执行@Supersharp建议的操作,也可以让<memory-game>类处理所有事件。

如果您这样做,那么<memory-card>的代码将侦听整个字段中的click事件。它会检查你是否点击了一张仍然朝下的卡片,如果是的话,告诉卡翻转。(通过设置属性或属性,或通过调用<memory-card>元素上的函数。)

所有其余的逻辑都将存在于<memory-game>类中,以确定所选的两张卡是否相同并分配点数等等。

如果您想让卡片处理click事件,那么您将让代码生成一个新的CustomEvent,以指示卡片已经翻转。可能包括网格内卡片的坐标和正在翻转的卡的类型。

然后,<memory-game>类将侦听flipped事件并对该信息进行操作。

不管你怎么做,这并不是真正的问题。这只是你想要对它进行编码的方式,以及你想要的代码如何绑定在一起。如果您从未计划在任何其他游戏中使用此代码,那么这并不重要。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54002383

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档