javascript - 试图在数组中找到确切单词的索引,而不仅仅是匹配的第一个单词的索引
问题描述
我有 2 个要解决的问题:我正在尝试为圣经应用程序制作圣经游戏。
问题是我的经文中有多次相同的词(例如“起初上帝创造了天地”有3次)。我现在设置的方式适用于仅在圣经中出现一次的单词,但对于单词“the”,我的代码当前将找到与“the”匹配的第一个数组项并将其移动到数组中的其他位置。例如:如果我有乱七八糟的经文——“起初上帝创造天地 the the在创造和天堂之间它移动第一个(在和开始之间的那个)。如何更改我的比较功能以便找到正确的?
我希望我的单词数组/项目列表在单词被拖到下一个单词时重新排列,而不仅仅是在单词被删除时。如果您对此有任何想法,请告诉我。
<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()
返回匹配条件的第一个元素 - 这就是您的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 ,它是围绕sortable.js的 Vue 包装器,这是一个使用拖放 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>
推荐阅读
- javascript - 防止反斜杠从Javascript中的字符串转义
- android - 如何在android中存储API凭据并避免反编译攻击?
- postgresql - 在 Postgresql 存储过程中使用准备好的语句或动态命令?
- ios - 当我滚动 UITableview 时自动滚动 UICollectionView
- angular - 如何等到我从 Angular 7 的后端 spring boot api 得到响应
- java - 从 JDK 8 迁移到 OPEN JDK 11 - 缺少导入
- python - ctypes 数组不可调用
- python - 为什么鼠标悬停数据消失
- jquery - 为什么引导选择选择器无法第二次调用?
- linux - 如何计算特定列有两种模式的行数?