Как предотвратить голосование множественным / быстрым кликом в Vue эксплойте? - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть система голосования, которая позволяет пользователям голосовать или не голосовать.

Проблема заключается в том, что пользователь нажимает кнопку голосования несколько раз быстро. Это вызывает странное увеличение числа голосов до go вверх (вниз) (поднимается на 1,2,3, а затем опускается ниже 0, вероятно, связано с голосованием. vue, которое добавляет и вычитает 1 из общее количество голосов, поэтому при нажатии достаточно быстро, это вызывает эту странность).

Кроме того, я позаботился о том, чтобы уникальный идентификатор вопросов и идентификатор пользователя в таблице голосования.

У меня есть эти простые голосования / unvote методов в QuestionController:

/**
 * Vote a question up.
 */
public function voteUp(Question $question)
{
    Auth::user()->votes()->attach($question->id);
}

/**
 * Vote a question down.
 */
public function voteDown(Question $question)
{
    Auth::user()->votes()->detach($question->id);
}

И, возможно, более важным и, вероятно, причиной проблемы является голосование. vue, как вы можете видеть, я добавляю / вычитаю 1 к общему количеству отображаемых голосов.

methods: {
    voteUp(question) {
        axios.post('/voteup/'+question)
            .then(response => this.isVoted = true, this.votes = this.votes + 1)
            .catch(response => console.log(response.data));
    },

    voteDown(question) {
        axios.post('/votedown/'+question)
            .then(response => this.isVoted = false, this.votes = this.votes - 1)
            .catch(response => console.log(response.data));
    }
}

Как мне преодолеть это, чтобы пользователи не могли использовать это + сделать его более стабильным?

РЕДАКТИРОВАТЬ: Я пробовал эти решения, но это не решило проблему:

# 1 - Я пробовал решение @Radu Diță:

<vote 
    :votes="{{ $question->votes()->count() }}"
    :question="{{ $question->id }}"
    :voted="{{ $question->currentUserVoted() ? 'true' : 'false' }}"
    :disabled="voteInAir"
></vote>

и Голосование. vue скрипт:

// resources/js/components/Vote.vue

<template>
    <span>
        <a href="#" v-if="isVoted" @click.prevent="voteDown(question)">
            <i class="fas fa-caret-up fa-3x text-primary vote-effect vote-up-effect"></i>
        </a>
        <a href="#" v-else @click.prevent="voteUp(question)">
            <i class="fas fa-caret-up fa-3x vote-gray vote-effect"></i>
        </a>
        <span class="vote-count-post "><strong>{{ this.votes }}</strong></span>
    </span>
</template>

<script>
    export default {
        props: ['question', 'voted', 'votes'],

        data: function() {
            return {
                isVoted: '',
                voteInAir: false
            }
        },

        mounted() {
            this.isVoted = this.isVote ? true : false;
        },

        computed: {
            isVote() {
                return this.voted;
            },
        },

        methods: {
            voteUp(question) {
                this.voteInAir = true;
                axios.post('/voteup/'+question)
                    .then(response => this.isVoted = true, this.votes = this.votes + 1, this.voteInAir = false)
                    .catch(response => console.log(response.data), this.voteInAir = false);
            },

            voteDown(question) {
                this.voteInAir = true;
                axios.post('/votedown/'+question)
                    .then(response => this.isVoted = false, this.votes = this.votes - 1, this.voteInAir = false)
                    .catch(response => console.log(response.data), this.voteInAir = false);
            }
        }
    }
</script>

# 2 - Я также попытался @ Rijo sh решение:

<vote 
  :votes="{{ $question->votes()->count() }}"
  :question="{{ $question->id }}"
  :voted="{{ $question->currentUserVoted() ? 'true' : 'false' }}"
></vote>

И это с интервалом времени задержка, которая не сработала:

<template>
    <span>
        <a href="#" v-if="isVoted" @click.prevent="voteDown(question)">
            <i class="fas fa-caret-up fa-3x text-primary vote-effect vote-up-effect"></i>
        </a>
        <a href="#" v-else @click.prevent="voteUp(question)">
            <i class="fas fa-caret-up fa-3x vote-gray vote-effect"></i>
        </a>
        <span class="vote-count-post "><strong>{{ this.votes }}</strong></span>
    </span>
</template>

<script>
    export default {
        props: ['question', 'voted', 'votes'],

        data: function() {
            return {
                isVoted: '',
                timer: null,
                interval: 200,
            }
        },

        mounted() {
            this.isVoted = this.isVote ? true : false;
        },

        computed: {
            isVote() {
                return this.voted;
            },
        },

        methods: {
            voteUp(question) {
                clearTimeout(this.timer);
                this.timer = setTimeout(() => {
                    axios.post('/voteup/'+question)
                        .then(response => this.isVoted = true, this.votes = this.votes + 1)
                        .catch(response => console.log(response.data));
                }, this.interval);
            },

            voteDown(question) {
                clearTimeout(this.timer);
                this.timer = setTimeout(() => {
                    axios.post('/votedown/'+question)
                        .then(response => this.isVoted = false, this.votes = this.votes - 1)
                        .catch(response => console.log(response.data));
                }, this.interval);
            }
        }
    }
</script>

Ответы [ 3 ]

0 голосов
/ 15 апреля 2020

Попробуйте это решение

Шаблон

    <div>
        <button @click="voteUp">UpVote</button>
        <button @click="voteDown">DownVote</button>
    </div>

Данные

    data: () => {
        return {
            timer: null,
            interval: 200
        }
    },

Методы

    methods: {
        voteUp: function () {
            clearTimeout(this.timer);
            this.timer = setTimeout(() => {
                console.log('up vote')
                // your action
            }, this.interval);
        },

        voteDown: function () {
            clearTimeout(this.timer);
            this.timer = setTimeout(() => {
                console.log('down vote')
                // your action
            }, this.interval);
        }
    }

Я использую setTimeout и clearTimeout в методах. Это предотвратит последовательные действия на кнопках. Непрерывные клики вызовут только одно действие. Время между каждым кликом можно контролировать с помощью значения interval в data.

0 голосов
/ 15 апреля 2020

Вы должны отключить кнопку после ее нажатия и включить ее снова после получения ответа. Это можно использовать для любой кнопки, которую вы не хотите отключать спамом.

В вашем data добавьте логическое значение для каждой кнопки

data () {
  return {
    //other data
    upVoteInAir: false
  }
}

, затем свяжите свою кнопку в соответствии с флагом

<button :disabled="upVoteInAir">Up</button>

обновить флаг на основе http-запроса

methods: {
    voteUp(question) {
        this.upVoteInAir = true
        axios.post('/voteup/'+question)
            .then(response => this.isVoted = true, this.votes = this.votes + 1,         this.upVoteInAir = false)
            .catch(response => console.log(response.data),         this.upVoteInAir = false);
    },
}
0 голосов
/ 15 апреля 2020

Так как вы разрешаете только один голос (или это то, что я понимаю), я бы не увеличивал количество голосов напрямую, а создавал бы систему с логическими значениями вроде этого:

<button v-on:click="activateUpVote">UpVote</button>
<button v-on:click="activateDownVote">DownVote</button>
.
.
.
data(){
  return{
    upVote: false,
    downVote: false,
    hasVoted: false
  }
},
methods: {
  activateUpVote(){
    this.upVote = !this.upVote
    if(this.upVote && (!this.hasVoted || this.downVote)){
      this.downVote = false
      this.hasVoted = true
      this.vote('/votedown/'+this.question, this.votes + 1)
    }else{
      this.hasVoted = false
    }
  },
  //downVote same as above but the other way around except for the hasVoted part          
  vote(route, votes) {
    axios.post(route)
        .then(response => votes)
        .catch(response => console.log(response.data));
    },
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...