这是一个打字游戏。
规则如下
1、当输入第一个字母的时候,开始计时,当完全输入正确,计时停止。并且不能继续输入。
2、输入字母正确时显示为绿色,错误的显示为红色。
3、输入正确后,点击刷新按钮,可以换题目。
截图如下
你可以学习到以下知识点
1、组件的全局使用。
2、模版的使用。
3、props。从父组件传递参数到子组件。
4、自定义事件。子组件通过emit与父组件进行通讯。
代码如下:
<!DOCTYPE html>
<html>
<head>
<title>打字游戏</title>
<script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script>
<style type="text/css">
.main {
border: 1px solid #ccc;
padding: 15px;
font-size: 20px;
}
.green {
color: green;
}
.red {
color: red;
}
</style>
</head>
<body>
<div id="app" class="main">
<h1>{{ title }}</h1>
<hr>
<typing-game :time-status="currentStatus" @toggle-time-status="toggleStatus" ></typing-game>
<time-record :time-status="currentStatus" ></time-record>
</div>
<div>
还可以优化的地方:
1、计数器刷新清零。实现单独计时。(完成)
2、统计多次计时,算出总数。
3、不要使用focus触发计时器,使用watch触发。(完成)
</div>
<!--模版区域-->
<script type="text/x-template" id="typing-game-template">
<div>
<div>题目
<button @click="refresh" :disabled="buttonDisabled">刷新</button>
<!--
{{ timeStatus }}
<button @click="toggleTime">切换</button>
-->
</div>
<div>{{ question }}</div>
<div><input type="text" v-model="input" :disabled="textDisabled" > <!--@focus="toggleTime"--> </div>
<div v-html="answer"></div>
</div>
</script>
<script type="text/x-template" id="time-record-template">
<div>
{{ time.toFixed(2) }}
</div>
</script>
<!--模版区域-->
<script type="text/javascript">
let timeCounter; //计数器变量
Vue.component('typing-game', {
template: '#typing-game-template',
props: ['timeStatus'],
data () {
return {
question: getRandomString() ,
input: '',
textDisabled: false,
buttonDisabled: false,
isTyping: true //是否正在输入
}
},
computed: {
answer () {
let questionLen = this.question.length;
let questionAry = [];
let input = this.input;
let inputLen = input.length;
let inputAry = [];
let output = '';
let count = 0;
for (let i = 0; i < questionLen; i ++) {
questionAry.push(this.question[i])
}
for (let i = 0; i < inputLen; i ++) {
inputAry.push(input[i])
}
inputAry = inputAry.map((value, index) => {
if (value === questionAry[index]) {
value = '<span class="green">' + value + '</span>';
count ++;
} else {
value = '<span class="red">' + value + '</span>';
}
return value;
})
if (questionLen === count && questionLen === inputLen ) {
output = inputAry.join('') + ' 完全正确';
this.textDisabled = true;
this.toggleTime();
} else {
output = inputAry.join('');
}
return output;
}
},
methods: {
refresh () {
this.question = getRandomString();
this.input = '';
this.textDisabled = false;
},
toggleTime () {
this.buttonDisabled = !this.buttonDisabled;
this.isTyping = !this.isTyping;
this.$emit('toggle-time-status');
}
},
watch: {
input: function (newValue, oldValue) {
if (this.isTyping) {
this.toggleTime();
}
}
}
})
Vue.component('time-record', {
template: '#time-record-template',
//props: ['timeStatus', 'currentTime'],
props: {
timeStatus: String,
currentTime: Number
},
data () {
return {
time: 0.00,
}
},
watch: {
timeStatus (newValue, oldValue) {
console.log(111111);
if (newValue === 'start') {
this.time = 0.00;
timeCounter = setInterval(() => {
this.time += 0.01
//this.time = this.time.toFixed(2);
}, 10);
} else {
clearInterval(timeCounter)
}
}
}
})
var app = new Vue({
el: '#app',
data: {
title: 'Typing Game',
currentStatus: 'end'
},
methods: {
toggleStatus () {
this.currentStatus = this.currentStatus === 'start' ? 'end' : 'start';
}
}
})
function getRandomString() {
let chars = 'abcdefghijklmnopqsrtuvwxyz';
const max = 20; //less than 20
let randomString = '';
let randomNumber = Math.floor(Math.random() * max);
randomNumber = randomNumber === 0 ? max : randomNumber;
for (let i = 0; i < randomNumber; i ++) {
randomString += chars.charAt(Math.floor(Math.random() * 26));
}
return randomString;
}
</script>
</body>
</html>