• vue + element UI【实战】打字闯关(含按键监听、按键音效、字符匹配、动态样式、结果判定、数据统计、音效获取和剪辑等实用技巧)


    效果预览

    点我在线预览
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    实现思路

    • 将目标字符串按字符转换为数组,遍历展示
          this.stringLib[this.step].split("").forEach((item) => {
            this.targetList.push({
              text: item,
            });
          });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 监听键盘事件
    created() {
      this.keyDown();
    },
    
    • 1
    • 2
    • 3
    // 按下按键
    keyDown() {
       // function内的this不再是vue实例,需提前将 this 存入 that以便在 function内使用
       let that = this;
       document.onkeydown = function (e) {
           console.log(e.key) // 按下键盘上的 A 时会打印 a
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 根据按键值判断输入是否正确,若正确则添加属性 type 为 success ,字符变绿 ;输入错误则添加属性 type 为 danger,字符变红 (type 值来自 el-tag 对应的效果)
    // 用下标 index 跟踪标记输入进度
    let targetText = that.targetList[that.index].text;
    if (e.key === targetText) {
      // 使用 $set 页面才能及时响应对象的变化
      that.$set(that.targetList[that.index], "type", "success");
    } else {
      that.$set(that.targetList[that.index], "type", "danger");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 当前关的字符输入完后,按任意键都会判定通关结果,输入全部正确才能通关
    // 输入的正确字符数与目标字符数相等时,通过当前关
    if (that.rightCharNum === that.targetList.length) {
      // 若已是最后一关,则全部通关,闯关结束
      if (that.step === that.totalStep) {
        that.over();
      } else {
        that.result = "success";
        // 通过当前关时播放通关成功的音效
        that.$refs.successAudio.play();
      }
    } else {
      that.result = "fail";
      // 存在错误字符时播放通关失败的音效
      that.$refs.failAudio.play();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 判定结果后,按回车键/空格键,若通关则开始下一关,若失败则重新挑战
    if (that.result) {
      if (e.key === "Enter" || e.key === " ") {
        if (that.result === "success") {
          that.nextStep();
        }
        if (that.result === "fail") {
          that.replay();
        }
      }
      return;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 为提升用户体验,每一次输入都会配音效,并统计输入正确和错误的次数
     if (e.key === targetText) {
       that.$set(that.targetList[that.index], "type", "success");
       // 为避免输入过快时声音反应不及时,在每次输入时让音频从头开始播放
       that.$refs.inputAudio.currentTime = 0;
       that.$refs.inputAudio.play();
       that.rightNum++;
     } else {
       that.$set(that.targetList[that.index], "type", "danger");
       that.$refs.errorAudio.currentTime = 0;
       that.$refs.errorAudio.play();
       that.wrongNum++;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    重要提示

    完整范例代码

    <template>
      <div class="mainBox">
        <h1 class="center">【 打字闯关 】第 {{ step }} 关h1>
        <el-row type="flex" class="pageBanner" justify="center">
          <el-pagination
            :pager-count="20"
            :total="totalStep"
            :page-size="1"
            @current-change="currentPageChange"
            :current-page="step"
            layout="prev, pager, next"
          >
          el-pagination>
        el-row>
        <el-row type="flex" justify="center">
          <el-tag
            :key="index"
            v-for="(item, index) in targetList"
            :type="item.type"
          >
            {{ item.text }}
          el-tag>
        el-row>
    
        <el-row :gutter="10" type="flex" justify="center">
          <el-col class="center" :span="2"> 正确:{{ rightNum }} 次 el-col>
          <el-col class="center" :span="2"> 错误:{{ wrongNum }} 次el-col>
          <el-col class="center" :span="4" v-if="result">
            正确字符:{{ rightCharNum }} 个el-col
          >
          <el-col class="center" :span="4" v-if="result">
            错误字符:{{ wrongCharNum }} 个el-col
          >
        el-row>
    
        <el-result
          v-if="result === 'success'"
          icon="success"
          title="恭喜通关"
          subTitle="你真棒!"
        >
          <template slot="extra">
            <el-button type="primary" size="medium" @click="nextStep"
              >下一关el-button
            >
          template>
        el-result>
    
        <el-result
          v-if="result === 'over'"
          icon="success"
          title="恭喜您,已全部通关"
          subTitle="这大腿,俺抱定了!"
        >
        el-result>
    
        <el-result
          v-if="result === 'fail'"
          icon="error"
          title="挑战失败"
          subTitle="失败是成功的妈妈,再试一次吧!"
        >
          <template slot="extra">
            <el-button type="primary" size="medium" @click="replay"
              >重新挑战el-button
            >
          template>
        el-result>
    
        <audio ref="overAudio" controls="controls" hidden>
          <source src="./audios/全部通关.wav" type="audio/mpeg" />
        audio>
    
        <audio ref="successAudio" controls="controls" hidden>
          <source src="./audios/通关.wav" type="audio/mpeg" />
        audio>
    
        <audio ref="failAudio" controls="controls" hidden>
          <source src="./audios/一片嘘声.wav" type="audio/mpeg" />
        audio>
    
        <audio ref="inputAudio" controls="controls" hidden>
          <source src="./audios/键盘输入音.mp3" type="audio/mpeg" />
        audio>
    
        <audio ref="errorAudio" controls="controls" hidden>
          <source src="./audios/错误提示音.wav" type="audio/mpeg" />
        audio>
      div>
    template>
    <script>
    export default {
      data() {
        return {
          index: 0,
          targetList: [],
          rightNum: 0,
          wrongNum: 0,
          result: null,
          wrongCharNum: 0,
          rightCharNum: 0,
          stringLib: {
            1: "aaaa ssss dddd ffff",
            2: "jjjj kkkk llll ;;;;",
            3: "qqqq wwww eeee rrrr",
            4: "uuuu iiii oooo pppp",
            5: "zzzz xxxx cccc vvvv",
            6: "mmmm ,,,, .... ",
            7: "tttt yyyy gggg hhhh",
            8: "bbbb nnnn 1111 2222",
            9: "3333 4444 5555 6666",
            10: "7777 8888 9999 0000",
          },
          // 关卡数
          step: 1,
          // 总关卡数
          totalStep: 10,
        };
      },
      created() {
        this.keyDown();
      },
      mounted() {
        this.init();
      },
      methods: {
        currentPageChange(newPage) {
          this.step = newPage;
          this.init();
        },
        // 重玩
        replay() {
          this.init();
        },
        // 下一关
        nextStep() {
          if (!this.stringLib[this.step + 1]) {
            this.over();
            return;
          }
          this.step++;
          this.init();
        },
        // 初始化
        init() {
          this.result = null;
          this.rightNum = 0;
          this.wrongNum = 0;
          this.rightCharNum = 0;
          this.wrongCharNum = 0;
          this.index = 0;
          this.targetList = [];
    
          this.stringLib[this.step].split("").forEach((item) => {
            this.targetList.push({
              text: item,
            });
          });
        },
        // 全部通关
        over() {
          this.result = "over";
          this.$refs.overAudio.play();
        },
        // 按下按键
        keyDown() {
          let that = this;
          document.onkeydown = function (e) {
            if (that.result) {
              if (e.key === "Enter" || e.key === " ") {
                if (that.result === "success") {
                  that.nextStep();
                }
                if (that.result === "fail") {
                  that.replay();
                }
              }
              return;
            }
    
            if (that.index > that.targetList.length - 1) {
              that.targetList.forEach((item) => {
                if (item.type === "success") {
                  that.rightCharNum++;
                } else {
                  that.wrongCharNum++;
                }
              });
              // 输入的正确字符数与目标字符数相等时,通过当前关
              if (that.rightCharNum === that.targetList.length) {
                // 若已是最后一关,则全部通关,闯关结束
                if (that.step === that.totalStep) {
                  that.over();
                } else {
                  that.result = "success";
                  // 通过当前关时播放通关成功的音效
                  that.$refs.successAudio.play();
                }
              } else {
                that.result = "fail";
                // 存在错误字符时播放通关失败的音效
                that.$refs.failAudio.play();
              }
              return;
            }
    
            if (e.key === "Backspace") {
              if (that.index > 0) {
                that.index--;
                that.$set(that.targetList[that.index], "type", "");
              }
    
              return;
            }
    
            let targetText = that.targetList[that.index].text;
            if (e.key === targetText) {
              that.$set(that.targetList[that.index], "type", "success");
              // 为避免输入过快时声音反应不及时,在每次输入时让音频从头开始播放
              that.$refs.inputAudio.currentTime = 0;
              that.$refs.inputAudio.play();
              that.rightNum++;
            } else {
              that.$set(that.targetList[that.index], "type", "danger");
              that.$refs.errorAudio.currentTime = 0;
              that.$refs.errorAudio.play();
              that.wrongNum++;
            }
    
            that.index++;
          };
        },
      },
    };
    script>
    <style  scoped>
    .center {
      text-align: center;
    }
    .mainBox {
      padding: 30px;
    }
    .el-tag {
      margin: 10px;
      height: 100px;
      width: 100px;
      font-size: 60px;
      line-height: 100px;
      border-radius: 10%;
      text-align: center;
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
  • 相关阅读:
    Hadoop如何启动HttpFS服务?
    linux应用移植问题
    C++Builder6.0 启动参数设置,不打开默认工程,不显示启动画面
    fastadmin分类下拉(多级分类)使用教程
    FFmpeg入门详解之124:Qt5 FFmpeg单路网络摄像头采集预览
    大模型微调方法
    CSS day_13(6.28) Boot常用组件(nav、tab、分页)Sass介绍
    英伟达发布526.98 WHQL 显卡驱动,支持RTX 4080,三款即将上线游戏
    Springboot服装服装销售管理系统毕业设计-附源码221801
    MATLAB--二维图像和三维图像的绘制
  • 原文地址:https://blog.csdn.net/weixin_41192489/article/details/126016319