Vue.js简单案例教程

这里以Vue.js创建一个简单的小回答测验项目quiz为案例,一步步从无到有展示Vue的使用。

安装
创建HTML主要骨架,并导入Vue:


<html>
<body>

<!-- Vue在这个div中起作用工作 -->
<div id="app">
<!-- Vue的data.title 显示在这儿-->
<h1>{{ title }}</h1>
</div>

<!-- Load Vue script -->
< script src =
" https://vuejs.org/js/vue.js " >< /script >
<!-- On load, init Vue -->
window.function(){
new Vue({
el: 'app',
// Vue 工作在这个div
data: { title: 'Hello.' },
// title设置为 'Hello.'
});
}

</body>

将其保存为foo.html,在浏览器打开,会看到Hello,这里我们学习了{{title}}语法渲染数据。

Data数据
创建一个简单的quiz回答项目,带有一个标题和两个问题,每个问题有一个或多个答案,其中有多个可能答案正确。我们将其连接Vue的实例数据。



window.function(){

var quiz = {
title: 'My quiz',
questions: [
{
text: "问题 1",
responses: [
{text: '错误, too bad.'},
{text: '正确!', correct: true},
]
}, {
text:
"问题 2",
responses: [
{text: '正确答案', correct: true},
{text: '回答错误'},
]
}
]
};

new Vue({
el: 'app',
data: { quiz: quiz },
// 连接quiz 到 Vue data
});
}

设置好基本回答问题后,下一步如何使用Vue loops循环输出。

在Html渲染数据
Vue提供指令驱动循环系统将数据加入HTML:v-for=”item on items”:


<div id="app">
<!-- Quiz title -->
<h1>{{ quiz.title }}</h1>
<!-- questions: 为questions中每个question用div显示输出 -->
<div v-for=
"question in quiz.questions">
<h2>{{ question.text }}</h2>
<!-- Responses: display a li for each possible response with a radio button -->
<ol>
<li v-for=
"response in question.responses">
<label>
<input type=
"radio"> {{response.text}}
</label>
</li>
</ol>
</div>
</div>

这里有一个不显眼的响应式reactive系统,如果数据对象改变,HTML试图会更新,现在quiz这个项目的所有问题都已经显示,它是活动的及时更新的,是积极响应的。

导航
现在这个项目中所有问题显示在一个页面上,那我们改一下,每个页面显示一个问题,需要在每个问题页面上增加next(上一页)和previous(下一页)。隐藏所有不不是当前问题的其他问题。

我们创建的app能够处理用户输入:按钮点按,首先,增加当前问题索引数据和两个导航方法到Vue实例:


new Vue({
el: 'app',
data: {
quiz: quiz,
// 存储当前问题索引Store current question index
questionIndex: 0,
},
// 当点按按钮时,视图会触发这些方法
methods: {
// Go to next question 到下一个问题
next: function() {
this.questionIndex++;
},
// Go to previous question到上个问题
prev: function() {
this.questionIndex--;
}
}
});

questionIndex 会在next()增加,而在prev()调用是减少。

下面创建Html导航按钮触发上面两个方法,使用v-on:click=”next”指令触发next();使用v-show=”index === questionIndex”显示当前问题,不要忘记将index索引加入v-for中。


<div id="app">
<h1>{{ quiz.title }}</h1>
<!-- index is used to check with current question index -->
<div v-for=
"(question, index) in quiz.questions">
<!-- 隐藏不是当前问题的其他问题,只显示索引对应的问题 -->
<div v-show=
"index === questionIndex">
<h2>{{ question.text }}</h2>
<ol>
<li v-for=
"response in question.responses">
<label>
<input type=
"radio"> {{response.text}}
</label>
</li>
</ol>
<!-- 两个导航按钮 -->
<!-- Note: prev is hidden on first question -->
<button v-if=
"questionIndex > 0" v-on:click="prev">
prev
</button>
<button v-on:click=
"next">
next
</button>
</div>
</div>
</div>

现在我们可以进入这个问答项目。最后一页是空白的,我们应该显示测验结果在它。

Quiz结果
要显示一个评分结果,我们必须处理每个问题的用户响应。这是最难的一步。

目前radio 按钮没有绑定Vue,点按radio 没有效果,v-model实现表单输入和应用状态两者双向绑定,使用下面radio 替代之前的:


<!-- for each response of the current question -->
<li v-for="response in question.responses">
<label>
<!-- The radio button has three new directives -->
<!-- v-bind:如果回答正确设置
"value""true"-->
<!-- v-bind:n设置
"name" 到问题索引,指向问题一组答案中一个-->
<!-- v-model 和userResponses 绑定-->
<input type=
"radio"
v-bind:value=
"response.correct"
v-bind:name=
"index"
v-model=
"userResponses[index]"> {{response.text}}
</label>
</li>

name和value被绑定到Vue数据,然后在Vue实例初始化userResponses :

new Vue({
el: 'app',
data: {
quiz: quiz,
questionIndex: 0,
// 数组为每个问题初始值为 "false"
// 意思是: "用户正确回答这个问题吗?" "no".
userResponses: Array(quiz.questions.length).fill(false)
},
methods: {
// ...
}
});

这是为了处理用户响应的最后一步:userResponses包含一个数组,你可以向前和向后导航,选择和更改答案,会发现userresponses“自己更新”。

创建方法进行分数计算:


new Vue({
// ...
methods: {
// ...
// 返回 在userResponses中"true" 数量
score: function() {
return this.userResponses.filter(function(val) { return val }).length;
}
}
});

增加下面最后一页显示总分:


<div id="app">
<h1>{{ quiz.title }}</h1>
<div v-for=
"(question, index) in quiz.questions">
<!--
//... -->
</div>
<!-- Last page, quiz is finished, display result -->
<div v-show=
"questionIndex === quiz.questions.length">
<h2>
Quiz finished
</h2>
<p>
Total score: {{ score() }} / {{ quiz.questions.length }}
</p>
</div>
</div>

最后项目完成,可在这里演示。源码这里

原文:
Create a quiz with Vue.js – Medium

[该贴被banq于2016-11-03 11:09修改过]