试图在数组中查找确切单词的索引,而不仅仅是匹配的第一个单词的索引
Trying to find index of the exact word in an array instead of just the index of the first word that matches
我有 2 个问题要解决:
我正在尝试为圣经软件制作一个解读经文的游戏。
问题是我的经文多次出现相同的词(例如“起初神创造天地”有 3 次)。我现在设置它的方式适用于只在经文中出现一次的单词,但对于单词“the”,我的代码当前将找到与“the”匹配的第一个数组项并将其移动到数组中的其他位置。例如:如果我有乱序的经文——“起初上帝创造了天地 the the the”,我尝试将第一个 the in 拖到 in 和 beginning 之间,它会像预期的那样工作,但是,如果我尝试将第二个 the in 拖到在创造和天堂之间它移动第一个(在和开始之间的那个)。我怎样才能改变我的比较功能,以便它找到正确的?
我希望我的 words/list 项目数组在单词被拖到下一个项目时重新排列,而不仅仅是在单词被放下时。如果您对此有任何想法,请告诉我。
<template>
<div>
<!-- <div :scripture="scripture">{{ scripture }}</div> -->
<ul :scripture="scriptureArray" id="list"></ul>
<div :verse="verse">- {{ verse }}</div>
</div>
</template>
<script>
let vm;
export default {
data() {
return {
dragging: "",
draggedOver: "",
scriptureArray: [],
};
},
props: {
scripture: {
type: String,
required: true,
default: "",
},
verse: {
type: String,
required: true,
default: "",
},
correct: {
type: String,
required: true,
default: "",
}
},
methods: {
renderDraggableItems(scriptureArr) {
let list = document.getElementById("list");
list.innerText = "";
scriptureArr.forEach((word) => {
var node = document.createElement("li");
node.draggable = true;
node.addEventListener("drag", vm.setDragging);
node.addEventListener("dragover", vm.setDraggedOver);
node.addEventListener("dragend", vm.compare);
node.innerText = word;
list.appendChild(node);
});
},
setDragging(e) {
this.dragging = Number.isNaN(parseInt(e.target.innerText))
? e.target.innerText
: parseInt(e.target.innerText);
},
setDraggedOver(e) {
e.preventDefault();
this.draggedOver = Number.isNaN(parseInt(e.target.innerText))
? e.target.innerText
: parseInt(e.target.innerText);
},
compare(e) {
e.preventDefault();
var index1 = this.scriptureArray.indexOf(this.dragging);
var index2 = this.scriptureArray.indexOf(this.draggedOver);
this.scriptureArray.splice(index1, 1);
this.scriptureArray.splice(index2, 0, this.dragging);
console.log("scriptureArray:", this.scriptureArray);
this.renderDraggableItems(this.scriptureArray);
// this way works as long as no 2 words in the scripture are the same (text matching), is there another way?
},
},
mounted() {
vm = this;
this.scriptureArray = this.scripture.split(" ");
this.renderDraggableItems(this.scriptureArray);
},
};
</script>
<style scopped>
#list {
list-style: none;
font-size: 30px;
display: flex;
justify-content: space-evenly;
}
</style>
这个组件是这样调用的
<template>
<!-- add a component that shows the scrptures, keeps track of time, and allows unscrabling -->
<div>
<Timer @GameOver="handleGameOver" />
<DraggableSentence
:scripture="scrambledCurrentScripture"
:verse="currentScriptureVerse"
:correct="correctCurrentScripture"
/>
<!-- TODO: create a level for each key in genesis -->
</div>
</template>
哪里
scrambledCurrentScripture = "the begging In God created the earth heavens and the"
currentScriptureVerse = "genesis 1:1"
correctCurrentScripture = "In the beginning God created the heave and the earth"
您有很多可以改进的地方:
- 打乱版本中的单词与正确答案中的单词不同。如果这是给一些孩子的,我可以想象他们变老了,还在玩,因为无法破解而感到沮丧
- 你不应该在使用 Vue 时执行 DOM 操作。并不是说它不起作用,而是说 Vue 在处理和更新 DOM 方面非常高效。当您手动执行时,这有点像从驾驶座上下来并将其推到路上(只需更新源数组并让 Vue 根据值变化处理 DOM)
- 处理拖放时,您需要元素的唯一标识符。他们目前的
index
就足够了。 (.indexOf()
returns 符合条件的第一个元素 - 这就是您的 compare
方法失败的原因)。
这里是:
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
to: "",
from: "",
words: [],
verse: "Genesis 1:1",
correctAnswer: "In the beginning God created the heavens and the earth"
}),
computed: {
isCorrectOrder() {
return this.words.join(' ') === this.correctAnswer;
}
},
methods: {
onDragEnd() {
const word = this.words[this.from];
this.words.splice(this.from, 1);
this.words.splice(this.to, 0, word);
},
},
mounted() {
// basic shuffle
this.words = this.correctAnswer.split(" ")
.map(s => ({s, r: Math.random()}))
.sort((a, b) => a.r > b.r ? -1 : 1)
.map(o => o.s);
},
})
ul {
list-style: none;
font-size: 24px;
display: flex;
justify-content: space-evenly;
padding-left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="( value, index ) in words"
:key="index"
draggable="true"
@drag="from = index"
@dragover.prevent="to = index"
@dragend.prevent="onDragEnd"
v-text="value" />
</ul>
<div :verse="verse">- {{ verse }}</div>
<h4><em v-if="isCorrectOrder">You got it right!</em></h4>
</div>
就第二个请求而言,我的建议是使用 Vue.draggable, the Vue wrapper around sortable.js,一个使用拖放 HTML5 api 的小型但功能强大的 d&d 包,具有旧版浏览器的后备功能和触摸兼容。
它还会简化标记,因为您不再需要指定拖动事件:
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
words: [],
verse: "Genesis 1:1",
correctAnswer: "In the beginning God created the heavens and the earth"
}),
computed: {
isCorrectOrder() {
return this.words.join(' ') === this.correctAnswer;
}
},
mounted() {
this.words = _.shuffle(this.correctAnswer.split(" "));
},
})
.drag-list {
font-size: 24px;
display: flex;
justify-content: space-evenly;
padding-left: 0;
margin: 40px 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="//cdn.jsdelivr.net/npm/sortablejs@1.8.4/Sortable.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js"></script>
<div id="app">
<draggable v-model="words" class="drag-list">
<div v-for="( value, index ) in words"
:key="index">{{value}}</div>
</draggable>
<div :verse="verse">- {{ verse }}</div>
<h4><em v-if="isCorrectOrder">You got it right!</em></h4>
</div>
忍不住加了一个计时器。太诱人了...
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
words: [],
verse: "Genesis 1:1",
correctAnswer: "In the beginning God created the heavens and the earth",
start: performance.now(),
current: performance.now()
}),
computed: {
isCorrectOrder() {
return this.words.join(' ') === this.correctAnswer;
},
timeElapsed() {
return Math.round((this.current - this.start) / 100) / 10;
}
},
methods: {
tick() {
this.current = performance.now();
if (!this.isCorrectOrder) {
setTimeout(this.tick, 100);
}
}
},
mounted() {
this.words = _.shuffle(this.correctAnswer.split(" "));
this.tick();
},
})
.drag-list {
font-size: 24px;
display: flex;
justify-content: space-evenly;
padding-left: 0;
margin: 40px 10px;
}
.flexer {
display: flex;
align-items: center;
}
code {
padding-left: 2rem;
}
code:after {
content: 's'
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="//cdn.jsdelivr.net/npm/sortablejs@1.8.4/Sortable.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js"></script>
<div id="app">
<draggable v-model="words" class="drag-list">
<div v-for="( value, index ) in words" :key="index">{{value}}</div>
</draggable>
<div :verse="verse">- {{ verse }}</div>
<div class="flexer">
<h4><em v-if="isCorrectOrder">You got it right!</em></h4>
<code v-text="timeElapsed"></code>
</div>
</div>
我有 2 个问题要解决: 我正在尝试为圣经软件制作一个解读经文的游戏。
问题是我的经文多次出现相同的词(例如“起初神创造天地”有 3 次)。我现在设置它的方式适用于只在经文中出现一次的单词,但对于单词“the”,我的代码当前将找到与“the”匹配的第一个数组项并将其移动到数组中的其他位置。例如:如果我有乱序的经文——“起初上帝创造了天地 the the the”,我尝试将第一个 the in 拖到 in 和 beginning 之间,它会像预期的那样工作,但是,如果我尝试将第二个 the in 拖到在创造和天堂之间它移动第一个(在和开始之间的那个)。我怎样才能改变我的比较功能,以便它找到正确的?
我希望我的 words/list 项目数组在单词被拖到下一个项目时重新排列,而不仅仅是在单词被放下时。如果您对此有任何想法,请告诉我。
<template>
<div>
<!-- <div :scripture="scripture">{{ scripture }}</div> -->
<ul :scripture="scriptureArray" id="list"></ul>
<div :verse="verse">- {{ verse }}</div>
</div>
</template>
<script>
let vm;
export default {
data() {
return {
dragging: "",
draggedOver: "",
scriptureArray: [],
};
},
props: {
scripture: {
type: String,
required: true,
default: "",
},
verse: {
type: String,
required: true,
default: "",
},
correct: {
type: String,
required: true,
default: "",
}
},
methods: {
renderDraggableItems(scriptureArr) {
let list = document.getElementById("list");
list.innerText = "";
scriptureArr.forEach((word) => {
var node = document.createElement("li");
node.draggable = true;
node.addEventListener("drag", vm.setDragging);
node.addEventListener("dragover", vm.setDraggedOver);
node.addEventListener("dragend", vm.compare);
node.innerText = word;
list.appendChild(node);
});
},
setDragging(e) {
this.dragging = Number.isNaN(parseInt(e.target.innerText))
? e.target.innerText
: parseInt(e.target.innerText);
},
setDraggedOver(e) {
e.preventDefault();
this.draggedOver = Number.isNaN(parseInt(e.target.innerText))
? e.target.innerText
: parseInt(e.target.innerText);
},
compare(e) {
e.preventDefault();
var index1 = this.scriptureArray.indexOf(this.dragging);
var index2 = this.scriptureArray.indexOf(this.draggedOver);
this.scriptureArray.splice(index1, 1);
this.scriptureArray.splice(index2, 0, this.dragging);
console.log("scriptureArray:", this.scriptureArray);
this.renderDraggableItems(this.scriptureArray);
// this way works as long as no 2 words in the scripture are the same (text matching), is there another way?
},
},
mounted() {
vm = this;
this.scriptureArray = this.scripture.split(" ");
this.renderDraggableItems(this.scriptureArray);
},
};
</script>
<style scopped>
#list {
list-style: none;
font-size: 30px;
display: flex;
justify-content: space-evenly;
}
</style>
这个组件是这样调用的
<template>
<!-- add a component that shows the scrptures, keeps track of time, and allows unscrabling -->
<div>
<Timer @GameOver="handleGameOver" />
<DraggableSentence
:scripture="scrambledCurrentScripture"
:verse="currentScriptureVerse"
:correct="correctCurrentScripture"
/>
<!-- TODO: create a level for each key in genesis -->
</div>
</template>
哪里
scrambledCurrentScripture = "the begging In God created the earth heavens and the"
currentScriptureVerse = "genesis 1:1"
correctCurrentScripture = "In the beginning God created the heave and the earth"
您有很多可以改进的地方:
- 打乱版本中的单词与正确答案中的单词不同。如果这是给一些孩子的,我可以想象他们变老了,还在玩,因为无法破解而感到沮丧
- 你不应该在使用 Vue 时执行 DOM 操作。并不是说它不起作用,而是说 Vue 在处理和更新 DOM 方面非常高效。当您手动执行时,这有点像从驾驶座上下来并将其推到路上(只需更新源数组并让 Vue 根据值变化处理 DOM)
- 处理拖放时,您需要元素的唯一标识符。他们目前的
index
就足够了。 (.indexOf()
returns 符合条件的第一个元素 - 这就是您的compare
方法失败的原因)。
这里是:
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
to: "",
from: "",
words: [],
verse: "Genesis 1:1",
correctAnswer: "In the beginning God created the heavens and the earth"
}),
computed: {
isCorrectOrder() {
return this.words.join(' ') === this.correctAnswer;
}
},
methods: {
onDragEnd() {
const word = this.words[this.from];
this.words.splice(this.from, 1);
this.words.splice(this.to, 0, word);
},
},
mounted() {
// basic shuffle
this.words = this.correctAnswer.split(" ")
.map(s => ({s, r: Math.random()}))
.sort((a, b) => a.r > b.r ? -1 : 1)
.map(o => o.s);
},
})
ul {
list-style: none;
font-size: 24px;
display: flex;
justify-content: space-evenly;
padding-left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="( value, index ) in words"
:key="index"
draggable="true"
@drag="from = index"
@dragover.prevent="to = index"
@dragend.prevent="onDragEnd"
v-text="value" />
</ul>
<div :verse="verse">- {{ verse }}</div>
<h4><em v-if="isCorrectOrder">You got it right!</em></h4>
</div>
就第二个请求而言,我的建议是使用 Vue.draggable, the Vue wrapper around sortable.js,一个使用拖放 HTML5 api 的小型但功能强大的 d&d 包,具有旧版浏览器的后备功能和触摸兼容。
它还会简化标记,因为您不再需要指定拖动事件:
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
words: [],
verse: "Genesis 1:1",
correctAnswer: "In the beginning God created the heavens and the earth"
}),
computed: {
isCorrectOrder() {
return this.words.join(' ') === this.correctAnswer;
}
},
mounted() {
this.words = _.shuffle(this.correctAnswer.split(" "));
},
})
.drag-list {
font-size: 24px;
display: flex;
justify-content: space-evenly;
padding-left: 0;
margin: 40px 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="//cdn.jsdelivr.net/npm/sortablejs@1.8.4/Sortable.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js"></script>
<div id="app">
<draggable v-model="words" class="drag-list">
<div v-for="( value, index ) in words"
:key="index">{{value}}</div>
</draggable>
<div :verse="verse">- {{ verse }}</div>
<h4><em v-if="isCorrectOrder">You got it right!</em></h4>
</div>
忍不住加了一个计时器。太诱人了...
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => ({
words: [],
verse: "Genesis 1:1",
correctAnswer: "In the beginning God created the heavens and the earth",
start: performance.now(),
current: performance.now()
}),
computed: {
isCorrectOrder() {
return this.words.join(' ') === this.correctAnswer;
},
timeElapsed() {
return Math.round((this.current - this.start) / 100) / 10;
}
},
methods: {
tick() {
this.current = performance.now();
if (!this.isCorrectOrder) {
setTimeout(this.tick, 100);
}
}
},
mounted() {
this.words = _.shuffle(this.correctAnswer.split(" "));
this.tick();
},
})
.drag-list {
font-size: 24px;
display: flex;
justify-content: space-evenly;
padding-left: 0;
margin: 40px 10px;
}
.flexer {
display: flex;
align-items: center;
}
code {
padding-left: 2rem;
}
code:after {
content: 's'
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="//cdn.jsdelivr.net/npm/sortablejs@1.8.4/Sortable.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js"></script>
<div id="app">
<draggable v-model="words" class="drag-list">
<div v-for="( value, index ) in words" :key="index">{{value}}</div>
</draggable>
<div :verse="verse">- {{ verse }}</div>
<div class="flexer">
<h4><em v-if="isCorrectOrder">You got it right!</em></h4>
<code v-text="timeElapsed"></code>
</div>
</div>