Vue 实现答题功能的完整攻略包含以下步骤:
步骤一:设计数据结构
在 Vue 实现答题功能之前,我们首先需要设计数据结构。数据结构应该包含题目、选项、答案等信息。例如,以下是一个选择题的数据结构:
const questions = [
{
question: '以下哪个不是JavaScript的数据类型?',
options: ['Undefined', 'Boolean', 'Null', 'Number'],
answer: 3,
},
{
question: '以下哪个不是CSS的布局方式?',
options: ['Flexbox', 'Elastic', 'Inline-block', 'Grid'],
answer: 1,
},
// ...
];
步骤二:创建组件
在 Vue 实现答题功能中,我们需要创建两个组件,一个是题目组件,另一个是选项组件。题目组件负责显示题目和用户选择的答案,选项组件负责显示选项和记录用户选择的选项。
1. 题目组件
题目组件负责显示题目和用户选择的答案。代码示例如下:
<template>
<div>
<h2>{{ question }}</h2>
<p v-if="selectedOption !== null">
你的选择是:{{ options[selectedOption] }}
</p>
<ul>
<li v-for="(option, index) in options" :key="index">
<input
type="radio"
:id="'option-' + index"
:value="index"
v-model="selectedOption"
/>
<label :for="'option-' + index">{{ option }}</label>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
question: { type: String, required: true },
options: { type: Array, required: true },
answer: { type: Number, required: true },
},
data() {
return {
selectedOption: null,
};
},
watch: {
selectedOption() {
this.$emit('answer', this.selectedOption === this.answer);
},
},
};
</script>
2. 选项组件
选项组件负责显示选项和记录用户选择的选项。代码示例如下:
<template>
<li>
<input type="checkbox" :id="'option-' + index" v-model="selected" />
<label :for="'option-' + index">{{ option }}</label>
</li>
</template>
<script>
export default {
props: {
option: { type: String, required: true },
index: { type: Number, required: true },
},
data() {
return {
selected: false,
};
},
watch: {
selected() {
this.$emit('select', this.selected);
},
},
};
</script>
步骤三:组合组件
在 Vue 实现答题功能中,我们需要将题目组件和选项组件组合起来形成一个完整的题目。以下是一个使用答题组件的示例:
<template>
<div>
<h1>答题页面</h1>
<div v-for="(question, index) in questions" :key="index">
<question-component
:question="question.question"
:options="question.options"
:answer="question.answer"
@answer="updateScore"
/>
<p>正确答案是:{{ question.options[question.answer] }}</p>
</div>
<p>你的得分是:{{ score }}</p>
</div>
</template>
<script>
import QuestionComponent from './QuestionComponent.vue';
export default {
components: {
QuestionComponent,
},
data() {
return {
questions: [
{
question: '以下哪个不是JavaScript的数据类型?',
options: ['Undefined', 'Boolean', 'Null', 'Number'],
answer: 2,
},
{
question: '以下哪个不是CSS的布局方式?',
options: ['Flexbox', 'Elastic', 'Inline-block', 'Grid'],
answer: 1,
},
],
score: 0,
};
},
methods: {
updateScore(isCorrect) {
if (isCorrect) {
this.score++;
}
},
},
};
</script>
在上面的示例中,我们将题目组件和选项组件组合起来,使用 v-for 指令循环展示每个问题。同时,我们通过 updateScore 方法更新用户的得分。最后,我们还在每个题目下方显示了正确答案。
示例一:多选题
多选题需要使用多个复选框来选择答案。同样,我们可以通过修改题目组件和选项组件来实现多选题。以下是一个多选题的数据结构:
const questions = [
{
question: '以下哪些是Vue的生命周期钩子函数?',
options: [
'created',
'mounted',
'updated',
'destoryed',
'beforeCreate',
'beforeUpdate',
],
answer: [0, 1, 2, 3],
},
];
我们可以将题目组件中的单选框改为复选框,然后在选项组件中记录用户是否选择了该选项。修改后的组件可如下:
<template>
<li>
<input type="checkbox" :id="'option-' + index" v-model="selected" />
<label :for="'option-' + index">{{ option }}</label>
</li>
</template>
<script>
export default {
props: {
option: { type: String, required: true },
index: { type: Number, required: true },
},
data() {
return {
selected: false,
};
},
watch: {
selected() {
this.$emit('select', { index: this.index, selected: this.selected });
},
},
};
</script>
在选项组件中,我们通过 $emit 方法告诉父组件哪些选项被选中了。在题目组件中,我们只需要将 v-model 和 answer 属性改为一个数组即可:
<template>
<div>
<h2>{{ question }}</h2>
<p v-if="selectedOptions.length > 0">
你的选择是:
<span v-for="(option, index) in selectedOptions" :key="index">
{{ options[option] }}
<span v-if="index !== selectedOptions.length - 1">、</span>
</span>
</p>
<ul>
<li v-for="(option, index) in options" :key="index">
<input
type="checkbox"
:id="'option-' + index"
:value="index"
v-model="selectedOptions"
/>
<label :for="'option-' + index">{{ option }}</label>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
question: { type: String, required: true },
options: { type: Array, required: true },
answer: { type: Array, required: true },
},
data() {
return {
selectedOptions: [],
};
},
watch: {
selectedOptions() {
const answerSet = new Set(this.answer);
const selectedSet = new Set(this.selectedOptions);
this.$emit('answer', isEqualSet(answerSet, selectedSet));
},
},
};
function isEqualSet(set1, set2) {
if (set1.size !== set2.size) {
return false;
}
for (const item of set1) {
if (!set2.has(item)) {
return false;
}
}
return true;
}
</script>
在题目组件中,我们使用了一个 isEqualSet 函数来比较原始答案和用户选择的答案是否相等。这是因为在多选题中,数组顺序可能不同,但选项相等。因此,我们不能直接使用 === 运算符比较两个数组。
示例二:拖拽排序题
拖拽排序题需要使用拖拽操作来调整选项的顺序。在 Vue 实现拖拽排序题时,我们需要使用 HTML5 的 Drag & Drop API。以下是一个拖拽排序题的数据结构:
const questions = [
{
question: '把以下 Vue 指令按照使用频率从高到低排序:',
options: ['v-if', 'v-for', 'v-model', 'v-show', 'v-bind'],
answer: [1, 2, 0, 4, 3],
},
];
我们需要修改选项组件,使其支持拖拽排序。以下是修改后的选项组件:
<template>
<li draggable="true" :id="'option-' + index" @dragstart="onDragStart" @dragend="onDragEnd">
{{ option }}
</li>
</template>
<script>
export default {
props: {
option: { type: String, required: true },
index: { type: Number, required: true },
},
methods: {
onDragStart(event) {
event.dataTransfer.setData('text/plain', this.index);
this.$emit('dragstart', this.index);
},
onDragEnd() {
this.$emit('dragend');
},
},
};
</script>
在选项组件中,我们设置了 draggable 属性,并监听了 dragstart 和 dragend 事件。在 dragstart 事件中,我们使用 setData 方法将选项的索引存储到数据传输对象中。在 dragend 事件中,我们通知父组件拖拽操作已经结束。
接下来,我们需要修改题目组件,使其支持拖拽操作。以下是修改后的题目组件:
<template>
<div>
<h2>{{ question }}</h2>
<div class="options" @drop.prevent="onDrop" @dragover.prevent>
<li
v-for="(option, index) in options"
:key="index"
:class="{ active: isDragging && index === draggingIndex }"
:data-index="index"
@dragenter="onDragEnter"
@dragleave="onDragLeave"
>
<option-component
:option="option"
:index="index"
@dragstart="onDragStart"
@dragend="onDragEnd"
/>
</li>
</div>
</div>
</template>
<script>
import OptionComponent from './OptionComponent.vue';
export default {
components: {
OptionComponent,
},
props: {
question: { type: String, required: true },
options: { type: Array, required: true },
answer: { type: Array, required: true },
},
data() {
return {
isDragging: false,
draggingIndex: null,
overIndex: null,
};
},
methods: {
onDragStart(index) {
this.isDragging = true;
this.draggingIndex = index;
},
onDragEnd() {
this.isDragging = false;
this.draggingIndex = null;
this.overIndex = null;
},
onDragEnter(event) {
const index = parseInt(event.target.dataset.index, 10);
if (index !== this.draggingIndex) {
this.overIndex = index;
}
},
onDragLeave(event) {
const index = parseInt(event.target.dataset.index, 10);
if (index === this.overIndex) {
this.overIndex = null;
}
},
onDrop() {
const newOptions = [...this.options];
const [removed] = newOptions.splice(this.draggingIndex, 1);
newOptions.splice(this.overIndex, 0, removed);
this.$emit('answer', newOptions.map((option) => this.options.indexOf(option)));
},
},
};
</script>
在题目组件中,我们添加了一个 options 类名的 div 元素,使其可以接受拖拽操作。当选项拖拽进入该元素时,我们需要将其高亮显示。在该元素上监听了 drop、dragover 事件,分别表示拖拽操作结束、拖拽操作进行中。在 onDrop 方法中,我们使用 splice 方法重新排序选项。最后,我们通过 map 方法将索引数组转换成原始答案数组。
至此,我们已经成功实现了一个支持单选题、多选题和拖拽排序题的答题功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue实现答题功能 - Python技术站