Laravel Vuejs 实战:开发知乎 (27)对答案进行点赞

1.建表

用户与回答点赞的关系表【多对多关系】

  1 php artisan make:model Vote -m
  1 <?php
  2 
  3 use IlluminateDatabaseMigrationsMigration;
  4 use IlluminateDatabaseSchemaBlueprint;
  5 use IlluminateSupportFacadesSchema;
  6 
  7 class CreateVotesTable extends Migration
  8 {
  9     /**
 10      * Run the migrations.
 11      *
 12      * @return void
 13      */
 14     public function up()
 15     {
 16         Schema::create('votes', function (Blueprint $table) {
 17             $table->bigIncrements('id');
 18             $table->unsignedBigInteger('user_id')->index()->comment("点赞用户的id");
 19             $table->unsignedBigInteger('answer_id')->index()->comment("被赞答案的id");
 20             $table->timestamps();
 21         });
 22         Schema::table('votes', function (Blueprint $table) {
 23             //用户表中用户被删除的时候,同步删除votes表user_id列对应的数据行
 24             $table
 25                 ->foreign('user_id')//本表有一个user_id列
 26                 ->references('id')//指向了id列
 27                 ->on('users')//users表中的那个id列
 28                 ->onDelete('cascade');//users表中id列里面任意一个id数据删除的时候,删除本votes表user_id列对应的数据行
 29 
 30             //答案表中答案被删除的时候,同步删除votes表answer_id对应的数据行
 31             $table
 32                 ->foreign('answer_id')//本表有一个answer_id列
 33                 ->references('id')//指向了id列
 34                 ->on('answers')//answers表中的那个id列
 35                 ->onDelete('cascade');//answers表中id列里面任意一个id数据删除的时候,删除本votes表answer_id列对应的数据行
 36         });
 37     }
 38 
 39     /**
 40      * Reverse the migrations.
 41      *
 42      * @return void
 43      */
 44     public function down()
 45     {
 46         Schema::dropIfExists('votes');
 47     }
 48 }
 49 
 50 
  1 php artisan migrate

参照:Migration Foreign Key Vs Eloquent Relationships in Laravel 强调一下,Eloquent关系和Migration必须同时创建,但是外键约束视情况而定。 Laravel Relationship - Foreign key delete

2.模型关联:

User.php中添加:

  1 public function votes()
  2 {
  3     return $this->belongsToMany(Answer::class, 'votes')->withTimestamps();
  4 }
  5 

Answer.php中添加:

  1 public function users()
  2 {
  3     return $this->belongsToMany(User::class, 'votes')->withTimestamps();
  4 }
  5 

注意 表名由于不是laravel默认的格式,所以要自己设置表名

  1 <?php
  2 
  3 namespace App;
  4 
  5 use AppModelsQuestion;
  6 use IlluminateDatabaseEloquentModel;
  7 use IlluminateDatabaseEloquentSoftDeletes;
  8 
  9 class Answer extends Model
 10 {
 11     #region 支持软删除添加
 12     use SoftDeletes;
 13     protected $dates = ['deleted_at'];
 14 
 15     #endregion
 16 
 17     protected $fillable = ['user_id', 'question_id', 'content'];
 18 
 19     /** 一个回答只有一个回答主人
 20      * @return IlluminateDatabaseEloquentRelationsBelongsTo
 21      */
 22     public function user()
 23     {
 24         return $this->belongsTo(User::class);
 25     }
 26 
 27     /** 一个回答只针对一个问题
 28      * @return IlluminateDatabaseEloquentRelationsBelongsTo
 29      */
 30     public function question()
 31     {
 32         return $this->belongsTo(Question::class);
 33     }
 34 
 35     /**
 36      * @return IlluminateDatabaseEloquentRelationsBelongsToMany
 37      */
 38     public function userVotes()
 39     {
 40         return $this->belongsToMany(User::class, 'votes')->withTimestamps();
 41     }
 42 }
 43 
 44 
Answer.php


最好在User.php中添加上voteAnswer方法,更方便:

  1 public function voteAnswer($answer_id)
  2 {
  3     return $this->votes()->toggle($answer_id);
  4 }
  5 
  1 <?php
  2 
  3 namespace App;
  4 
  5 use AppModelsQuestion;
  6 use IlluminateContractsAuthMustVerifyEmail;
  7 use IlluminateDatabaseEloquentSoftDeletes;
  8 use IlluminateFoundationAuthUser as Authenticatable;
  9 use IlluminateNotificationsNotifiable;
 10 
 11 class User extends Authenticatable implements MustVerifyEmail
 12 {
 13     use Notifiable;
 14     #region 支持软删除
 15     use SoftDeletes;
 16     protected $dates = ['deleted_at'];
 17     #endregion
 18     /**
 19      * The attributes that are mass assignable.
 20      *
 21      * @var array
 22      */
 23     protected $fillable = [
 24         'name', 'email', 'password', 'avatar', 'activation_token', 'api_token'
 25     ];
 26 
 27     /**
 28      * The attributes that should be hidden for arrays.
 29      *
 30      * @var array
 31      */
 32     protected $hidden = [
 33         'password', 'remember_token',
 34     ];
 35 
 36     /**
 37      * The attributes that should be cast to native types.
 38      *
 39      * @var array
 40      */
 41     protected $casts = [
 42         'email_verified_at' => 'datetime',
 43     ];
 44 
 45 
 46     /**添加用户模型和问题模型的模型关联
 47      * @return IlluminateDatabaseEloquentRelationsHasMany
 48      */
 49     public function questions()
 50     {
 51         return $this->hasMany(Question::class);
 52     }
 53 
 54 
 55     /** 添加用户模型和回答模型的模型关联 一个用户可以有多个回答
 56      * @return IlluminateDatabaseEloquentRelationsHasMany
 57      */
 58     public function answers()
 59     {
 60         return $this->hasMany(Answer::class);
 61     }
 62 
 63 
 64     public function followQuestions()
 65     {
 66         //默认表名 可以不设置后面三个参数,自定义表名需要设置
 67         return $this->belongsToMany(Question::class, 'users_questions', 'question_id', 'user_id')->withTimestamps();
 68     }
 69 
 70 
 71     /** 用户的粉丝
 72      * @return IlluminateDatabaseEloquentRelationsBelongsToMany
 73      */
 74     public function followers()
 75     {
 76 
 77         return $this->belongsToMany
 78         (
 79             self::class,
 80             'followers',
 81             'user_id', //foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是leader】的外键id
 82             'follower_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键)
 83         )->withTimestamps();
 84     }
 85 
 86 
 87     /** 用户关注的作者
 88      * @return IlluminateDatabaseEloquentRelationsBelongsToMany
 89      */
 90     public function followings()
 91     {
 92         return $this->belongsToMany
 93         (
 94             self::class,
 95             'followers',
 96             'follower_id',//foreignPivotKey:当前模型在中间表的字段(当前模型类的外键) //【当前模型是粉丝】的外键id
 97             'user_id'//relatedPivotKey:另一模型在中间表的字段(另一模型类的外键)
 98         )
 99             ->withTimestamps();
100     }
101 
102 
103     /**
104      * @return IlluminateDatabaseEloquentRelationsBelongsToMany
105      */
106     public function votes()
107     {
108         return $this->belongsToMany(Answer::class, 'votes')->withTimestamps();
109     }
110 
111 
112     /**
113      * @param $answer_id
114      * @return array
115      */
116     public function voteAnswer($answer_id)
117     {
118         return $this->votes()->toggle($answer_id);
119     }
120 }
121 
122 
User.php

3.视图层面:直接使用vue组件:

  1 <template>
  2     <button :class="classObject"
  3             @click="up"
  4             v-text="text">
  5     </button>
  6 </template>
  7 
  8 <script>
  9     export default {
 10         props: ['answer'],
 11         name: "UserVoteButton",
 12         data() {
 13             return {
 14                 voteable: true,
 15             }
 16         },
 17         computed: {
 18             text() {
 19                 return this.voteable ? "点赞" : "取消赞";
 20             },
 21             classObject() {
 22                 return this.voteable ? "btn btn-sm btn-secondary" : "btn btn-sm btn-danger";
 23             },
 24         },
 25         mounted: function () {
 26             let currentObj = this;
 27             axios.post('/api/answers/vote/stats', {'answer': this.answer})
 28                 .then(function (response) {
 29                     currentObj.voteable = response.data.voteable;
 30                 })
 31                 .catch(function (e) {
 32                     console.log(e);
 33                 });
 34         },
 35         methods: {
 36             up() {
 37                 let currentObj = this;
 38                 axios.post('/api/answers/vote/up', {'answer': this.answer})
 39                     .then(function (response) {
 40                             currentObj.voteable = response.data.voteable;
 41                         }
 42                     )
 43                     .catch(function (e) {
 44                         console.log(e);
 45                     });
 46             },
 47             //暂时不写踩的
 48             down() {
 49                 let currentObj = this;
 50                 axios.post('/api/answers/vote/down', {'answer': this.answer})
 51                     .then(function (response) {
 52                             currentObj.voteable = response.data.voteable;
 53                         }
 54                     )
 55                     .catch(function (e) {
 56                         console.log(e);
 57                     });
 58             },
 59         }
 60     }
 61 </script>
 62 
 63 <style scoped>
 64 
 65 </style>
 66 
 67 
UserVoteButton
  1 /**
  2  * First we will load all of this project's JavaScript dependencies which
  3  * includes Vue and other libraries. It is a great starting point when
  4  * building robust, powerful web applications using Vue and Laravel.
  5  */
  6 
  7 require('./bootstrap');
  8 require('../../vendor/select2/select2/dist/js/select2.js');
  9 // 将views/vendor/ueditor/assets.blade.php中的引用换到本处
 10 require('../../public/vendor/ueditor/ueditor.config.js');
 11 require('../../public/vendor/ueditor/ueditor.all.js');
 12 
 13 window.Vue = require('vue');
 14 
 15 /**
 16  * The following block of code may be used to automatically register your
 17  * Vue components. It will recursively scan this directory for the Vue
 18  * components and automatically register them with their "basename".
 19  *
 20  * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
 21  */
 22 
 23 // const files = require.context('./', true, /.vue$/i)
 24 // files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
 25 
 26 // Vue.component('example-component', require('./components/ExampleComponent.vue').default);
 27 Vue.component('question-follow-button', require('./components/QuestionFollowButton').default);
 28 Vue.component('user-follow-button', require('./components/UserFollowButton').default);
 29 Vue.component('user-vote-button', require('./components/UserVoteButton').default);
 30 /**
 31  * Next, we will create a fresh Vue application instance and attach it to
 32  * the page. Then, you may begin adding components to this application
 33  * or customize the JavaScript scaffolding to fit your unique needs.
 34  */
 35 
 36 const app = new Vue({
 37     el: '#app',
 38 });
 39 
 40 
app.js
  1 @extends('layouts.app')
  2 @section('content')
  3     <div class="container">
  4         <div class="row">
  5             <div class="col-md-8 col-md offset-1">
  6                 {{--问题--}}
  7                 <div class="card">
  8                     <div class="card-header">
  9                         {{ $question->title }}
 10 
 11                         @foreach(['success','warning','danger'] as $info)
 12                             @if(session()->has($info))
 13                                 <div class="alert alert-{{$info}}">{{ session()->get($info) }}</div>
 14                             @endif
 15                         @endforeach
 16 
 17                         @can('update',$question)
 18                             <a href="{{ route('questions.edit',$question) }}" class="btn btn-warning">编辑</a>
 19                         @endcan
 20 
 21                         @can('destroy',$question)
 22                             <form action="{{ route('questions.destroy',$question) }}" method="post">
 23                                 @csrf
 24                                 @method('DELETE')
 25                                 <button type="submit" class="btn btn-danger">删除</button>
 26                             </form>
 27                         @endcan
 28 
 29                         @forelse($question->topics as $topic)
 30                             <button class="btn btn-secondary float-md-right m-1">{{ $topic->name }}</button>
 31                         @empty
 32                             <p class="text text-warning float-md-right"> "No Topics"</p>
 33                         @endforelse
 34 
 35                         <p class="text text-info float-md-right"> 已有{{ count($question->answers) }}个回答</p>
 36 
 37                     </div>
 38                     <div class="card-body">
 39                         {!! $question->content !!}
 40                     </div>
 41                 </div>
 42 
 43 
 44                 {{--回答提交form--}}
 45                 {{--只有登录用户可以提交回答--}}
 46                 @if(auth()->check())
 47                     <div class="card mt-2">
 48                         <div class="card-header">
 49                             提交回答
 50                         </div>
 51                         <div class="card-body">
 52                             <form action="{{ route('answers.store',$question) }}" method="post">
 53                             @csrf
 54                             <!-- 回答编辑器容器 -->
 55                                 <script id="container" name="content" type="text/plain"
 56                                         style=" 100%;height: 200px">{!! old('content') !!}</script>
 57                                 <p class="text text-danger"> @error('content') {{ $message }} @enderror </p>
 58                                 <!--提交按钮-->
 59                                 <button type="submit" class="btn btn-primary float-md-right mt-2">提交回答</button>
 60                             </form>
 61                         </div>
 62                     </div>
 63                 @else
 64                     {{--显示请登录--}}
 65                     <a href="{{ route('login') }}" class="btn btn-success btn-block mt-4">登录提交答案</a>
 66                 @endif
 67                 {{--展示答案--}}
 68                 @forelse($question->answers as $answer)
 69                     <div class="card mt-4">
 70                         <div class="card-header">
 71                             @include('users._small_icon',['userable'=>$answer])
 72                             <span class="float-right text text-info text-center">
 73                                 {{ $answer->updated_at->diffForHumans() }}</span>
 74                             @if(auth()->check())
 75                                 <user-vote-button answer="{{ $answer->id }}" class="float-right"></user-vote-button>
 76                             @endif
 77                         </div>
 78 
 79                         <div class="card-body">
 80                             {!!  $answer->content  !!}
 81                         </div>
 82                     </div>
 83 
 84                 @empty
 85 
 86                 @endforelse
 87             </div>
 88 
 89             <div class="col-md-3">
 90                 <div class="card">
 91                     <div class="card-header">
 92                         <h2> {{ $question->followers_count }}</h2>
 93                         <span>关注者</span>
 94                     </div>
 95                     <div class="card-body">
 96                         <question-follow-button question="{{$question->id}}"id}}">
 97                         </question-follow-button>
 98                     </div>
 99                 </div>
100 
101                 <div class="card mt-4">
102                     <div class="card-header">
103                         <h2> 提问者 </h2>
104                     </div>
105                     <div class="card-body">
106                         @include('users._small_icon',['userable'=>$question])
107                     </div>
108                     @include('users._user_stats')
109                 </div>
110             </div>
111 
112 
113         </div>
114     </div>
115 @endsection
116 @section('footer-js')
117     @include('questions._footer_js')
118 @endsection
119 
120 
show.blade.php

api.php:

  1 <?php
  2 
  3 use IlluminateHttpRequest;
  4 
  5 /*
  6 |--------------------------------------------------------------------------
  7 | API Routes
  8 |--------------------------------------------------------------------------
  9 |
 10 | Here is where you can register API routes for your application. These
 11 | routes are loaded by the RouteServiceProvider within a group which
 12 | is assigned the "api" middleware group. Enjoy building your API!
 13 |
 14 */
 15 
 16 Route::middleware('auth:api')->get('/user', function (Request $request) {
 17     return $request->user();
 18 });
 19 
 20 Route::middleware('api')->get('/topics', function (Request $request) {
 21     $query = $request->query('q');
 22     return AppTopic::query()->where('name', 'like', '%' . $query . '%')->get();
 23 });
 24 #region 问题关注
 25 //加载页面时取关注状态
 26 Route::middleware('auth:api')->post('/questions/follow/stats', 'QuestionController@getFollowStats');
 27 //执行关注/取关操作
 28 Route::middleware('auth:api')->post('/questions/follow', 'QuestionController@followThroughApi');
 29 #endregion
 30 
 31 #region 用户关注
 32 //加载页面时取关注状态
 33 Route::middleware('auth:api')->post('/users/follow/stats', 'FollowerController@getFollowStats');
 34 //执行关注/取关操作
 35 Route::middleware('auth:api')->post('/users/follow', 'FollowerController@followThroughApi');
 36 
 37 #endregion
 38 
 39 
 40 #region
 41 //加载页面时取赞状态
 42 Route::middleware('auth:api')->post('/answers/vote/stats', 'VoteController@getVoteStats');
 43 //执行赞/取消赞操作
 44 Route::middleware('auth:api')->post('/answers/vote/up', 'VoteController@voteUpThroughApi');
 45 #endregion
 46 
 47 
api.php

4.控制器:

  1 php artisan make:controller VoteController

VoteController.php:

  1 <?php
  2 
  3 namespace AppHttpControllers;
  4 
  5 use AppAnswer;
  6 use IlluminateHttpRequest;
  7 
  8 class VoteController extends Controller
  9 {
 10     //
 11     public function __construct()
 12     {
 13         $this->middleware('auth');
 14     }
 15 
 16 
 17     public function getVoteStats(Request $request)
 18     {
 19         $answer = Answer::find($request->get('answer'));
 20 
 21         $user = auth()->user();
 22 
 23         //是否可以点赞
 24         return response()->json(
 25             [
 26                 'voteable' => !($user->votes->contains('id', $answer->id))
 27             ]
 28         );
 29     }
 30 
 31     public function voteUpThroughApi(Request $request)
 32     {
 33         $answer = Answer::find($request->get('answer'));
 34 
 35         $user = auth()->user();
 36 
 37         $user->voteAnswer($answer->id);
 38 
 39         //是否可以点赞
 40         return response()->json(
 41             [
 42                 'voteable' => !($user->votes->contains('id', $answer->id))
 43             ]
 44         );
 45     }
 46 }
 47 
 48 
VoteController.php

5.如果要对赞进行计数:

  1 @extends('layouts.app')
  2 @section('content')
  3     <div class="container">
  4         <div class="row">
  5             <div class="col-md-8 col-md offset-1">
  6                 {{--问题--}}
  7                 <div class="card">
  8                     <div class="card-header">
  9                         {{ $question->title }}
 10 
 11                         @foreach(['success','warning','danger'] as $info)
 12                             @if(session()->has($info))
 13                                 <div class="alert alert-{{$info}}">{{ session()->get($info) }}</div>
 14                             @endif
 15                         @endforeach
 16 
 17                         @can('update',$question)
 18                             <a href="{{ route('questions.edit',$question) }}" class="btn btn-warning">编辑</a>
 19                         @endcan
 20 
 21                         @can('destroy',$question)
 22                             <form action="{{ route('questions.destroy',$question) }}" method="post">
 23                                 @csrf
 24                                 @method('DELETE')
 25                                 <button type="submit" class="btn btn-danger">删除</button>
 26                             </form>
 27                         @endcan
 28 
 29                         @forelse($question->topics as $topic)
 30                             <button class="btn btn-secondary float-md-right m-1">{{ $topic->name }}</button>
 31                         @empty
 32                             <p class="text text-warning float-md-right"> "No Topics"</p>
 33                         @endforelse
 34 
 35                         <p class="text text-info float-md-right"> 已有{{ count($question->answers) }}个回答</p>
 36 
 37                     </div>
 38                     <div class="card-body">
 39                         {!! $question->content !!}
 40                     </div>
 41                 </div>
 42 
 43 
 44                 {{--回答提交form--}}
 45                 {{--只有登录用户可以提交回答--}}
 46                 @if(auth()->check())
 47                     <div class="card mt-2">
 48                         <div class="card-header">
 49                             提交回答
 50                         </div>
 51                         <div class="card-body">
 52                             <form action="{{ route('answers.store',$question) }}" method="post">
 53                             @csrf
 54                             <!-- 回答编辑器容器 -->
 55                                 <script id="container" name="content" type="text/plain"
 56                                         style=" 100%;height: 200px">{!! old('content') !!}</script>
 57                                 <p class="text text-danger"> @error('content') {{ $message }} @enderror </p>
 58                                 <!--提交按钮-->
 59                                 <button type="submit" class="btn btn-primary float-md-right mt-2">提交回答</button>
 60                             </form>
 61                         </div>
 62                     </div>
 63                 @else
 64                     {{--显示请登录--}}
 65                     <a href="{{ route('login') }}" class="btn btn-success btn-block mt-4">登录提交答案</a>
 66                 @endif
 67                 {{--展示答案--}}
 68                 @forelse($question->answers as $answer)
 69                     <div class="card mt-4">
 70                         <div class="card-header">
 71                             @include('users._small_icon',['userable'=>$answer])
 72                             <span class="float-right text text-info text-center">
 73                                 {{ $answer->updated_at->diffForHumans() }}</span>
 74                             @if(auth()->check())
 75                                 <user-vote-button answer="{{ $answer->id }}" vote_count="{{ $answer->userVotes->count() }}" class="float-right"></user-vote-button>
 76                             @endif
 77                         </div>
 78 
 79                         <div class="card-body">
 80                             {!!  $answer->content  !!}
 81                         </div>
 82                     </div>
 83 
 84                 @empty
 85 
 86                 @endforelse
 87             </div>
 88 
 89             <div class="col-md-3">
 90                 <div class="card">
 91                     <div class="card-header">
 92                         <h2> {{ $question->followers_count }}</h2>
 93                         <span>关注者</span>
 94                     </div>
 95                     <div class="card-body">
 96                         <question-follow-button question="{{$question->id}}"id}}">
 97                         </question-follow-button>
 98                     </div>
 99                 </div>
100 
101                 <div class="card mt-4">
102                     <div class="card-header">
103                         <h2> 提问者 </h2>
104                     </div>
105                     <div class="card-body">
106                         @include('users._small_icon',['userable'=>$question])
107                     </div>
108                     @include('users._user_stats')
109                 </div>
110             </div>
111 
112 
113         </div>
114     </div>
115 @endsection
116 @section('footer-js')
117     @include('questions._footer_js')
118 @endsection
119 
120 
show.blade.php
  1 <template>
  2     <button :class="classObject"
  3             @click="up"
  4             v-text="text">
  5     </button>
  6 </template>
  7 
  8 <script>
  9     export default {
 10         props: ['answer', 'vote_count'],
 11         name: "UserVoteButton",
 12         data() {
 13             return {
 14                 voteable: true,
 15                 vote_count: this.vote_count,
 16             }
 17         },
 18         computed: {
 19             text() {
 20                 return this.vote_count;
 21             },
 22             classObject() {
 23                 return this.voteable ? "btn btn-sm btn-secondary" : "btn btn-sm btn-danger";
 24             },
 25         },
 26         mounted: function () {
 27             let currentObj = this;
 28             axios.post('/api/answers/vote/stats', {'answer': this.answer})
 29                 .then(function (response) {
 30                     currentObj.voteable = response.data.voteable;
 31                     currentObjvote_count = response.data.vote_count;
 32                 })
 33                 .catch(function (e) {
 34                     console.log(e);
 35                 });
 36         },
 37         methods: {
 38             up() {
 39                 let currentObj = this;
 40                 axios.post('/api/answers/vote/up', {'answer': this.answer})
 41                     .then(function (response) {
 42                             currentObj.voteable = response.data.voteable;
 43                             currentObj.vote_count = response.data.vote_count;
 44                         }
 45                     )
 46                     .catch(function (e) {
 47                         console.log(e);
 48                     });
 49             },
 50             //暂时不写踩的
 51             down() {
 52                 let currentObj = this;
 53                 axios.post('/api/answers/vote/down', {'answer': this.answer})
 54                     .then(function (response) {
 55                             currentObj.voteable = response.data.voteable;
 56                         }
 57                     )
 58                     .catch(function (e) {
 59                         console.log(e);
 60                     });
 61             },
 62         }
 63     }
 64 </script>
 65 
 66 <style scoped>
 67 
 68 </style>
 69 
 70 
UserVoteButton.vue
  1 <?php
  2 
  3 namespace AppHttpControllers;
  4 
  5 use AppAnswer;
  6 use IlluminateHttpRequest;
  7 
  8 class VoteController extends Controller
  9 {
 10     //
 11     public function __construct()
 12     {
 13         $this->middleware('auth');
 14     }
 15 
 16 
 17     public function getVoteStats(Request $request)
 18     {
 19         $answer = Answer::find($request->get('answer'));
 20 
 21         $user = auth()->user();
 22 
 23         //是否可以点赞
 24         return response()->json(
 25             [
 26                 'voteable' => !($user->votes->contains('id', $answer->id)),
 27                 'vote_count' => $answer->userVotes->count(),
 28             ]
 29         );
 30     }
 31 
 32     public function voteUpThroughApi(Request $request)
 33     {
 34         $answer = Answer::find($request->get('answer'));
 35 
 36         $user = auth()->user();
 37 
 38         $user->voteAnswer($answer->id);
 39 
 40         //是否可以点赞
 41         return response()->json(
 42             [
 43                 'voteable' => !($user->votes->contains('id', $answer->id)),
 44                 'vote_count' => $answer->userVotes->count(),
 45             ]
 46         );
 47     }
 48 }
 49 
 50 
VoteController.php
原文地址:https://www.cnblogs.com/dzkjz/p/12399221.html