【问题标题】:How can I implement up and down voting? [closed]如何实施上下投票? [关闭]
【发布时间】:2011-09-11 10:45:56
【问题描述】:

如果你用过Stack Overflow,你肯定用过问答的上下投票功能。我注意到 Stack Overflow 使用 <a> 锚点。但我不知道如何将数据发布到服务器。我认为这是与此 <a> 相关联的 JavaScript,但我找不到它。如何实现?

【问题讨论】:

  • 我认为这个问题是合法的,没有理由关闭。
  • 在 Google 上搜索“Ajax”,探索、探索和探索,一个全新的世界为您打开!
  • 我很高兴我们有版主可以保护我们免受这个可怕的问题的影响。

标签: javascript php post


【解决方案1】:

是的,涉及到 JavaScript。有两个部分:为投票“按钮”上的点击事件连接一个处理程序,并将数据发送到服务器。

连接事件在其他地方已经很好地介绍了,我不会在这里讨论它。 (例如,我在this answer 中介绍了它。)

发送数据到服务器,可以使用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 的链接会被浏览器(标签目标等)特殊处理,因此这对于可访问性很有用。 (要真正做到这一点,我可能还必须将文章 ID 放在 href 中。)
  • 我将我们要投票的项目的 ID 存储在 data- attribute 中。
  • 我们通过将“最接近”的文章定位到被点击的按钮来找到要投票的项目。 DOM 的 closest 函数从元素开始并检查该元素以查看它是否适合给定的 CSS 选择器,如果不适合则查看其父级,然后查看 父级,等等,直到找到匹配。所以投票按钮通过包含与文章相关联;被投票的文章包含投票按钮。
  • 如果您将事件处理程序植根于页面更深处(而不是文档级别)的元素中,您可能会遵循closest 检查和contains 检查以确保附加处理程序的元素to 包含找到的元素(如果它是在祖先元素中找到的)。那将是上面的!voteLink || !this.contains(voteLink)(而不仅仅是!voteLink)。
  • 我使用 POST 因为调用改变了服务器状态,所以 GET 不合适

【讨论】:

  • 是的。我知道阿贾克斯。但我不知道stackoverflow 的上下投票如何与ajax 相关联。您查看上下投票的源代码。它只是一个没有名称和 ID 的“”锚。
  • @Magic:我在答案中添加了一个示例,可能会更清楚。
  • 从 jQuery 1.7 开始,不推荐使用 .live() 方法。使用 .on() 附加事件处理程序。旧版本 jQuery 的用户应该使用 .delegate() 而不是 .live()。
  • @ScottFleming - 哈哈,哇,这是一个真的老答案,不是吗? :-) 距离我编写 jQuery 1.7 的时间还有五个月。感谢您标记它。来晚了,明天更新。
  • @T.J.Crowder 这对我来说已经足够了,我曾经创建自己的版本,经过一些调整后运行良好。如果你喜欢,我可以分享。
【解决方案2】:

查看Ajax

【讨论】:

    【解决方案3】:

    您可以使用 jquery 来完成。 只需在向上/向下箭头上应用单击事件侦听器,这将使用 ajax 将数据发送到您的服务器。

    您服务器上的脚本将验证数据库中的传入数据和更新计数。 然后你可以发回一个回复,给出更新的上升/下降计数

    注意:您还必须考虑到用户只能喜欢或不喜欢一次。 您可以在服务器端处理它/或为简单起见将其存储在 cookie 中。

    【讨论】:

    【解决方案4】:

    Magic 是正确的,您希望使用 AJAX,这是一种允许您在不完全发布页面的情况下从页面到服务器来回发送数据的技术。

    如果您想要一篇好的文章来帮助您入门,我会在 Nettuts 上查看这篇文章:5 ways to make ajax call with jquery

    在我看来,使用 jQuery 是从 javascript 发布和获取数据的最简单方法。

    干杯

    【讨论】:

    【解决方案5】:

    投票功能需要两个部分:

    1. 客户端 这个处理投票的视觉部分。您拥有的按钮可以是跨度、链接、图像或任何 HTML 元素。 Javascript 用于向该元素注册一个操作,因此当有人向上或向下单击时,Javascript 将知道单击了哪个按钮。

    2. 服务器端 在服务器端,您需要存储投票的逻辑。您将需要一个表来存储结果并将投票连接到用户和数据库中的某个帖子。您将需要一些与此投票相关的功能,例如:

      function saveVote ($user_id, $post_id) {...}
      // or
      function getPostVotes ($post_id) {...}
      // or
      function getUserVotes ($user_id) {...}
      

    连接这两个部分的原因是 Emil 建议的 Ajax。尽管这是当今最常见的表单,但您甚至可以使用简单的表单或 iframe 或其他技术将信息传递到服务器。它们都做同样的事情,就是将投票参数(如 post_id 和 user_id 和 vote_result)传递给一个 php 脚本,该脚本会将它们保存到数据库中。作为确认投票真实并保存后的额外步骤,您可以增加/减少页面中的投票计数。

    【讨论】:

    • 是的。我知道阿贾克斯。但我不知道stackoverflow 的上下投票如何与ajax 相关联。您查看上下投票的源代码。它只是一个没有名称和 ID 的“”锚。
    • 名称可以存储在 cookie 中,该 cookie 也随请求一起发送。并记住事件会冒泡,因此另一个有趣的信息可以来自上层。例如,标签的 prev 是一个隐藏在 post 值中的输入。
    猜你喜欢
    • 2012-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    相关资源
    最近更新 更多