Google Apps ScriptでVue Routerを使ったページ遷移を実現【GAS】
Google Apps Scriptで作成するウェブアプリケーションはiframeで閉じられたSandbox内で動作する為、基本的には一般的なウェブサービスと違い、SPAな作り方で構築しなければなりません。以前も以下のエントリーのような擬似的なページ遷移を作りましたが、あまり使いやすいものとは言えません。
そこで使うのがVue.jsで利用するVue Router。今回はGoogle Apps Scriptならではの使い方で作ってみようと思います。
今回利用するファイルやライブラリ
- Vue Router - Google Spreadsheet
- Vue Router
Vue.jsも利用する必要がありますので、ライブラリのロードではVue.jsとVue Routerの2つのライブラリを読み込みます。3つのページの内容はGAS側で用意しておいた3つのHTMLをcreateTemplateFromFileにてロードして切り替えます。
ソースコード
GAS側コード
//外部貼り付け用
function doGet(e){
var html = HtmlService.createTemplateFromFile("index").evaluate()
html = html.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
return html;
}
//ページをロードする関数
function gethtmlpage(page){
var html = HtmlService.createTemplateFromFile(page).evaluate().getContent();
return html;
}
- gethtmlpageは指定されたHTMLのデータを取得して返すだけの関数です。
HTML側コード
<!DOCTYPE html>
<html>
<head>
<script>
function tomato(){
alert("とまと");
}
</script>
</head>
<body>
<div id="app">
<h1>{{ title }}</h1>
<nav>
<router-link to="/start">リンク</router-link>
<router-link to="/cook">お料理</router-link>
<router-link to="/button">ボタン</router-link>
</nav>
<router-view/>
</div>
<!-- VueとVue-Routerを読み込む -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
<script src="https://unpkg.com/vue-router@3.5.2/dist/vue-router.js"></script>
<script>
var vm;
var router;
var routeman = [];
var page01, page02
//HTMLデータを取得する
Promise.resolve()
.then(function () {
return new Promise(function (resolve, reject) {
google.script.run.withSuccessHandler(function(ret) {
//値を格納する
page01 = ret;
page01 = page01.replace(/[\'']/g,"\\'");
routeman.push({path:'*', component : { template: "<b>上のリンクをクリックして下さい。</b>"}})
routeman.push({path:'/start', component : { template: page01}})
resolve('新規データ追加完了');
}).gethtmlpage("page01");
});
})
.then(function (value) {
return new Promise(function (resolve, reject) {
google.script.run.withSuccessHandler(function(ret2) {
//値を格納する
page02 = ret2;
routeman.push({path:'/button',component: { template: page02}})
resolve("next");
}).gethtmlpage("page02");
});
})
.then(function (value) {
return new Promise(function (resolve, reject) {
//他を追加
routeman.push({path:'/cook',component: { template: '<div>{{ vm.cookman }}</div>'}})
//vue-routerの設定
router = new VueRouter({
mode: 'history',
routes : routeman
})
resolve("next");
});
})
.then(function (value) {
return new Promise(function (resolve, reject) {
//vueを初期化
vm = new Vue({
router: router,
data:{
title: 'Vue Routerサンプル',
cookman : "チーズハンバーグ",
link : "https://www.google.co.jp"
},
mounted:function(){
//startのページを初期表示するように変更
router.replace('/')
router.replace('/start')
}
}).$mount('#app')
});
})
.catch(function (err) {
//エラー発生時の処理
console.log(err);
});
</script>
</body>
</html>
- <nav>の中にルーティングするページの一覧へのリンクを構築します。最後に<router-view/>を追加することでappの中身はOK
- CDNからVue.jsとvue-router.jsをロードするのはページの後半部分で行います。
- GAS側に用意した呼び出すHTMLはgethtmlpage関数で呼び出して格納します。
- new VueRouterでルーターを初期化し、各ページへのデータをここで格納しておきます。
- Vue.jsの初期化は一番最後に行い、ここでrouter:routerとして追加をします。
呼び出すHTML
今回のvue-routerではvue.jsのdataの値を取得できるかどうか?といった基本的なポイントに基づいて、2つのHTMLと1つの直書きした値をrouteに追加しています。主に以下のような内容です。
//1つ目のHTML(page01.html)
<a v-bind:href="vm.link" target="_blank">Google</a>
//2つ目のHTML(直書き)
<div>{{ vm.cookman }}</div>
//3つ目のHTML(page02.html)
<button type="button" onClick="tomato();">クリック</button>
それぞれを/start, /button, /cookのルートに対して呼び出すようにセットしています。
注意点とポイント
今回のVueRouteを作成するにあたっては、Google Apps Scriptで利用する上での特別な注意点があります。
- 通常は遷移先URLが変わるのですが、GASではウェブアプリはiframe内のサンドボックス内なので、ブラウザのURL自体は変わりません(iframe内のソースが変わる)
- 初期ページ(ルート)のpathを初期表示した場合には、vueのdataの内容がundefinedで取得出来ない。redirectを指定しても同様。
- GAS側のHTMLの取得やrouteへの追加、new VueRouterの初期化は順番に行うために、Promiseで順番に取得して実行させています。
- 最後にVue.jsの初期化のMountedにてルートパスが開かれた場合をreplaceで/startへ書き換えて表示させ、2.の問題を回避しています(同じテクを応用すればページの内容を別のHTMLを呼び出して表示といった事も可能)
- 直書きの場合はルートのページでなければ、普通にvue.jsのdataへアクセスが可能なので、普通に値が取得可能
また、通常GASのウェブアプリは、戻るボタンをクリックしてしまうとウェブアプリからその前に表示されていたページへ戻ってしまうのですが、Routerを使ってる場合は、その上で操作した履歴はきちんと残されているので、戻るボタンでVueRouteのHistoryで表示した内容に移動できる利点があります。
