【学習メモ】Vue.js入門 基礎から実践アプリケーション開発まで その3
4 Vue Router を活用したアプリケーション開発
4.2 ルーティングの基礎
4.2.2 ルーティング設計
ルート と ルーターコンストラクタ を用います。
<div id="app"> <router-link to="/top">トップページ</router-link> <router-link to="/users">ユーザー一覧ページ</router-link> <router-view></router-view> </div> <script src="https://unpkg.com/vue@2.5.17"></script> <script src="https://unpkg.com/vue-router@3.0.1"></script> <script src="./assets/js/main.js"></script>
// ルーターコンストラクタ // ルートオプションを渡してルーターインスタンスを生成 var router = new VueRouter({ // ルート定義 routes: [ { path: "/top", component: { template: `<div>トップページです。</div>` } }, { path: "/users", component: { template: `<div>ユーザー一覧ページです。</div>` } } ] }); // Vue のマウント // ルーターのインスタンスをrootとなるVueインスタンスに渡す var app = new Vue({ router: router, el: "#app" });
4.4 サンプルアプリケーションの実装
<div id="app"> <nav v-cloak> <!-- `router-link` によるナビゲーション定義 --> <router-link to="/top">トップページ</router-link> <router-link to="/users">ユーザー一覧ページ</router-link> <router-link to="/users/new?redirect=ture">新規ユーザー登録</router-link> <router-link to="/login" v-show="!Auth.loggedIn()">ログイン</router-link> <router-link to="/logout" v-show="Auth.loggedIn()">ログアウト</router-link> </nav> <router-view></router-view> </div> <script src="https://unpkg.com/vue@2.5.17"></script> <script src="https://unpkg.com/vue-router@3.0.1"></script> <!-- ユーザー一覧ページのテンプレート --> <script type="text/x-template" id="user-list"> <div> <div class="loading" v-if="loading">読み込み中</div> <div v-if="error" class="error"> {{ error }} </div> <!-- usersがロードされたら各ユーザーの名前を表示する --> <div v-for="user in users" :key="user.id"> <h2>{{ user.name }}</h2> </div> </div> </script> <!-- ユーザー詳細ページのテンプレート --> <script type="text/x-template" id="user-detail"> <div> <div class="loading" v-if="loading">読み込み中</div> <div v-if="error" class="error"> {{ error }} </div> <!-- users がロードされたら各ユーザの名前を表示する --> <div v-if="user"> <h2>{{ user.name }}</h2> <p>{{ user.description }}</p> </div> </div> </script> <!-- ユーザー作成ページのテンプレート --> <script type="text/x-template" id="user-create"> <div> <div class="sending" v-if="sending">Sending</div> <div> <h2>新規ユーザー作成</h2> <div> <label>名前: </label> <input type="text" v-model="user.name"> </div> <div> <label>説明文: </label> <textarea v-model="user.description"></textarea> </div> <div v-if="error" class="error"> {{ error }} </div> <div> <input type="button" @click="createUser" value="送信"> </div> </div> </div> </script> <!-- ログインページのテンプレート --> <script type="text/x-template" id="login"> <div> <h2>Login</h2> <p v-if="$route.query.redirect"> ログインしてください </p> <form @submit.prevent="login"> <label><input v-model="email" placeholder="email"></label> <label><input v-model="pass" placeholder="password" type="password"></label> <br> <button type="submit">ログイン</button> <p v-if="error" class="error">ログインに失敗しました</p> </form> </div> </script> <script src="./assets/js/main.js"></script>
////////////////////////// // ユーザー一覧 ////////////////////////// var getUsers = function(callback) { setTimeout(function() { callback(null, [ { id: 1, name: "Takuya Tejima" }, { id: 2, name: "Yohei Noda" } ]); }, 1000); }; var UserList = { template: "#user-list", data: function() { return { loading: false, users: function() { return []; // 初期値の空配列 }, error: null }; }, // 初期化時にデータを取得する created: function() { this.fetchData(); }, // $route の変更をwatchすることでルーティングが変更されたときに再度データを取得 watch: { $route: "fetchData" }, methods: { fetchData: function() { this.loading = true; // 取得したデータの結果をusersに格納する getUsers( function(err, users) { this.loading = false; if (err) { this.error = err.toString(); } else { this.users = users; } }.bind(this) ); } } }; ////////////////////////// // ユーザー詳細 ////////////////////////// var userData = [ { id: 1, name: "Takuya Tejima", description: "東南アジアで働くエンジニアです。" }, { id: 2, name: "Yohei Noda", description: "アウトドア・フットサルが趣味のエンジニアです。" } ]; var getUser = function(userId, callback) { setTimeout(function() { var filteredUsers = userData.filter(function(user) { return user.id === parseInt(userId, 10); }); callback(null, filteredUsers && filteredUsers[0]); }, 1000); }; var UserDetail = { template: "#user-detail", data: function() { return { loading: false, user: null, error: null }; }, // 初期化時にデータを取得する created: function() { this.fetchData(); }, // $route の変更をwatchすることでルーティングが変更されたときに再度データを取得 watch: { $route: "fetchData" }, methods: { fetchData: function() { this.loading = true; // `this.$route.params.userId` に現在のURL上のパラメータに対応した userIdが格納される getUser( this.$route.params.userId, function(err, user) { this.loading = false; if (err) { this.error = err.toString(); } else { this.user = user; } }.bind(this) ); } } }; ////////////////////////// // ユーザー作成 ////////////////////////// // 擬似的にAPI経由で情報を更新したようにする // 実際のWebアプリケーションではサーバーへへPOSTリクエストを行う var postUser = function(params, callback) { setTimeout(function() { params.id = userData.length + 1; userData.push(params); callback(null, params); }, 1000); }; // 新規ユーザー作成コンポーネント var UserCreate = { template: "#user-create", data: function() { return { sending: false, user: this.defaultUser(), error: null }; }, created: function() {}, methods: { defaultUser: function() { return { name: "", description: "" }; }, createUser: function() { // 入力パラメーターのバリデーション if (this.user.name.trim() === "") { this.error = "Nameは必須です"; return; } if (this.user.description.trim() === "") { this.error = "Descriptionは必須です"; return; } postUser( this.user, function(err, user) { this.sending = false; if (err) { this.error = null; } else { // デフォルトでフォームをリセット this.user = this.defaultUser(); alert("新規ユーザーが登録されました"); // ユーザー一覧ページに戻る this.$router.push("/users"); } }.bind(this) ); } } }; ////////////////////////// // ログイン・ログアウト ////////////////////////// var Auth = { login: function(email, pass, cb) { // ダミーデータを使った疑似ログイン setTimeout(function() { if (email === "vue@example.com" && pass === "vue") { // ログイン成功時はローカルストレージに taken を保存する localStorage.token = Math.random() .toString(36) .substring(7); if (cb) { cb(true); } } else { if (cb) { cb(false); } } }, 0); }, logout: function() { delete localStorage.token; }, loggedIn: function() { // ローカルストレージにtokenがあればログイン状態とみなす return !!localStorage.token; } }; var Login = { template: "#login", data: function() { return { email: "vue@example.com", pass: "", error: false }; }, methods: { login: function() { Auth.login( this.email, this.pass, function(loggedIn) { if (!loggedIn) { this.error = true; } else { // redirect パラメータがついている場合はそのパスに遷移 this.$router.replace(this.$route.query.redirect || "/"); } }.bind(this) ); } } }; ////////////////////////// // ルーター設定 ////////////////////////// // ルートオプションを渡してルーターインスタンスを生成 var router = new VueRouter({ routes: [ { path: "/top", component: { template: `<div>トップページです。</div>` } }, { path: "/users", component: UserList }, { // ルー定義を追加 path: "/users/new", component: UserCreate, beforeEnter: function(to, from, next) { // 認証されていない状態でアクセスした時はloginページに遷移する if (!Auth.loggedIn()) { next({ path: "/login", query: { redirect: to.fullPath } }); } else { // 認証済みであればそのまま新規ユーザー作成ページに進む next(); } } }, { path: "/users/:userId", component: UserDetail }, { path: "/login", component: Login }, { path: "/logout", beforeEnter: function(to, from, next) { Auth.logout(); next("/top"); } }, { // 定義されていないパスへの対応。トップページへリダイレクトする。 path: "*", redirect: "/top" } ] }); ////////////////////////// // Vue のマウント ////////////////////////// var app = new Vue({ data: { Auth: Auth }, router: router, el: "#app" });