Vue.js 单击后图像映射禁用区域
Vue.js Image Map Disable area after click
我有一个包含 3 个区域的图像。当我点击每个区域时,我希望出现一系列问题。我已经这样做了,但我想稍微改变一下。
因为我不想将它重定向到一个页面,所以我将 # 作为 href link 并根据 event.currentTarget.id 获取该区域的 ID
然后我有三个 v-if,每个组件都有一个条件。
这是 jfiddle:
https://jsfiddle.net/rau4apyg/
<div id="app">
<img id="Image-Maps-Com-image-maps-2017-03-16-100553" src="http://www.image-maps.com/m/private/0/fdfutap3klci37abfmuasc2mk7_screenshot.png" border="0" width="588" height="414" orgWidth="588" orgHeight="414" usemap="#image-maps-2017-03-16-100553" alt="" />
<map name="image-maps-2017-03-16-100553" id="ImageMapsCom-image-maps-2017-03-16-100553">
<area shape="rect" coords="586,412,588,414" alt="Image Map" style="outline:none;" title="Image Map" href="http://www.image-maps.com/index.php?aff=mapped_users_0" />
<area id="component1" alt="" title="comp1" href="#" shape="poly" coords="420,228,296,34,180,226,178,228" style="outline:none;" target="_self" v-on:click="compId($event)" />
<area id="component2" alt="" title="comp2" href="#" shape="poly" coords="92,368,176,234,292,234,294,368,298,236,290,368" style="outline:none;" target="_self" v-on:click="compId($event)" />
<area id="component3" alt="" title="comp3" href="#" shape="poly" coords="506,366,296,366,296,232,422,232" style="outline:none;" target="_self" v-on:click="compId($event)" />
</map>
<h1> Title here </h1>
<div v-if="compid === 'component1'">
component1 is clicked, questions are shown
</div>
<!-- show questions in for loop -->
<div v-if="compid === 'component2'">
2 is clicked
</div>
<div v-if="compid === 'component3'">
3 is clicked
</div>
<div v-show="questionIndex === quiz.questions.length -1">
<button v-on:click="addAnswers">
submit
</button>
<h2>
Quiz finished, plase continue with Component 2 questions.
</h2>
<button v-on:click="goToNextComponent">
Next
</button>
</div>
new Vue({
el: '#app',
data: {
quiz: {
questions: [],
answers: []
},
// Store current question index
questionIndex: 0,
total:0,
show: true,
compid: '',
flag: false
},
mounted: {
//functions here
},
computed: {
//functions here
},
// The view will trigger these methods on click
methods: {
//some functions
//return id of clicked component
compId: function(event){
this.compid = event.currentTarget.id;
console.log(event.currentTarget.id); // returns the name of the id clicked.
} ,
addAnswers: function(){
//store answers in Firebase
//vm.$forceUpdate();
flag = true; //change the flag
console.log(flag);
},
goToNextComponent: function(){
}
}
});
我想按顺序做题,也就是说:先做Component1的题,点击提交保存答案,然后显示Component2的题,回答完之后再转到Component3。
如果用户完成了组件 1,我希望他无法再次回答这些问题,以某种方式禁用它,然后转到组件 2。
当他完成下一个组件时,我也想禁用它并转到最后一个组件。
我不知道如何让它以这种方式工作。我有两个想法:
1)当我点击提交按钮时,我将一个标志更改为真。所以我知道组件 1 被单击了,我将它添加到 v-if 子句中。我尝试使用 && 运算符添加它,但没有成功。
2) 提交后有一个下一个按钮(我不确定这听起来是否合适),当它被点击时,显示组件 2 中包含的下一个问题。
P.S.My 数据库在 Firebase 上,我将所有问题都放在一个数组中。例如前 10 个问题是组件 1,接下来的 8 个是组件 2,等等。也许添加一个字段来分隔它们会更好吗?现在是这样的:
{
"questions" : [ {
"q_options" : [ "Yes", "No", "Don't know" ],
"q_text" : "Do you agree with blah blah?"
}}
也许我可以添加一个 component_option: 1
您有什么建议可以解决这些问题?
我稍微修改了你的方法。从本质上讲,您走在正确的轨道上;您只需要跟踪完成了哪些问题。然后,当有人点击特定图像地图时,检查是否已经完成,如果是,则阻止导航到它。
const quiz = new Vue({
el: '#app',
data: {
quiz: {
questions: [
{
"q_options" : [ "Yes", "No", "Don't know" ],
"q_text" : "Do you agree with blah blah?",
coords:"420,228,296,34,180,226,178,228",
shape:"poly",
completed: false,
answer: null
},
{
"q_options" : [ "Yes", "No", "Don't know" ],
"q_text" : "Question Number 2?",
coords:"92,368,176,234,292,234,294,368,298,236,290,368",
shape: "poly",
completed: false,
answer: null
},
{
"q_options" : [ "Yes", "No", "Don't know" ],
"q_text" : "Question Number 3?",
coords:"506,366,296,366,296,232,422,232",
shape:"poly",
completed: false,
answer: null
}],
answers: []
},
currentQuestion: null,
quizCompleted: false
},
methods: {
selectQuestion(question){
if (!question.completed)
this.currentQuestion = question;
else
alert("This question has already been completed!")
},
completeQuestion(){
this.currentQuestion.completed = true;
let currentIndex = this.quiz.questions.indexOf(this.currentQuestion);
if ( currentIndex === this.quiz.questions.length - 1){
this.quizCompleted = true;
this.currentQuestion = null;
this.quiz.answers = this.quiz.questions.map(q => q.answer)
} else {
this.currentQuestion = this.quiz.questions[++currentIndex];
}
}
},
mounted(){
this.currentQuestion = this.quiz.questions[0]
}
});
和模板:
<div id="app">
<img id="Image-Maps-Com-image-maps-2017-03-16-100553" src="http://www.image-maps.com/m/private/0/fdfutap3klci37abfmuasc2mk7_screenshot.png" border="0" width="588" height="414" orgWidth="588" orgHeight="414" usemap="#image-maps-2017-03-16-100553" alt="" />
<map name="image-maps-2017-03-16-100553" id="ImageMapsCom-image-maps-2017-03-16-100553">
<area v-for="question in quiz.questions"
:shape="question.shape"
:coords="question.coords"
@click="selectQuestion(question)"/>
</map>
<div v-if="currentQuestion">
<h1> {{currentQuestion.q_text}} </h1>
<template v-for="(option, index) in currentQuestion.q_options">
<input type="radio" :value="option" v-model="currentQuestion.answer">
<label>{{option}}</label>
<br />
</template>
<button @click="completeQuestion">Complete</button>
</div>
<div v-if="quizCompleted">
<h1>You're Done!</h1>
{{quiz.answers}}
</div>
</div>
这是一个有效的 example。
一些关键点。
- 您的地图区域似乎与问题直接相关,所以我只是将它们设为数据。然后你可以迭代它们来制作你的图像映射。当您想为不同的测验重用 Vue 时,这将使它变得更容易。
- 您真的不想显示和隐藏您调用的内容 "components"。只需构建一个代表当前问题的问题并更改其数据即可。一般在Vue中,你想通过数据来驱动你的界面。
这还没有完善,但它实现了你的主要目标;使用地图进行导航,并防止导航到已完成的问题。
我有一个包含 3 个区域的图像。当我点击每个区域时,我希望出现一系列问题。我已经这样做了,但我想稍微改变一下。 因为我不想将它重定向到一个页面,所以我将 # 作为 href link 并根据 event.currentTarget.id 获取该区域的 ID 然后我有三个 v-if,每个组件都有一个条件。
这是 jfiddle: https://jsfiddle.net/rau4apyg/
<div id="app">
<img id="Image-Maps-Com-image-maps-2017-03-16-100553" src="http://www.image-maps.com/m/private/0/fdfutap3klci37abfmuasc2mk7_screenshot.png" border="0" width="588" height="414" orgWidth="588" orgHeight="414" usemap="#image-maps-2017-03-16-100553" alt="" />
<map name="image-maps-2017-03-16-100553" id="ImageMapsCom-image-maps-2017-03-16-100553">
<area shape="rect" coords="586,412,588,414" alt="Image Map" style="outline:none;" title="Image Map" href="http://www.image-maps.com/index.php?aff=mapped_users_0" />
<area id="component1" alt="" title="comp1" href="#" shape="poly" coords="420,228,296,34,180,226,178,228" style="outline:none;" target="_self" v-on:click="compId($event)" />
<area id="component2" alt="" title="comp2" href="#" shape="poly" coords="92,368,176,234,292,234,294,368,298,236,290,368" style="outline:none;" target="_self" v-on:click="compId($event)" />
<area id="component3" alt="" title="comp3" href="#" shape="poly" coords="506,366,296,366,296,232,422,232" style="outline:none;" target="_self" v-on:click="compId($event)" />
</map>
<h1> Title here </h1>
<div v-if="compid === 'component1'">
component1 is clicked, questions are shown
</div>
<!-- show questions in for loop -->
<div v-if="compid === 'component2'">
2 is clicked
</div>
<div v-if="compid === 'component3'">
3 is clicked
</div>
<div v-show="questionIndex === quiz.questions.length -1">
<button v-on:click="addAnswers">
submit
</button>
<h2>
Quiz finished, plase continue with Component 2 questions.
</h2>
<button v-on:click="goToNextComponent">
Next
</button>
</div>
new Vue({
el: '#app',
data: {
quiz: {
questions: [],
answers: []
},
// Store current question index
questionIndex: 0,
total:0,
show: true,
compid: '',
flag: false
},
mounted: {
//functions here
},
computed: {
//functions here
},
// The view will trigger these methods on click
methods: {
//some functions
//return id of clicked component
compId: function(event){
this.compid = event.currentTarget.id;
console.log(event.currentTarget.id); // returns the name of the id clicked.
} ,
addAnswers: function(){
//store answers in Firebase
//vm.$forceUpdate();
flag = true; //change the flag
console.log(flag);
},
goToNextComponent: function(){
}
}
});
我想按顺序做题,也就是说:先做Component1的题,点击提交保存答案,然后显示Component2的题,回答完之后再转到Component3。
如果用户完成了组件 1,我希望他无法再次回答这些问题,以某种方式禁用它,然后转到组件 2。 当他完成下一个组件时,我也想禁用它并转到最后一个组件。
我不知道如何让它以这种方式工作。我有两个想法: 1)当我点击提交按钮时,我将一个标志更改为真。所以我知道组件 1 被单击了,我将它添加到 v-if 子句中。我尝试使用 && 运算符添加它,但没有成功。 2) 提交后有一个下一个按钮(我不确定这听起来是否合适),当它被点击时,显示组件 2 中包含的下一个问题。
P.S.My 数据库在 Firebase 上,我将所有问题都放在一个数组中。例如前 10 个问题是组件 1,接下来的 8 个是组件 2,等等。也许添加一个字段来分隔它们会更好吗?现在是这样的:
{
"questions" : [ {
"q_options" : [ "Yes", "No", "Don't know" ],
"q_text" : "Do you agree with blah blah?"
}}
也许我可以添加一个 component_option: 1 您有什么建议可以解决这些问题?
我稍微修改了你的方法。从本质上讲,您走在正确的轨道上;您只需要跟踪完成了哪些问题。然后,当有人点击特定图像地图时,检查是否已经完成,如果是,则阻止导航到它。
const quiz = new Vue({
el: '#app',
data: {
quiz: {
questions: [
{
"q_options" : [ "Yes", "No", "Don't know" ],
"q_text" : "Do you agree with blah blah?",
coords:"420,228,296,34,180,226,178,228",
shape:"poly",
completed: false,
answer: null
},
{
"q_options" : [ "Yes", "No", "Don't know" ],
"q_text" : "Question Number 2?",
coords:"92,368,176,234,292,234,294,368,298,236,290,368",
shape: "poly",
completed: false,
answer: null
},
{
"q_options" : [ "Yes", "No", "Don't know" ],
"q_text" : "Question Number 3?",
coords:"506,366,296,366,296,232,422,232",
shape:"poly",
completed: false,
answer: null
}],
answers: []
},
currentQuestion: null,
quizCompleted: false
},
methods: {
selectQuestion(question){
if (!question.completed)
this.currentQuestion = question;
else
alert("This question has already been completed!")
},
completeQuestion(){
this.currentQuestion.completed = true;
let currentIndex = this.quiz.questions.indexOf(this.currentQuestion);
if ( currentIndex === this.quiz.questions.length - 1){
this.quizCompleted = true;
this.currentQuestion = null;
this.quiz.answers = this.quiz.questions.map(q => q.answer)
} else {
this.currentQuestion = this.quiz.questions[++currentIndex];
}
}
},
mounted(){
this.currentQuestion = this.quiz.questions[0]
}
});
和模板:
<div id="app">
<img id="Image-Maps-Com-image-maps-2017-03-16-100553" src="http://www.image-maps.com/m/private/0/fdfutap3klci37abfmuasc2mk7_screenshot.png" border="0" width="588" height="414" orgWidth="588" orgHeight="414" usemap="#image-maps-2017-03-16-100553" alt="" />
<map name="image-maps-2017-03-16-100553" id="ImageMapsCom-image-maps-2017-03-16-100553">
<area v-for="question in quiz.questions"
:shape="question.shape"
:coords="question.coords"
@click="selectQuestion(question)"/>
</map>
<div v-if="currentQuestion">
<h1> {{currentQuestion.q_text}} </h1>
<template v-for="(option, index) in currentQuestion.q_options">
<input type="radio" :value="option" v-model="currentQuestion.answer">
<label>{{option}}</label>
<br />
</template>
<button @click="completeQuestion">Complete</button>
</div>
<div v-if="quizCompleted">
<h1>You're Done!</h1>
{{quiz.answers}}
</div>
</div>
这是一个有效的 example。
一些关键点。
- 您的地图区域似乎与问题直接相关,所以我只是将它们设为数据。然后你可以迭代它们来制作你的图像映射。当您想为不同的测验重用 Vue 时,这将使它变得更容易。
- 您真的不想显示和隐藏您调用的内容 "components"。只需构建一个代表当前问题的问题并更改其数据即可。一般在Vue中,你想通过数据来驱动你的界面。
这还没有完善,但它实现了你的主要目标;使用地图进行导航,并防止导航到已完成的问题。