Ответ 1
Да, JavaScript задействован. Он состоит из двух частей: подключение обработчика событий нажатия на кнопках голосования и отправка данных на сервер.
Освещение событий хорошо освещено в другом месте, и я не буду вдаваться в подробности здесь. (Например, я освещаю это в этом ответе.)
Отправляя данные на сервер, вы можете использовать ajax. В любом браузере, который не является полностью устаревшим, вы можете использовать XMLHttpRequest
:
var xhr = new XMLHttpRequest();
xhr.open("POST", "/path/to/server/destination");
xhr.onreadystatechange = handleStateChange;
xhr.send("id=" + encodeURIComponent(id) +
"&user=" + encodeURIComponent(userId) +
"&vote=up");
function handleStateChange() {
if (xhr.readyState === 4) {
// POST complete
if (xhr.status === 200) {
// POST complete and we have response, check it
if (xhr.responseText !== "ok") { // Or whatever you want it to be
// Report problem
}
} else {
// Ajax failed, handle/report problem
}
}
}
В более современных браузерах вы можете использовать fetch
:
var body = new FormData();
body.append("id", id);
body.append("user", userId);
body.append("vote", "up");
fetch("/path/to/server/destination", {
method: "POST",
body: body
})
.then(function(res) {
if (!res.ok) {
throw new Error("HTTP error " + res.status);
}
return res.text(); // or 'res.json()' if you return JSON
})
.then(function(data) {
if (data !== "ok") { // Or whatever
// Report problem
}
})
.catch(function(error) {
// Ajax failed, handle/report problem
});
Просто для удовольствия, вот полный пример:
HTML:
<div class="article" data-itemid="427">
<a href="voteup" class="vote up" >Up</a>
<a href="votedown" class="vote down">Down</a>
<!-- ...the contents of the item... -->
</div>
JavaScript:
document.addEventListener("click", function(event) {
// Regardless of the below, we handle the event, so "consume" it
event.stopPropagation();
event.preventDefault();
// Get the anchor element
var voteLink = event.target.closest("a.vote");
if (!voteLink) {
// Didn't find one, bail
return;
}
// See if the vote has already been done or is in progress
if (voteLink.classList.contains("done") || voteLink.classList.contains("inprogress")) {
// Ignore the click, possibly tell the user why
return;
}
// Get the vote type
var voteType = voteLink.classList.contains("up") ? "up" : "down";
// Get the item we"re voting on
var item = voteLink.closest(".article");
// Get its ID
var itemId = item.getAttribute("data-itemid");
// If we didn"t get an ID...
if (!itemId) {
// ...report error
return;
}
// Mark "in progress" and initiate the vote; action continues
// in our callbacks below
voteLink.classList.add("inprogress");
var body = new FormData();
body.append("itemId", itemId);
body.append("voteType", voteType);
fetch("savevote", {
method: "POST",
body: body
})
.then(function(res) {
if (!res.ok) {
throw new Error("HTTP error " + res.status);
}
return res.text(); // or 'res.json()' if you return JSON
})
.then(function(data) {
if (data === "ok") { // Or whatever
voteLink.classList.add("done");
} else {
// Report an error to the user, the server couldn"t record the vote
}
})
.catch(function(error) {
// Ajax failed, handle/report problem
})
.finally(function() {
// Not in progress anymore
voteLink.classList.remove("inprogress");
});
});
Некоторые заметки:
- Приведенный выше код написан на ES5, но вы можете использовать функции ES2015+ в большинстве современных браузеров (или с помощью таких инструментов, как Babel).
- Я добавил
href
на ссылки (чего нет у StackOverflow), чтобы, если JavaScript отключен, мы могли вернуться к странице, где мы позволяем пользователю голосовать, используя отправку формы или что-то в этом роде. Кроме того, ссылки сhref
обрабатываются специально браузерами (цели табуляции и т.д.), Так что это полезно для доступности. (Чтобы действительно сделать это, я, вероятно, должен был бы также поместить идентификатор статьи вhref
.) - Я
data-
идентификатор элемента, поdata-
мы голосуем, вdata-
. - Мы найдем элемент для голосования, найдя "ближайшую" статью к нажатой кнопке.
closest
функция DOM начинается с элемента и проверяет, соответствует ли этот элемент указанному селектору CSS, затем, если не смотрит на его родителя, затем на его родителя и т.д., Пока не найдет совпадение. Таким образом, кнопки голосования связаны со статьей по содержанию; статья, по которой проводится голосование, содержит кнопки голосования. - Если вы укоренение обработчика событий в элементе глубже страницы (а не на уровне документа), вы, вероятно, следовать за
closest
чеком сcontains
убедитесь, что элемент обработчик присоединен к содержит элемент, который был найден (в случае, если это было найдено в элементе предка вместо этого). Это было бы!voteLink || !this.contains(voteLink)
!voteLink || !this.contains(voteLink)
выше (вместо просто!voteLink
). - Я использую POST, потому что вызов изменяет состояние сервера, поэтому GET не подходит