此问题的解决方案:Render items into DOM from array and changing value for each on click
我一直在开发一个JavaScript游戏,该游戏基于使用jQuery的DOM操作。
我要简化的功能是单击该项目以从HTML #store
的一个位置购买它,然后将其移动到#inventory
的另一个位置。单击库存物品以进行装备将其移动到#room
。单击#room
中的项目会将其移回到#inventory
。
当您在商店中单击某项进行购买时,owned
变量将从0
变为1
。当您单击库存中的物品进行装备时,它会从1
变为2
。装备好该物品后,点击该物品,它会从2
变为1
以移动位置。
我现在对此的设置为无主item.owned=0
,无主item.owned=1
和已装备item.owned=2
。
拥有变量的原因是在localStorage
中进行设置/获取以保存项目的当前位置。
我刚刚对脚本进行了硬编码,然后重复我自己以获得所需的结果。但这确实使文件肿。
这是我以前的解决方法:
HTML(显示class =“ dn”:无)
<body class="bg-near-black near-white sans-serif">
<main class="mw6 center">
<div class="ma3" id="shop">
<h3>shop</h3>
<div id="item1" class="item">
<p class="name-item1"></p>
<p class="cost-item1"></p>
<p class="desc-item1"></p>
</div>
<div id="item2" class="item">
<p class="name-item2"></p>
<p class="cost-item2"></p>
<p class="desc-item2"></p>
</div>
<div id="item3" class="item">
<p class="name-item3"></p>
<p class="cost-item3"></p>
<p class="desc-item3"></p>
</div>
</div>
<div class="ma3" id="inventory">
<h3>inventory</h3>
<div id="item1" class="item dn">
<p class="name-item1"></p>
<p class="desc-item1"></p>
</div>
<div id="item2" class="item dn">
<p class="name-item2"></p>
<p class="desc-item2"></p>
</div>
<div id="item3" class="item dn">
<p class="name-item3"></p>
<p class="desc-item3"></p>
</div>
</div>
<div class="ma3" id="room">
<h3>room</h3>
<div id="item1" class="item dn">
<p class="name-item1"></p>
</div>
<div id="item2" class="item dn">
<p class="name-item2"></p>
</div>
<div id="item3" class="item dn">
<p class="name-item3"></p>
</div>
</div>
</main>
<script src="js/jquery.min.js"></script>
<script src="js/script.js"></script>
</body>
JavaScript
$(document).ready(function() {
let items = {
item1: {
cost: 100,
owned: 0,
name: "Item | 1",
desc: "This is item 1.",
img: "img/item-1.gif"
}
};
// Render item info
$(".name-item1").each(function(){$(this).text(items.item1.name)});
$(".cost-item1").each(function(){$(this).text(items.item1.cost)});
$(".desc-item1").each(function(){$(this).text(items.item1.desc)});
// Render items
function drawitems() {
if (items.item1.owned==0) {
$("#shop #item1").show();
$("#inventory #item1").hide();
$("#room #item1").hide();
}
if (items.item1.owned==1) {
$("#shop #item1").hide();
$("#inventory #item1").show();
$("#room #item1").hide();
}
if (items.item1.owned==2) {
$("#shop #item1").hide();
$("#inventory #item1").hide();
$("#room #item1").show();
}
}
// Change item data
// Display item in inventory (Buy)
$("#shop").on("click","#item1",function(){
items.item1.owned=1
drawitems();
});
// Display item in room (Equip)
$("#inventory").on("click","#item1",function(){
items.item1.owned=2
drawitems();
});
// Display item in inventory (Unequip)
$("#room").on("click","#item1",function(){
items.item1.owned=1
drawitems();
});
// Save and load item data
$("#save").click(function(){
var save = {
"owneditem1": items.item1.owned,
};
localStorage.setItem("save",JSON.stringify(save));
});
function loadprogress() {
if (localStorage.getItem("save") !== null) {
var progress = JSON.parse(localStorage.getItem("save"));
items.item1.owned = progress["owneditem1"];
drawitems();
}
};
loadprogress();
});
我一直在寻找更简便,更干净的方法,并使用<div>
函数将项目呈现为.each()
ID,这是一个好的开始。但是现在我遇到了以下问题:我想将每个owned
的点击数据<div>
更改为我要渲染的项目,然后重新渲染DOM以将项目放在正确的{{1} },而无需更改所有项目上的<div>
数据。
我正在进行的新解决方案:
HTML
owned
JavaScript
<body class="bg-near-black near-white sans-serif">
<main class="mw6 center">
<div class="ma3" id="shop">
<h3>shop</h3>
</div>
<div class="ma3" id="inventory">
<h3>inventory</h3>
</div>
<div class="ma3" id="room">
<h3>room</h3>
</div>
</main>
<script src="js/jquery.min.js"></script>
<script src="js/script.js"></script>
</body>
这是我在新版本的脚本中获得的成就。我希望有一种更简单的方法来更改状态并在HTML部分中相应地显示它们,而包括localStorage而不在其各自的函数中列出所有项目。
答案 0 :(得分:0)
尽管我无法在不知道事件处理程序做什么的情况下向您展示一种更改项目状态的简便方法,但是可以通过构建更多抽象来提高代码的可读性。这也将减少“负担”。
首先查找重复的事物,并可以将其封装到单独的函数中。例如,我首先将HTML String
的创建放入一个单独的函数中,该函数接受应该呈现的项目。
您很快就会发现更多一遍又一遍地重复的内容(使用$( ... )
进行DOM遍历,事件监听器注册$(...).on('click', ...)
等)。考虑一下替换这些行的方法(提示:function
是您的朋友)。尝试使它们尽可能通用,因为那样的话,您很有可能可以在其他部分重用它们。
下面是一个示例,分为几个步骤。您可以将它们从上到下进行组合,但是如果您继续这样做,将会从中得到更多的好处。
1。数据
数据本身(items
)与您已经拥有的数据完全相同,此处无更改。请注意,它是脚本内的全局可用变量。那很重要!如果情况有所不同,那么下面的代码部分最终将有所不同。无论如何:
var items = {
item1: {
cost: 100,
owned: 0,
name: "Item | 1",
desc: "This is item 1.",
img: "img/item-1.gif",
},
item2: {
cost: 200,
owned: 0,
name: "Item | 2",
desc: "This is item 2.",
img: "img/item-2.gif",
},
item3: {
cost: 300,
owned: 0,
name: "Item | 3",
desc: "This is item 3.",
img: "img/item-3.gif",
}
};
2。渲染抽象
这些函数用于将项目渲染到它们各自的DOM节点($('#shop')
,$('#inventory')
或$('#room')
中。
renderItem
函数接受一个项目,并从中创建一个String
,它代表一段HTML。看一下如何创建元素:反复使用完全相同的代码。这是一个重复的模式,可以“压缩”为一个函数。
renderItems
(请注意其末尾的s
)功能要复杂一些。它需要Array
的jQuery集合($('#shop')
等)。这些集合的索引位置必须是每个项目的.owned
状态的值,因此.owned: 0
映射到{{1} }。 $('#shop')
的第二个参数是要渲染的项目。
renderItems
3。实用程序
与其编写// ====== DOM BUILDING ======
function renderItem (x) {
return [
'<div class="item">',
'<div style="background-image:url(' + x.img + ')"></div>',
'<span>'+ x.name +'</span>',
'<span>Price: '+ x.cost +'</span>',
'<span>'+ x.desc +'</span>',
'</div>'
].join('');
}
function renderItems (targets, xs) {
$.each(xs, function(key, item) {
if (item.owned >= 0 && item.owned < targets.length) {
targets[item.owned].append(renderItem(item));
}
});
}
等,不如将事件侦听器添加到单独的函数中。稍后它会消除一些混乱。
$('#shop').on('click', ...)
4。与// ====== UTILITIES ======
function clickItem (jq, f) {
return jq.on('click', '.item', f);
}
相关
您可以将代码的某些方面提取到它们自己的功能中,例如加载和保存项目。在这里,localStorage
尝试检索以前保存的项目,而loadState
保存当前的项目。
我还删除了您的项目及其存储的表示形式之间的转换,因为它并不是真正需要的(至少在您显示的代码中不需要)。
saveState
5。在“就绪”状态下运行它
这是所有要素的集合。首先,在DOM中查询目标元素,并将其保留为// ====== SAVE/LOAD ======
function loadState () { // was: loadprogress
var state = localStorage.getItem('save');
if (state) {
items = JSON.parse(state);
}
}
function saveState () {
localStorage.setItem('save', JSON.stringify(items));
}
中的变量,因为它们将在其中多次使用。
下一步是尝试装入bootstrap
内部的项目。如果有项目,它们将是第1步中新的全局localStorage
变量。
接下来,将事件侦听器添加到目标DOM节点。这是第一次,items
和其他的一起使用。
然后,将当前可用的所有项目渲染到目标元素中。第二次,我们使用$('#shop')
及其他。
最后,使用$('#shop')
每10秒保存一次。
setInterval
我建议您在DOM加载后立即执行它。因此,请执行以下操作:// ====== INITIALIZE ======
function bootstrap () {
var $shop = $('#shop'),
$room = $('#room'),
$inventory = $('#inventory');
loadState();
clickItem($shop, function () {
//Set item owned to 1 to store in #inventory
});
clickItem($inventory, function () {
//Set item owned to 2 to display in #room
});
clickItem($room, function() {
//Set item owned to 1 to move back to to #inventory
});
renderItems([$shop, $inventory, $room], items);
setInterval(saveState, 10000);
}
,或执行以下操作:$(bootstrap)
。
如上所述,它没有显示更改jQuery.ready(bootstrap)
状态的方法,因为我对您的事件处理程序一无所知,并带有注释.owned
,因为在我看来,这就是您的{ {1}}状态更改。但这也应该引导您进入正确的心态以解决该问题。