输入和键盘

现在开始变得有点棘手,在我们开始之前,检查您是否熟悉该 Array.map() 函数可能是个好主意。与三元运算符一样,它们将成为您在这一步和下一篇文章中最好的朋友,因为 Numble 需要大量的数组映射来处理状态中的数据。

如果您的 Array.map() 技能有点生疏,或者您甚至没有听说过,请不要担心,它们很容易理解,您可以在此处阅读更多关于它们的信息。

此步骤包含三个主要部分:

创建虚拟键盘 显示用户的猜测 检查用户的猜测是否正确 尽管它们都相互依赖,但如果将所有内容分解成更小的块,则更容易理解。

首先,我们需要在 中添加我们将要使用的函数和另外三个属性 State:

const State = {
  started: false,
  digits: Array(10).fill("grey"),
  guess: Array(3).fill(null),
  count: 0,
  start, finish, remove, check, appear,
  View
}

按照这个顺序处理它们, digits 现在的值是一个长度为 10 的数组,每个空格都用字符串“grey”填充。这是因为我们将使用它来跟踪游戏中每个数字应该是什么颜色,并且数组的索引将代表从 0 到 9 的每个可能的数字。

的初始值 guess 也是一个长度为 3 的数组,每个空格填充 null.

最后, count 设置为 0,这将用于记录玩家猜到了多少位数。

我们将映射 digits 数组以创建我们的屏幕键盘,所以我们需要添加一些东西到 View. 虽然在我们这样做之前,我们需要摆脱

显示 的 number,否则只会破坏游戏的全部意义。

const View = state => html`
<h1>Numble</h1>
${state.started ?
 html`<div id="guesses">
${state.guess.map(number => html`<div>${number}</div>`)}
</div>
<div id="keyboard">
 ${state.digits.map((digit,index) => html`<button onclick=${appear(index)}>${index}</button>`)}
 <button onclick=${remove}>DELETE</button>
 <button onclick=${check}>ENTER</button>
</div>
<button onclick=${finish}>END</button>`
:
 html`<button onclick=${start}>START</button>`
}`

代替

显示的 number,我们现在有两个
s 一个和一个 id of “guesses” ,一个和一个 id of “keyboard”。

在“猜测”

中,我们有许多 .map() 函数中的第一个,它映射到长度为 3 的数组上,为
数组中的每个项目创建一个单独的项目,显示项目。这意味着在开始时,当数组中所有项的值为 时 null,将显示三个空格。

这是一个应该是什么样子的示例(使用我的 CSS):

最终,当数组中每一项的值发生变化时,显示的内容也会随之变化以匹配。

在“键盘”中,

我们有三件事:

${state.digits.map((digit,index) => html`<button onclick=${state.appear(index)}>${index}</button>`)}

这映射到长度为 10 的数组,为每个项目创建一个按钮并显示每个项目的按钮 index 。换句话说,数字 0 到 9。每个按钮还有一个内联事件侦听器,它调用事件处理程序 appear 并 index 作为参数提供。但是,我们稍后将对此进行全面探讨。

然后,我们有两个按钮,一个称为“删除”,另一个称为“输入”。它们都有内联事件侦听器,它们调用各自的事件处理程序 remove 和 check. 再一次,我们将在稍后充分探索这些。

首先,这是您的键盘外观的示例:

查看 appear 事件处理程序,我们希望此函数显示玩家在 guess.

const appear = guess => event => {
  Update(state => ({
    guess: state.guess.map((digit,index) => index === state.count ? guess : digit),
    count: state.count + 1
  }))
}

首先,这个事件处理程序和我们之前做的唯一区别是这个函数有一个额外的参数 guess。这是 作为参数提供index 的 数组的 。digits换句话说,它是玩家点击的数字。

该 Update 功能看起来有点不同。这是因为它需要访问状态,所以它提供了一个箭头函数,将旧状态映射到新状态(Nanny State 将这些称为“转换函数”)

就它实际更新的内容而言,该 属性映射在三个s guess 的原始数组上 ,如果 项目的 等于 (猜测的位置),则将值 替换 为用户单击的按钮)。如果 不等于 ,则项目的值保持原样: 。nullindexcountnullguessindexcountnull

然后它增加 count 1,允许用户将他们的第二个猜测输入到第二个空格中。

这是用户单击几个数字后该行的外观:

事件 remove 处理程序(具有讽刺意味)几乎相同:

const remove = event => {
  Update(state => ({
    guess: state.guess.map((digit,index) => index === state.count - 1 ? null : digit),
    count: state.count - 1
  }))
}

按照 appear 函数的逻辑,您应该能够弄清楚这里发生了什么,但如果没有,请不要担心。它 guess 通过映射原始数组进行更新,如果 index 等于之前的猜测次数(即计数 - 1),它会将项目的值替换为 null,从而有效地删除猜测。

而这一次,它减 count 一,让用户继续猜测。

只是 check 要执行的功能。

‘Enter’ 按钮的事件处理程序被调用 check,我们希望它(惊喜)检查用户的猜测是否正确,但我们也希望它重置猜测,以便用户可以重试。

该函数如下所示:

const check = event => {
  Update(state => {
    const numble = state.guess.join("") === state.number
    return {
      feedback: numble ? "NUMBLE!" : "Wrong!",
      guess: Array(3).fill(null),
      count: 0
    }
  })
}

和以前一样,它 Update 使用了一个转换器函数并 state 作为一个参数,让我们可以直接访问状态中保存的所有应用程序数据。然后它会创建一个名为 的布尔常量 numble。它可能看起来不像,但 state.guess.join("") === state.number 实际上是一个条件(检查用户的猜测是否等于我们生成的数字),如果满足此条件,则值为 , numble 否则 true 为 false。

然后它返回状态的三个更新属性:

  • feedback 获取我们刚刚创建的布尔值,如果是 true ,则将值设置为字符串“NUMBLE!” 如果是 false ,则将值设置为字符串“错误!”
  • guess 改回长度为 3 的数组,其中填充 null. 这将有效地重置用户的猜测,让他们再次猜测
  • count 也重置为 0,这意味着程序可以像从头开始一样工作。

我们的最后一步是放入一些 HTML View 以便显示反馈。

放置它的好地方是猜测下方和键盘上方。所以,你的决赛 View 应该是这样的:

const View = state => html`
<h1>Numble</h1>
${state.started ?
 html`<div id="guesses">
${state.guess.map(number => html`<div>${number}</div>`)}
</div>
<p id="feedback">${state.feedback}</p>
<div id="keyboard">
${state.digits.map((digit,index) => html`<button onclick=${state.appear(index)}>${index}</button>`)}
  <button onclick=${state.remove}>DELETE</button>
  <button onclick=${state.check}>ENTER</button>
</div>
 <button onclick=${state.finish}>END</button>`
:
 html`<button onclick=${state.start}>START</button>`
}`

如果您愿意,您可以 feedback 在游戏开始时设置消息,例如在 start 事件处理程序中,您可以添加 feedback 带有字符串值的属性(“猜 3 位数字”):

const start = event => {
  Update({
    started: true,
    number: generateNumber(),
    feedback: "Guess 3 digits"
  })
}

就是这样!你现在有一个功能齐全的猜数字游戏!

在继续阅读第二篇文章之前,这里只有一些关于 CSS 和 bug 的注释。

如果您是一名优秀的程序员,您可能会发现这里的一些错误,例如,如果用户在猜到三位数字之前点击“Enter”怎么办?如果你开始玩它,你肯定会注意到更多。

它们根本不难修复,您只需要在适当的情况下满足几个条件。例如,要解决在三位数之前检查的问题,可以在 check 函数中编写:

const check = event => {
  Update(state => {
    const numble = state.guess.join("") === state.number
    return state.count < 3 ? {
      feedback: "too short"
    }
    :
    {
      feedback: numble ? "NUMBLE!" : "Wrong!",
      guess: Array(3).fill(null),
      count: 0
    } 
  })
}

这只是检查猜测的数量是否小于 3,并相应地返回具有不同值的不同属性。

我们现在有一个功能齐全的“猜数字”游戏,接下来我们将使它更像完整的 Numble。