###それを共通化する
というお話です。
#いきさつ
現在仕事でVue.jsを書いており、上記のことを頼まれ実装したので備忘録として。
#使用しているライブラリ
・Vuex
・Vue Router
・BootstrapVue
#流れ
こんな感じです。
・子コンポーネント(Main.vue)はウォッチャで前画面の情報をstoreに保持させている。
・孫コンポーネント(Form.vue)で登録ボタン押下、登録処理後にmixinsで呼び出したメソッドで一覧画面へ。
・親コンポーネント(app.vue)がクエリにtoast_type
があることを検知すると、トーストを表示させる。
・toast_type
がクエリにない一覧画面に遷移する。
今書いてて思いますが、絶対もっと良い方法があると思う・・・。
#ソース
####子コンポーネント
Main.vue
watch: {
'$route': function (to, from) {
// 前画面情報を取得
this.$store.commit('from_page_param/setFromPage', {
full_path: from.fullPath,
name: from.name,
path: from.path
})
}
}
####store
from_page_param.js
export default {
namespaced: true,
state: {
from_page: {
full_path: '',
path: '',
name: ''
}
},
mutations: {
setFromPage (state, data) {
state.from_page.full_path = data.full_path;
state.from_page.path = data.path;
state.from_page.name = data.name;
}
},
getters: {
fromPage: state => {
return state.from_page;
}
}
}
ここまでが前画面情報保持。
####孫コンポーネント
Form.vue
上部でmyMixin.vue
をインポートし、mixinsで定義しているものとしてください。
onClickSend () {
this.$loading.load(this.$auth.api.patch(`/admin/hoges/create.json`, {
hoge: this.hoge
})
.then(response => {
this.transitionProcessed('created', 'IndexPageName');
})
.catch(error => {
if(error.response.status == 422) {
this.errors = error.response.data.errors;
}else{
this.$errorHandlers.ajax(error);
}
}))
},
見るべきはthis.transitionProcessed('created', 'IndexPageName');
。
このメソッドはForm.vueでimportしてきたmyMixin.vue
に書かれたメソッドです。
第一引数にはクエリ、toast_type
のvalue用、第二引数には遷移する一覧画面のNameを渡します。
この中身が・・・
####ミックスイン
myMixin.vue
// 登録処理後などの一覧画面遷移(検索結果保持用)
transitionProcessed (toast_type, name) {
let from_page = this.$store.getters['from_page_param/fromPage'];
if(from_page.full_path && from_page.name === name) {
this.$router.push({ path: from_page.full_path, query: { toast_type: toast_type } })
}else{
this.$router.push({ name: name, query: { toast_type: toast_type } })
}
},
前画面情報があり、戻りたい画面とこれから戻る画面が一致していれば
検索条件を保持してtoast_type
をクエリに追加した一覧画面に遷移します。
####親コンポーネント
methods: {
// クエリからtoast_typeを削除してreplace
replaceDeletedToast (path) {
let query = Object.assign({}, this.$route.query)
delete query['toast_type']
this.$router.replace({path: path, query: query})
}
},
watch: {
'$route': function (to, from) {
if (!!this.$route.query.toast_type){
if(this.$route.query.toast_type === 'updated') {
this.$bvToast.toast("更新しました", {
variant: 'success',
title: '完了'
});
} else if(this.$route.query.toast_type === 'created') {
this.$bvToast.toast("登録しました", {
variant: 'success',
title: '完了'
});
} else if(this.$route.query.toast_type === 'deleted') {
this.$bvToast.toast("削除されました", {
variant: 'success',
title: '完了'
});
}
this.replaceDeletedToast(to.path);
}
}
}
toast_type
の中身で表示させるトーストを判断。
トースト表示後のURLはlocalhost/admin/hoges/?page=2&toast_type=created
とtoast_type
が邪魔なので
this.replaceDeletedToast(to.path);
の中で消し、replace!
#結果
次からは非同期処理後にthis.transitionProcessed('created', 'IndexPageName');
だけ書けばOK
#ハマったところ
app.vueのこの部分。実は最初replace
ではなくpush
を使用していた
this.$router.replace({path: path, query: query})
この場合ひとつ前の履歴はlocalhost/admin/hoges/?page=2&toast_type=created
のようなtoast_type
を含むパスとなり、ブラウザバックをすると、再びapp.vueがトースト表示させ、クエリを消して$router.push ... を延々と繰り返してしまう。
だがreplaceを使うことによってその遷移を履歴に残さないようにすることができ、結果的にブラウザバックでForm.vueの画面に戻ることができた。
これについてはこちらの記事を参考にしました。
JSでブラウザの履歴を操作する
#あとがき
より良い方法をご存知の方がいらっしゃればコメントをくださると嬉しいです。
エンジニア歴1年記念日のQiita投稿でした。