前回の記事の続きみたいなものです。Laravel7.x系です。
まだ読んでいない方はぜひそちらからみてください。今回はコードを前回のものに付け足していく形になります。
大まかな流れ
ルーティング設定
モデル(メソッド追加)
コントローラー(アクション追加)
コンポーネント(作成)
コンポーネント(追加)
vuex(メソッド追加)
上記のような流れで実装していきます。
目次
ルーティング設定
以前のコードの下に下記を追加します。
Route::get('/user/{user}/follow_list', 'UserController@follow_list')->name('follow_list');
Route::get('/user/{user}/follower_list', 'UserController@follower_list')->name('follower_list');
モデル(メソッド追加)
以前のコードの下に下記を追加します。
public function follows()
{
#1 return $this->belongsToMany(self::class, 'follows', 'following_id', 'followed_id');
}
public function followers()
{
#2 return $this->belongsToMany(self::class, 'follows', 'followed_id', 'following_id');
}
#1, これはフォローしているユーザーを取得しています。
#2, これはフォロワーのユーザーを取得しています。
$thisはその時によってログインしているユーザーだったり、そうでなかったりします。
コントローラー(アクション追加)
以前のコードの下に下記を追加します。
public function follow_list(User $user)
{
#1 $follow_list = $user->follows()->get();
return $follow_list;
}
public function follower_list(User $user)
{
#2 $follower_list = $user->followers()->get();
return $follower_list;
}
#1, これは先ほどモデルに設定したメソッドを呼び出してフォローしているユーザーを取得しています。
#2, こちらも同様にメソッドを呼び出してフォロワーを取得しています。
ビューにも追加(blade,app.js)
以下を以前作成したファイルに書き加えます。
いくつか情報も渡しています。
<div class="profile-content">
<follow-list user_id="{{$user->id}}" login_user_id="{{Auth::id()}}" csrf="{{json_encode(csrf_token())}}"></follow-list>
<follower-list user_id="{{$user->id}}" login_user_id="{{Auth::id()}}" csrf="{{json_encode(csrf_token())}}"></follower-list>
</div>
app.jsに書き込み
Vue.component('follow-list', require('./components/FollowList.vue').default);
Vue.component('follower-list', require('./components/FollowerList.vue').default);
コンポーネント(作成)
新規コンポーネントを作成します。
フォローリスト
created()でフォロー一覧を取得。v-forで表示させている形ですね。
<template>
<div class="bg-light px-4 py-3">
<h5>フォロー</h5>
<hr>
<div v-for="follow_user in follow_users" :key="follow_user.id">
<div class="col-12 row my-2">
<img :src="follow_user.avatar" style="width: 40px; height: 40px; border-radius: 50%!important;" class="img-responsive" alt="">
<p class="pt-2 ml-3" style="font-size: 1rem; cursor: pointer;">
{{follow_user.name}}
</p>
<div v-if="follow_user.id != login_user_id">
<form @submit.prevent="send(follow_user.id)">
<input type="hidden" name="_token" v-bind:value="csrf" v-show="check_user(follow_user.id)">
#1 <div v-if="check">
<button type="submit" class="mt-2 ml-2 btn btn-outline-primary btn-sm" style="height: 1.7rem;">Unfollow</button>
</div>
<div v-else>
<button type="submit" class="mt-2 ml-2 btn btn-outline-primary btn-sm" style="height: 1.7rem;">Follow</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
data() {
return {
check: false
}
},
props: ['csrf', 'user_id', 'login_user_id'],
computed: {
...mapState("follow", ['follow_users'])
},
created() {
this.$store.dispatch('follow/get_follow_list', this.user_id)
},
methods: {
send(id){
this.$store.dispatch('follow/follow_do', id)
this.$store.dispatch('follow/get_follow_list', this.user_id)
#2 this.$store.dispatch('follow/get_follower_list', this.user_id)
},
#3 check_user(id) {
var array = ["/user/", id, "/follow_check"];
// パスをjoinで結合
const t = array.join('')
axios.get(t).then(res => {
if(res.data == 1) {
this.check = true
} else {
this.check = false
}
}).catch(function(error) {
console.log(error)
})
}
}
}
</script>
#1, checkの状態(フォロー状態)によってボタンの表示を変えています。
#2, ボタンが押された時の処理ですが、フォロー、フォロワー関係が変化するので非同期的にするためにvuexに飛ばして再取得しています。
#3, axiosでコントローラーと通信しています。その返り値をcheckの値に反映させています。フォローしているのかしていないのか、ですね。
フォロワーリスト
フォローリストより少し複雑です。
<template>
<div class="bg-light px-4 py-3 mt-3">
<h5>フォロワー</h5>
<hr>
<div v-for="follower_user in follower_users" :key="follower_user.id">
<div class="col-12 row my-2">
<img :src="follower_user.avatar" style="width: 40px; height: 40px; border-radius: 50%!important;" class="img-responsive" alt="">
<p class="pt-2 ml-3" style="font-size: 1rem; cursor: pointer;">
{{follower_user.name}}
</p>
<div v-if="follower_user.id != login_user_id">
<form @submit.prevent="send(follower_user.id)">
<div v-if="login_user_id == user_id">
<input type="hidden" name="_token" v-bind:value="csrf">
<div v-if="check_user(follower_user.id)">
<button type="submit" class="mt-2 ml-2 btn btn-outline-primary btn-sm" style="height: 1.7rem;">Unfollow</button>
</div>
<div v-else>
<button type="submit" class="mt-2 ml-2 btn btn-outline-primary btn-sm" style="height: 1.7rem;">Follow</button>
</div>
</div>
<div v-else>
<input type="hidden" name="_token" v-bind:value="csrf" v-show="check_user(follower_user.id)">
<div v-if="check">
<button type="submit" class="mt-2 ml-2 btn btn-outline-primary btn-sm" style="height: 1.7rem;">Unfollow</button>
</div>
<div v-else>
<button type="submit" class="mt-2 ml-2 btn btn-outline-primary btn-sm" style="height: 1.7rem;">Follow</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default {
data() {
return {
check: false
}
},
props: ['user_id', 'login_user_id', 'csrf'],
computed: {
...mapState("follow",['follow_users', 'follower_users'])
},
created() {
this.$store.dispatch('follow/get_follow_list', this.user_id)
this.$store.dispatch('follow/get_follower_list', this.user_id)
},
methods: {
make_url(id) {
this.$store.dispatch('get_link', id)
window.location.href = this.url
},
send(id){
this.$store.dispatch('follow/follow_do', id)
this.$store.dispatch('follow/get_follow_list', this.user_id)
this.$store.dispatch('follow/get_follower_list', this.user_id)
},
check_user(id) {
// マイページと他のユーザーのページで処理を分けている
if(this.login_user_id == this.user_id) {
if(this.follow_users) {
function following(arr, user_id) {
return arr.some(function(val) {
return val.id == user_id
})
}
if(following(this.follow_users, id)) {
return true
} else {
return false
}
}
} else {
var array = ["/user/", id, "/follow_check"];
// パスをjoinで結合
const t = array.join('')
axios.get(t).then(res => {
if(res.data == 1) {
this.check = true
} else {
this.check = false
}
}).catch(function(error) {
console.log(error)
})
}
}
}
}
</script>
コンポーネント(追加)
以前作成したコンポーネントのmethodsのsend()メソッドのなかを以下に変更します。
send() {
this.$store.dispatch('follow/follow_do', this.user_id)
this.check_follow()
#1 this.$store.dispatch('follow/get_follower_list', this.user_id)
}
#1,これが付け加えられたもので、このユーザーのフォロワーリストを再取得しています。(ログインしているユーザーがこのユーザーに対して追加、解除のどちらかを行なっているため)その変更点を非同期的に変更する目的です。
vuex(メソッド追加)
コードをそれぞれ追加していきます。
state
follow_users: '',
follower_users: '',
mutations
#1 follow_list(state, id) {
const array = ["/user/", id, "/follow_list"];
const t = array.join('')
axios.get(t).then(res => {
state.follow_users = res.data
}).catch(function(error) {
console.log(error)
})
},
#2 follower_list(state, id) {
const array = ["/user/", id, "/follower_list"];
const t = array.join('')
axios.get(t).then(res => {
state.follower_users = res.data
}).catch(function(error) {
console.log(error)
})
},
actions
get_follow_list({commit}, id) {
commit('follow_list',id)
},
get_follower_list({commit}, id) {
commit('follower_list', id)
}
#1, コンポーネントで呼ばれると、axiosでコントローラーと通信し、返り値(フォロー一覧)をstateに渡しています。
#2, 同じく、コンポーネントで呼ばれると、axiosでコントローラーと通信し、返り値(フォロワー一覧)をstateに渡しています。
まとめ
コントローラーとのやり取りの際に必要な値を受け取る事や、受け取ってから実行する処理などの流れが見えてくると実装しやすくなるかなと思います。
今回はこんな感じで!
以上!