如何制作类似Stackoverflow的投票按钮?

33 投票
4 回答
7691 浏览
提问于 2025-04-15 11:05

问题

  1. 如何制作一个Ajax按钮(向上和向下的箭头),让数字可以增加或减少
  2. 如何把用户的操作保存到一个变量NumberOfVotesOfQuestionID中

我不太确定是否应该为这个变量使用数据库。不过,我知道还有一种更简单的方法来保存投票的数量。

你能怎么解决这些问题?

[编辑]

服务器端的编程语言是Python。

4 个回答

3

你先创建一些按钮,这些按钮可以是链接、图片或者其他任何东西。然后,把一个JavaScript函数和每个按钮的点击事件连接起来。当你点击按钮时,这个函数就会被触发,

  • 它会向服务器发送一个请求,大致上是告诉服务器加1或者减1。
  • 服务器代码接手处理。这部分会根据你使用的框架(或者不使用框架)以及其他很多因素而大相径庭。
  • 代码会连接到数据库,并执行一个查询来加1或减1分数。具体怎么做会根据你的数据库设计而有所不同,但大致上会像这样:UPDATE posts SET score=score+1 WHERE score_id={{在这里插入ID}};
  • 根据数据库的反馈,服务器会返回一个成功的代码或者失败的代码,作为AJAX请求的响应。
  • 响应会异步发送给AJAX。
  • 如果返回的是成功代码,JS响应函数会更新分数;如果是失败代码,则会显示错误信息。

可以把代码存储在一个变量里,但这比较复杂,取决于你对代码运行环境的理解程度。最终这些数据还是需要存到持久存储中,所以一开始使用数据库是个不错的选择。当需要优化性能的时候,世界上有很多软件可以缓存数据库查询,让你觉得眼花缭乱,所以这并不是个大问题。

8

这里有几点没有人提到:

  • 当你要改变数据库的状态时,不应该使用GET请求。否则,我可以在我的网站上放一张图片,链接是 src="http://stackoverflow.com/question_555/vote/up/answer_3/",这样就能随便投票了。
  • 你还需要有 CSRF(跨站请求伪造)保护
  • 你必须记录每个投票者是谁,这样才能防止同一个人对某个问题投票多次。可以通过IP地址或者用户ID来记录。
60

这段内容是一个用jQuery和Django实现的理论性示例,可能有点脏乱和未经测试。

我们假设这里的投票是针对问题或答案的,就像这个网站上那样,不过你可以根据自己的实际情况进行调整。

模板

<div id="answer_595" class="answer">
  <img src="vote_up.png" class="vote up">
  <div class="score">0</div>
  <img src="vote_down.png" class="vote down">
  Blah blah blah this is my answer.
</div>

<div id="answer_596" class="answer">
  <img src="vote_up.png" class="vote up">
  <div class="score">0</div>
  <img src="vote_down.png" class="vote down">
  Blah blah blah this is my other answer.
</div>

JavaScript

$(function() {
    $('div.answer img.vote').click(function() {
        var id = $(this).parents('div.answer').attr('id').split('_')[1];
        var vote_type = $(this).hasClass('up') ? 'up' : 'down';
        if($(this).hasClass('selected')) {
            $.post('/vote/', {id: id, type: vote_type}, function(json) {
                if(json.success == 'success') {
                    $('#answer_' + id)
                     .find('img.' + vote_type);
                     .attr('src', 'vote_' + vote_type + '_selected.png')
                     .addClass('selected');
                    $('div.score', '#answer_' + id).html(json.score);
                }
            });
        } else {
            $.post('/remove_vote/', {id: id, type: vote_type}, function(json) {
                if(json.success == 'success') {
                    $('#answer_' + id)
                     .find('img.' + vote_type);
                     .attr('src', 'vote_' + vote_type + '.png')
                     .removeClass('selected');
                    $('div.score', '#answer_' + id).html(json.score);
                }
            });                
        }
    });
});

Django视图

def vote(request):
    if request.method == 'POST':
        try:
            answer = Answer.objects.get(pk=request.POST['id'])
        except Answer.DoesNotExist:
            return HttpResponse("{'success': 'false'}")

        try:
            vote = Vote.objects.get(answer=answer, user=request.user)
        except Vote.DoesNotExist:
            pass
        else:
            return HttpResponse("{'success': 'false'}")

        if request.POST['type'] == 'up':
            answer.score = answer.score + 1
        else:
            answer.score = answer.score - 1

        answer.save()

        Vote.objects.create(answer=answer,
                            user=request.user,
                            type=request.POST['type'])

        return HttpResponse("{'success':'true', 'score':" + answer.score + "}")
    else:
        raise Http404('What are you doing here?')

def remove_vote(request):
    if request.method == 'POST':
        try:
            answer = Answer.objects.get(pk=request.POST['id'])
        except Answer.DoesNotExist:
            return HttpResponse("{'success': 'false'}")

        try:
            vote = Vote.objects.get(answer=answer, user=request.user)
        except Vote.DoesNotExist:
            return HttpResponse("{'success': 'false'}")
        else:
            vote.delete()

        if request.POST['type'] == 'up':
            answer.score = answer.score - 1
        else:
            answer.score = answer.score + 1

        answer.save()

        return HttpResponse("{'success':'true', 'score':" + answer.score + "}")
    else:
        raise Http404('What are you doing here?')

哎呀。当我开始回答这个问题时,我没想到会写这么多,结果有点控制不住自己。你还缺少一个初始请求,用来在页面首次加载时获取所有的投票之类的,不过我就留给你自己去做了。总之,如果你确实在使用Django,并且对Stackoverflow投票的更成熟和经过测试的实现感兴趣,我建议你去看看cnprog.com的源代码,这是一个用Python/Django写的中文Stackoverflow克隆网站。他们发布了代码,质量还不错。

撰写回答