这是我对投票系统的尝试。只有一个时,它会按预期工作。但是,当我尝试将投票系统的数量扩展到一个以上时,它无法按预期工作。问题在于投票系统依赖于upVote
和downVote
状态。因此,当我增加投票系统的数量时,它们都依赖于相同的两个变量,而不是每个变量都有自己的upVote
和downVote
变量。我认为有两种方法可以解决我的问题。
创建一个数组,以便每个投票系统都有自己的upVote
和downVote
变量。
使用闭包。
我认为第一个太麻烦且不切实际,我不知道如何实现此解决方案。我尝试了第二个,但是无法正常工作。
我想不出任何简单的方法。我不一定要寻找使用闭包的解决方案。任何简单的原始Javascript 解决方案都可以。
工作代码:
const up_vote_span = document.querySelector('.up-vote');
const down_vote_span = document.querySelector('.down-vote');
let count = document.querySelector('.number');
let upVote = false;
let downVote = false;
up_vote_span.addEventListener('click', function() {
if (downVote === true) {
up_vote_span.style.color = "#3CBC8D";
down_vote_span.style.color = "dimgray";
count.innerHTML = parseInt(count.innerHTML) + 2;
upVote = true;
downVote = false;
} else if (upVote === false) {
up_vote_span.style.color = "#3CBC8D";
count.innerHTML = parseInt(count.innerHTML) + 1;
upVote = true;
} else if (upVote === true) {
up_vote_span.style.color = "dimgray";
count.innerHTML = parseInt(count.innerHTML) - 1;
upVote = false;
}
});
down_vote_span.addEventListener('click', function() {
if (upVote === true) {
up_vote_span.style.color = "dimgray";
down_vote_span.style.color = "#3CBC8D";
count.innerHTML = parseInt(count.innerHTML) - 2;
downVote = true;
upVote = false;
} else if (downVote === false) {
down_vote_span.style.color = "#3CBC8D";
count.innerHTML = parseInt(count.innerHTML) - 1;
downVote = true;
} else if (downVote === true) {
down_vote_span.style.color = "dimgray";
count.innerHTML = parseInt(count.innerHTML) + 1;
downVote = false;
}
});
.number {
display: inline-block;
text-align: center;
}
.vote {
display: flex;
flex-direction: column;
text-align: center;
}
.up-vote {
color: dimgray;
cursor: pointer;
}
.down-vote {
cursor: pointer;
color: dimgray;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
有问题的代码:
const up_vote_span = document.getElementsByClassName('up-vote');
const down_vote_span = document.getElementsByClassName('down-vote');
const count = document.getElementsByClassName('number');
let upVote = false;
let downVote = false;
for (let i = 0; i < count.length; i++) {
up_vote_span[i].addEventListener('click', function() {
if (downVote === true) {
up_vote_span[i].style.color = "#3CBC8D";
down_vote_span[i].style.color = "dimgray";
count[i].innerHTML = parseInt(count[i].innerHTML) + 2;
upVote = true;
downVote = false;
} else if (upVote === false) {
up_vote_span[i].style.color = "#3CBC8D";
count[i].innerHTML = parseInt(count[i].innerHTML) + 1;
upVote = true;
} else if (upVote === true) {
up_vote_span[i].style.color = "dimgray";
count[i].innerHTML = parseInt(count[i].innerHTML) - 1;
upVote = false;
}
});
down_vote_span[i].addEventListener('click', function() {
if (upVote === true) {
up_vote_span[i].style.color = "dimgray";
down_vote_span[i].style.color = "#3CBC8D";
count[i].innerHTML = parseInt(count[i].innerHTML) - 2;
downVote = true;
upVote = false;
} else if (downVote === false) {
down_vote_span[i].style.color = "#3CBC8D";
count[i].innerHTML = parseInt(count[i].innerHTML) - 1;
downVote = true;
} else if (downVote === true) {
down_vote_span[i].style.color = "dimgray";
count[i].innerHTML = parseInt(count[i].innerHTML) + 1;
downVote = false;
}
});
}
.number {
display: inline-block;
text-align: center;
}
.vote {
display: flex;
flex-direction: column;
text-align: center;
}
.up-vote {
color: dimgray;
cursor: pointer;
}
.down-vote {
cursor: pointer;
color: dimgray;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>
<body>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
</body>
</html>
答案 0 :(得分:4)
我正在使用Prototype Pattern来组织代码。
这将适用于n
中的.vote
HTML
类。例如,给定以下HTML
,将创建两个投票对象并将其与各自的UI关联。
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">0</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">0</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
您可能已经注意到,以上id
中没有HTML
。 id
是在forEach
循环中动态创建的,并在每个对象的init
上分配。我使用myVotePrototype
作为模板,将其prototype
复制到在myVote
中创建的每个新对象中。 myVote
使用id
进行初始化,这是每个投票都知道在哪里找到其关联的UI片段的方式。
JavaScript
在.vote
父容器中设置投票方向。因此,在投票之后,该投票对象的HTML
看起来像这样:
<div class="vote vote-up">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">0</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
我添加了一点CSS
,以便每个按钮都知道何时采用活动颜色。与直接将十六进制代码直接写到style
属性中相比,我发现这比较麻烦。
.vote.vote-up .up-vote,
.vote.vote-down .down-vote {
color: #3CBC8D;
}
const myVotePrototype = {
init: function(id) {
this.voteId = id;
// Prepare for voting clicks
this.bindEvents();
},
votes: 0,
upVote: function() {
this.votes++;
this.setVoteDirection('up');
},
downVote: function() {
this.votes--;
this.setVoteDirection('down');
},
setVoteDirection: function(direction) {
let voteObj = document.getElementById(this.voteId);
if (direction === 'up') {
voteObj.classList.add('vote-up');
if (voteObj.classList.contains('vote-down')) {
voteObj.classList.remove('vote-down');
}
} else if (direction === 'down') {
voteObj.classList.add('vote-down');
if (voteObj.classList.contains('vote-up')) {
voteObj.classList.remove('vote-up');
}
}
},
updateUI: function() {
document.querySelector(`#${this.voteId} .number`).innerHTML = Number(this.votes);
},
bindEvents: function() {
document
.querySelector(`#${this.voteId} .up-vote`)
.addEventListener('click', () => {
this.upVote();
this.updateUI();
});
document
.querySelector(`#${this.voteId} .down-vote`)
.addEventListener('click', () => {
this.downVote();
this.updateUI();
})
}
};
function myVote(id) {
function V() {};
V.prototype = myVotePrototype;
let v = new V();
v.init(id);
return v;
}
// Loop through all votes in the UI
const votes = document.querySelectorAll('.vote');
votes.forEach((vote, index) => {
// Create an id
let voteId = `vote_${index}`;
// Set the id in the UI so we can find it later for updating
vote.setAttribute('id', voteId);
// Create a new vote object, passing in the vote id
myVote(voteId);
});
.number {
display: inline-block;
text-align: center;
}
.vote {
display: flex;
flex-direction: column;
text-align: center;
}
.up-vote,
.down-vote {
color: dimgray;
cursor: pointer;
}
.vote.vote-up .up-vote,
.vote.vote-down .down-vote {
color: #3CBC8D;
}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">0</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">0</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">0</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
改进思想
HTML
(<button>
而非<span>
)button
与number
输出相关联localStorage
来记住页面加载之间的投票状态(或使用真实的DB
:))答案 1 :(得分:2)
我认为您会发现这更容易控制,并考虑是否要使用您在选项#1中提到的数组方法,然后创建一个单独的函数进行投票和一个单独的函数进行投票,而不是为每个单独的函数创建单独的函数像现在一样上下箭头。
您现在有四个组,因此在for
循环中,我们可以像这样初始化数组:
const votes = [
0: { up: false, down: false },
1: { up: false, down: false },
2: { up: false, down: false },
3: { up: false, down: false },
];
然后,您可以仅调用上下投票功能,并检查该数组中与您单击的箭头的组号相对应的对象的值。
我认为有助于提高可读性的另一件事是将更改投票总数与更改颜色分开。
您的投票逻辑包括三种不同的可能性:1.)箭头已被选中; 2.)反向箭头已被选中; 3.)箭头均未被选中。但是,您的变色逻辑和用于更改每个箭头的检查值的逻辑实际上只有两种可能:要么之前检查过箭头,要么没有检查过箭头。
所以我继续进行下面的代码片段中的更改。
希望这会有所帮助。
const up_vote_spans = document.getElementsByClassName('up-vote');
const down_vote_spans = document.getElementsByClassName('down-vote');
const count = document.getElementsByClassName('number');
let votes = [];
for (let i = 0; i < count.length; i += 1) {
const thisUpVoteSpan = up_vote_spans[i];
const thisDownVoteSpan = down_vote_spans[i];
votes[i] = { up: false, down: false };
thisUpVoteSpan.addEventListener('click', handleUpvote.bind(null, i), false);
thisDownVoteSpan.addEventListener('click', handleDownvote.bind(null, i), false);
}
function handleUpvote(i) {
const currentVote = votes[i];
const matchingUpSpan = up_vote_spans[i];
const matchingDownSpan = down_vote_spans[i];
const matchingCount = count[i];
const currentCount = parseInt(matchingCount.innerHTML);
if (currentVote.down) {
matchingCount.innerHTML = currentCount + 2;
} else if (currentVote.up === false) {
matchingCount.innerHTML = currentCount + 1;
} else {
matchingCount.innerHTML = currentCount - 1;
}
if (!currentVote.up) {
matchingUpSpan.style.color = "#3CBC8D";
matchingDownSpan.style.color = 'dimgray';
currentVote.up = true;
currentVote.down = false;
} else {
matchingUpSpan.style.color = 'dimgray';
currentVote.up = false;
}
}
function handleDownvote(i) {
const currentVote = votes[i];
const matchingUpSpan = up_vote_spans[i];
const matchingDownSpan = down_vote_spans[i];
const matchingCount = count[i];
const currentCount = parseInt(matchingCount.innerHTML);
if (currentVote.up) {
matchingCount.innerHTML = currentCount - 2;
} else if (currentVote.down === false) {
matchingCount.innerHTML = currentCount - 1;
} else {
matchingCount.innerHTML = currentCount + 1;
}
if (!currentVote.down) {
matchingDownSpan.style.color = "#3CBC8D";
matchingUpSpan.style.color = 'dimgray';
currentVote.down = true;
currentVote.up = false;
} else {
matchingDownSpan.style.color = 'dimgray';
currentVote.down = false;
}
}
.number {
display: inline-block;
text-align: center;
}
.vote {
display: flex;
flex-direction: column;
text-align: center;
}
.up-vote {
color: dimgray;
cursor: pointer;
}
.down-vote {
cursor: pointer;
color: dimgray;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
</head>
<body>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
<div class="vote">
<span class="up-vote"><i class="fas fa-angle-up"></i></span>
<span class="number">990</span>
<span class="down-vote"><i class="fas fa-angle-down"></i></span>
</div>
</body>
</html>
答案 2 :(得分:0)
我个人认为布尔型投票数组还不错。但是,如果您希望使用其他方法,则可以使用类操作来使它们分开以进行操作。
JSFiddle:https://jsfiddle.net/0uw83a17/
// From https://plainjs.com/javascript/traversing/get-siblings-of-an-element-40/
function getSiblings(el, filter) {
var siblings = [];
el = el.parentNode.firstChild;
do { if (!filter || filter(el)) siblings.push(el); } while (el = el.nextSibling);
return siblings;
}
function classFilter(el) {
return el.classList && el.classList.contains('active-vote');
}
function handleVote(type, el) {
let siblings = getSiblings(el, classFilter);
if (el.classList.contains('active-vote')) {
el.style.color = "dimgray";
el.classList.remove('active-vote');
return -1 * type;
} else if (siblings.length === 1) {
el.style.color = "#3CBC8D";
siblings[0].style.color = "dimgray";
siblings[0].classList.remove('active-vote');
el.classList.add('active-vote');
return 2 * type;
} else if (!el.classList.contains('active-vote')) {
el.style.color = "#3CBC8D";
el.classList.add('active-vote');
return type;
}
return 0;
}
const up_vote_span = document.getElementsByClassName('up-vote');
const down_vote_span = document.getElementsByClassName('down-vote');
const count = document.getElementsByClassName('number');
for (let i = 0; i < count.length; i++) {
up_vote_span[i].addEventListener('click', function(e) {
count[i].innerHTML = parseInt(count[i].innerHTML) + handleVote(1, up_vote_span[i]);
});
down_vote_span[i].addEventListener('click', function() {
count[i].innerHTML = parseInt(count[i].innerHTML) + handleVote(-1, down_vote_span[i]);
});
};