
åäžããŒãžã¢ããªã±ãŒã·ã§ã³ïŒSPAïŒã«ã¯ãé床ãæ¬åœã«åªããUXãHTMLããŒã¯ã¢ããã®å®å
šãªå¶åŸ¡ãªã©ãå€ãã®å©ç¹ããããŸãã ãŸããŸãå€ãã®SPAãµã€ãããããŸãã SPAéçºããã»ã¹ãç°¡çŽ åããããŒã«ãå¢ããŠããŸãã è¥ããŠææãª
Vue.jsãã¬ãŒã ã¯ãŒã¯ã«ã€ããŠã¯ããã§ã«èªãã§ãããš
æããŸãã Vueãããæ·±ãæãäžããå
·äœçãªäŸãæããŠãåçŽãªSPAãæ±ãããšããå§ãããŸãã
ç°¡åãªããã°ã®ã¯ã©ã€ã¢ã³ããµãŒããŒã¢ããªã±ãŒã·ã§ã³ãäœæããŸãã ã¢ããªã±ãŒã·ã§ã³ã¯ããšã³ããªã®ãªã¹ããšåã
ã®ãšã³ããªã®å
šæã衚瀺ããŸãã ãããŠãã¡ãããããã¯ãã¹ãŠããŒãžããªããŒãããªããŠãèµ·ãããŸãã
ãã®ã¢ããªã±ãŒã·ã§ã³ã®äŸãããç解ããåŸãVueã«ããŒã¿ãæœåºããã«ãŒããäœæããVueã®èå³æ·±ãæ©èœã§ããåäžãã¡ã€ã«ã³ã³ããŒãã³ããåŠçããæ¹æ³ãåŠç¿ããŸãã
ããã¯ãšã³ã
ãã®ã¬ã€ãã§ã¯ãäž»ã«
Vueã®ããã³ããšã³ãã«çŠç¹ãåœãŠãŸãã RESTããã¯ãšã³ãã®äœæã«ã€ããŠã¯èããŸããã ããšãã°ãREST APIã®åœ¢åŒã§ã¹ã¿ãã
æäŸããjsonplaceholder.typicode.comãµãŒãã¹ã䜿çšããŸãã
ããã³ããšã³ã
ããŒã«
Vueã䜿ãå§ããã®ã¯ç°¡åã§ãã é©åãªããŒã«ã®äœ¿çšã¯ããã«ç°¡åã§ãã ããŒã«ãã³ã³ããŒãã³ããã©ã€ãã©ãªããã¹ãŠã®æ©äŒã®ãã©ã°ã€ã³ã®ãªã¹ããå«ã
vue-awesomeãããžã§ã¯ãã
ã芧ã«ãªãããšããå§ãããŸãã
ãŽãŒã¯ãª
æ°ãããããžã§ã¯ããäœæãããšãã¯ãVue-cliã䜿çšããããšããå§ãããŸãã ãã®ãããå
¬åŒã®Vueãã³ãã¬ãŒããããžã§ã¯ãããŸãã¯å€ãã®ãªãŒãã³ãœãŒã¹ãã³ãã¬ãŒããããžã§ã¯ãã®1ã€ã䜿çšããŠãããžã§ã¯ããäœæã§ããŸãããã¡ãããç¬èªã®ãããžã§ã¯ããäœæããŠãã©ãã§ã䜿çšã§ããŸãã
ãããã£ãŠããŸãã¯vue-cliãã°ããŒãã«ããã±ãŒãžãšããŠã€ã³ã¹ããŒã«ããŸãã
$ npm install -g vue-cli
次ã«ãéžæãããã³ãã¬ãŒãã§ãããžã§ã¯ããåæåããŸãã ãã®äŸã§ã¯ãwebpack-simpleã§ååã§ãã
$ vue init webpack-simple vue-spa
次ã«ãvue-spaãã©ã«ããŒã«ç§»åããã¿ãŒããã«ã§
npm installãå®è¡ããŸãã ãã¹ãŠã®ããã±ãŒãžãã€ã³ã¹ããŒã«ããããã¢ããªã±ãŒã·ã§ã³ãéçºã¢ãŒãã§å®è¡ã§ããŸãã
$ npm run dev
ãã®ã³ãã³ãã¯ãããŒã«ã«webpack devãµãŒããŒã§ãããžã§ã¯ããèªåçã«èµ·åããŸãã æãã·ã³ãã«ãªVueã¢ããªããã©ãŠã¶ãŒã«è¡šç€ºãããŸãã ãã¡ãããããã¯ç§ãã¡ãæãããã«ãã¹ãŠãèŠãŠããŸããããããŠãããã«äœããå§ããããã®åºçºç¹ãšããŠã®ã¿é©ããŠããŸãã äœæ¥ãç¶è¡ããã«ã¯ããŸããã³ãã¬ãŒãã®æ§é ã«æ
£ããããšããå§ãããŸãã
Webpackã·ã³ãã«ãã³ãã¬ãŒã
webpack-simpleãã³ãã¬ãŒãã®å
éšã«ã¯æ¬¡ã®æ§é ããããŸãã
index.htmlãã¡ã€ã«ã«ã¯ãæ¬æã«åäžã®ãappãèŠçŽ ãæã€åçŽãªHTMLããŒã¯ã¢ãããå«ãŸããŠããŸãã vueã«ãã£ãŠçæãããDOMã«çœ®ãæããããŸãã ãã®ããã
bodyã¿ã°ã¯ã«ãŒãèŠçŽ ãšããŠæšå¥šãããŠããŸããã
srcãã©ã«ããŒã«ã¯ãwebpackãšã³ããªãã€ã³ããå«ãmain.jsãã¡ã€ã«ãå«ãŸããŠããŸãã Vueã³ã³ããŒãã³ããããã«ã€ã³ããŒããããŸãã ãŸããVueã®ã«ãŒãã€ã³ã¹ã¿ã³ã¹ã«ã€ããŠã説æããŸããããã«ã¯ããããŸã§2ã€ã®ããããã£ããããŸãã ãelãããããã£ã¯ãæå®ãããDOMèŠçŽ ãžã®ãªã³ã¯ãVueã€ã³ã¹ã¿ã³ã¹ã«æäŸããŸãã ãã1ã€ã¯ã
App.vueããDOMãçæããã¬ã³ããªã³ã°é¢æ°ã§ãã äžè¬ã«ãwebpack-simpleãã³ãã¬ãŒãã®æ§é ã«ã€ããŠç¥ãå¿
èŠãããã®ã¯ããã ãã§ãã ã¢ããªã±ãŒã·ã§ã³ã®äž»èŠéšåã¯App.vueã§ããã°ã©ã ãããŸãã .vueæ¡åŒµåã¯ããã¡ã€ã«ãvueã®åäžãã¡ã€ã«ã³ã³ããŒãã³ããšããŠå®çŸ©ããŸãã ããã¯ãVueã®æ©èœã®1ã€ã§ãããããããããã«è©³ããç¥ãããšãã§ããŸãã
åäžãã¡ã€ã«ã³ã³ããŒãã³ã

å* .vueãã¡ã€ã«ã¯ã3ã€ã®ã¿ã€ãã®ãããã¯ã§æ§æãããŸãïŒ<ãã³ãã¬ãŒã>ã<ã¹ã¯ãªãã>ãããã³ãªãã·ã§ã³ã§<ã¹ã¿ã€ã«>ã ãã®çµæããããžã§ã¯ããé¢é£ããã³ã³ããŒãã³ãã«åå²ã§ããŸãã ã³ã³ããŒãã³ãã®å
éšã§ã¯ããã®ãã³ãã¬ãŒããããžãã¯ãããã³ã¹ã¿ã€ã«ã¯å¯æ¥ã«ãªã³ã¯ãããŠããããããã®çµã¿åããã«ãããå®éã«ã¯ã³ã³ããŒãã³ããããå
šäœçãã€å®¹æã«ç¶æãããŸãã ããã§ãVueã§ããã°ãäœæããæºåãæŽããŸããã
ã¢ããªã±ãŒã·ã§ã³ãæžã
å®éã«äœãå®è£
ããã®ãèŠãŠã¿ãŸãããã ããŒãžäžéšã«ããã°ã®ååã®èŠåºãããããŸãã å·ŠåŽã«ã¯ãæçš¿ã®ã¿ã€ãã«ã衚瀺ããåºå®ãµã€ãããŒããããŸããããã¯ç®æ¬¡ã®ãããªãã®ã«ãªããŸãã ããŒãžã®æ®ãã®éšåã¯ãã¬ã³ãŒãã®ããã¹ãã衚瀺ãããåçãããã¯ã§å ããããŸãã

ã¹ããã1
ãŸããApp.vueããäœåãªè¡ããã¹ãŠåé€ããŸãã ãããŠãèŠä»¶ã«åŸã£ãŠãã³ãã¬ãŒããæžãæããŸãã
<template> <div id="app"> <header> <h1>Vue.js SPA</h1> </header> <main> <aside class="sidebar"> </aside> <div class="content"> </div> </main> </div> </template>
次ã«ãdataããããã£ã䜿çšããŠVueã€ã³ã¹ã¿ã³ã¹ãäœæããã¡ãã»ãŒãžãšãšãã«é
åã«é
眮ããŸãã çŸæç¹ã§ã¯ç©ºã§ãããããã«ã¢ã¬ã€å
ã®ãµãŒããŒããåä¿¡ããããŒã¿ãå
¥ããŸãã
æåã®åŒã³åºãåŸãã«ãŒãããŒã¿ãªããžã§ã¯ãã«ãªã¢ã¯ãã£ãããããã£ãè¿œå ã§ããªããªããŸãã ãããã£ãŠãVueã®ã€ã³ã¹ã¿ã³ã¹ãäœæããåã«ããã¹ãŠã®ãªã¢ã¯ãã£ãããããã£ãã«ãŒãã¬ãã«ã§å®£èšããããšããå§ãããŸãã
<script> export default { data () { return { posts: [] } } } </script>
ãŸããããã€ãã®ã¹ã¿ã€ã«ãè¿œå ããŠãã¢ããªã®èŠæ ããè¯ãããããšãã§ããŸãã
ã¢ããªã±ãŒã·ã§ã³ã³ãŒãã¯
github.comã§ãã¹ããããŠã
ãŸã ã ãªããžããªã®ã¯ããŒã³ãäœæããã¹ãããçªå·ã§ãã©ã³ããåãæ¿ããã ãã§ãã¢ããªã±ãŒã·ã§ã³ã®éçºãã¹ãããããšã«è¿œè·¡ã§ããŸãã次ã«äŸã瀺ããŸãã
$ git checkout step-1
çŸæç¹ã§ã¯ãããã²ãŒã·ã§ã³ããã«ã«è¡šç€ºãããã®ã¯ãŸã£ãããªãã®ã§ããµãŒããŒããããŒã¿ãååŸããŸãããã ãã®ããã䜿ããããHTTPã¯ã©ã€ã¢ã³ãã§ããAxiosãéžæããŸããã ãŸããVueãªãœãŒã¹ãç¬èªã®éžæãjQuery Ajaxãªã©ã䟿å©ãªæ¹æ³ã䜿çšããããšãã§ããŸãã
ã¹ããã2
Axiosãã€ã³ã¹ããŒã«ãã
$ npm install --save-dev axios
次ã«ããããAppã³ã³ããŒãã³ãã«ã€ã³ããŒããããµãŒããŒã«èŠæ±ãéä¿¡ããŠãããpostsããããã£ã«å²ãåœãŠãgetAllPostsïŒïŒã¡ãœãããå®çŸ©ããŸãã createdïŒïŒããã¯ã§ã¡ãœãããåŒã³åºããŸããããã¯ãVueã€ã³ã¹ã¿ã³ã¹ã®äœæåŸãããã³ããŒã¿ã¢ã¯ã»ã¹èšå®ã®èšå®åŸã«åŒã³åºãããŸãã
import axios from 'axios' export default { data () { return { posts: null, endpoint: 'https://jsonplaceholder.typicode.com/posts/', } }, created() { this.getAllPosts(); }, methods: { getAllPosts() { axios.get(this.endpoint) .then(response => { this.posts = response.data; }) .catch(error => { console.log('-----error-------'); console.log(error); }) } } }
ãããŠããµã€ãããŒã«ãã¹ãŠã®ã¬ã³ãŒãããããŒã衚瀺ããŸãã
<aside class="sidebar"> <div v-for="post in posts"> {{ post.title }} </div> </aside>
ãããŸã§ãã¬ã³ãŒãã®ã¿ã€ãã«ã®ã¿ã衚瀺ããŸãããããããŸã§ã®ãšãããã¬ã³ãŒãèªäœã¯è¡šç€ºã§ããŸããã 次ã«ããµã€ãããŒã§éžæããååã«åŸã£ãŠãã³ã³ãã³ãã»ã¯ã·ã§ã³ã«å®å
šãªæçš¿ã衚瀺ããå¿
èŠããããŸãã åæã«ãåãšã³ããªãäžæã®ã¢ãã¬ã¹ã§å©çšã§ããããã«ããããšæããŸãã
ã¹ããã3
ãããè¡ãã«ã¯ãå
¬åŒã®Vueã©ã€ãã©ãªvue-routerã䜿çšããŸãã ååã瀺ãããã«ãã©ã€ãã©ãªã䜿çšãããšãã¢ããªã±ãŒã·ã§ã³ã®ã«ãŒãã£ã³ã°ãæ§æã§ããŸãã
ã©ã€ãã©ãªãã€ã³ã¹ããŒã«ããŸãã
$ npm install --save-dev vue-router
ã«ãŒãã£ã³ã°ãèšå®ããããã«ãmain.jsã«æ»ããŸãããã ããã§ãã«ãŒãã£ã³ã°èšå®ãå®çŸ©ããVueã€ã³ã¹ã¿ã³ã¹ã«è¿œå ããŸãã
import Vue from 'vue' import Router from 'vue-router' import App from './App.vue' import Post from './components/Post.vue' import Hello from './components/Hello.vue' Vue.use(Router) const router = new Router({ routes: [ { path: '/', name:'home', component: Hello, }, { path: '/post/:id', name:'post', component: Post, props: true, }, ] }) new Vue({ el: '#app', render: h => h(App), router })
ã«ãŒãã£ã³ã°èšå®ã§ã¯ã察å¿ãããã¹ã«æ²¿ã£ãŠã¬ã³ããªã³ã°ããã³ã³ããŒãã³ããæå®ããŸããã åæçš¿ã®ã¬ã³ããªã³ã°ã¯Post.vueã³ã³ããŒãã³ãã®ã¿ãæ
åœãããããåæçš¿ãžã®ãã¹ã決å®ããå¿
èŠã¯ãããŸãããåçãã¹ãå®çŸ©ããã ãã§ååã§ãã
path: '/post/:id'
ãã®ãã¹ã«ã¯ãç¹å®ã®æçš¿ãæãåçã»ã°ã¡ã³ãIDãå«ãŸããŸãã åæã«ããããä»ããŠPostã³ã³ããŒãã³ãã®ãã®ã»ã°ã¡ã³ãã«ã¢ã¯ã»ã¹ã§ã
ãŸã$ Route.params.id ã ãã ããã³ã³ããŒãã³ãã§$ã«ãŒãã䜿çšãããšãç¹å®ã®URLã§ã®ã¿äœ¿çšã§ãããããã«ãŒããšã®ç·å¯ãªæ¥ç¶ãä¿®æ£ãããã³ã³ããŒãã³ãã®æè»æ§ãå¶éãããŸãã 代ããã«ã
propsãªãã·ã§ã³ã䜿çšããŠ
trueã«èšå®ã§ã
ãŸã ã ãã®åŸã$ route.paramsã¯Postã³ã³ããŒãã³ãã®propsãªãã·ã§ã³ã«é¢é£ä»ããããŸãã
ã«ãŒã¿ãŒãäœæããã®ã§ãã¢ããªã±ãŒã·ã§ã³ã«æ»ãããã³ãã¬ãŒãã«ããã«æ°è¡ãè¿œå ã§ããŸãã
<main> <aside class="sidebar"> <router-link v-for="post in posts" active-class="is-active" class="link" :to="{ name: 'post', params: { id: post.id } }"> {{post.id}}. {{post.title}} </router-link> </aside> <div class="content"> <router-view></router-view> </div> </main>
ããã«ã¯ã2ã€ã®
vue-routerã³ã³ããŒãã³ãããããŸãïŒ<router-link>ããã³<router-view>ã 1ã€ã¯ãã«ãŒãã£ã³ã°ããµããŒãããã¢ããªã±ãŒã·ã§ã³ã§ãŠãŒã¶ãŒããã²ãŒã·ã§ã³ãæå¹ã«ããããã®ã³ã³ããŒãã³ãã§ãã 2çªç®ã®ã³ã³ããŒãã³ãã¯ãç¹å®ã®ãã¹ã«å¯ŸããŠäžè²«ããã³ã³ããŒãã³ããæç»ããæ©èœã³ã³ããŒãã³ãã§ãã
æåŸã®ã¹ãããã¯æ®ã£ãã æçš¿ãšã³ããªã®å
容ã衚瀺ããå¿
èŠããããŸãã
ã¹ããã4
Post.vueãã¡ã€ã«ã«ç§»ããŸããããããã§ã¯ãåçŽãªãã³ãã¬ãŒããè¿œå ããŸãã
<template lang="html"> <div class="post" v-if="post"> <h1 class="post__title">{{ post.title }}</h1> <p class="post__body">{{ post.body }}</p> <p class="post__id">{{ post.id }}</p> </div> </template>
次ã«ããã®ã³ã³ããŒãã³ãã®Vueã€ã³ã¹ã¿ã³ã¹ã®ãã©ã¡ãŒã¿ãŒãèšå®ããå¿
èŠããããŸãã ããã§ã¯ããã¹ãŠããã¹ãŠã®æçš¿ã®è¡šç€ºèšå®ãšåãã§ãã
idãå€æŽããŠ
propsãªãã·ã§ã³ã宣èšããŸããããã¯ãæçš¿ã®çªå·ãåãåããŸãã 次ã«ãApp.vueã§æ¢ã«è¡ãããŠããããã«ãããŒã¿ãªããžã§ã¯ãã宣èšããŸãã
import axios from 'axios'; export default { props: ['id'], data() { return { post: null, endpoint: 'https://jsonplaceholder.typicode.com/posts/', } } }
次ã«ã
getPostïŒïŒã¡ãœããã«ã€ããŠèª¬æããŸãããã®ã¡ãœããã¯ãèå¥åã«ãã£ãŠ1ã€ã®æçš¿ã¬ã³ãŒãã®ã¿ãåãåãã
äœæãããïŒïŒããã¯ã§åŒã³åºããŸãã
methods: { getPost(id) { axios(this.endpoint + id) .then(response => { this.post = response.data }) .catch( error => { console.log(error) }) } }, created() { this.getPost(this.id); },
ã»ãŒå®äºã ããã§ã¢ããªã±ãŒã·ã§ã³ãèµ·åãããšãURLã¯å€æŽãããŸãããæåã«æãããå¯äžã®æçš¿ã衚瀺ãããŸãã å®éã«ã¯ãç°ãªãæçš¿ãã¬ã³ããªã³ã°ããããã«åãã³ã³ããŒãã³ãããããVueã¯ãªãœãŒã¹ã®äžå¿
èŠãªç¡é§ã®ããã«åäœæããå¿
èŠããããŸãããããã¯ãã³ã³ããŒãã³ãã®ã©ã€ããµã€ã¯ã«ããã¯ãåŒã³åºãããªãããšãæå³ããŸãã
ãããä¿®æ£ããã«ã¯ã
$ã«ãŒããªããžã§ã¯ãã®ãŠã©ããã£ãŒãã€ã³ã¹ããŒã«ããã ãã§ãã
watch: { '$route'() { this.getPost(this.id); } }
ããã§ãã¹ãŠãæ£åžžã«æ©èœããããã«ãªããŸããã å®åçšã®ããŒãžã§ã³ãååŸããã«ã¯ãã³ã³ãœãŒã«ã§
npm run buildã³ãã³ãã
å®è¡ããã ãã§ãã
ãŸãšãããš
4ã€ã®ã¹ãããã§Vueã䜿çšããç°¡åãª1ããŒãžã®ã¢ããªã±ãŒã·ã§ã³ãäœæããŸããã vue-cliã䜿çšããŠãããžã§ã¯ããéå§ããã®ãããã«ç°¡åããåŠã³ãŸããã ãããžã§ã¯ããããæè»ã§ã¹ã±ãŒã©ãã«ã«ããåäžãã¡ã€ã«Vueã³ã³ããŒãã³ãã®æŠå¿µãæ€èšããŸããã Axiosã䜿çšããŠå€éšAPIããããŒã¿ãæœåºããæ¹æ³ãåŠã³ãŸããã ãããŠãvue-routerã䜿çšããŠã«ãŒãã£ã³ã°ãæ§æããæ¹æ³ãèŠãŸããã ãã¡ãããããã¯åºæ¬çãªç¥èã§ããããããé«åºŠãªæ©èœã䜿çšããŠVue.jsã䜿ãå§ããã®ã«åœ¹ç«ã€ããšãé¡ã£ãŠããŸãã
䟿å©ãªãªã³ã¯
â
ãªãªãžãã«èšäºâ
èšäºã®ãœãŒã¹ã³ãŒãã䜿çšããŠGitHubãããžã§ã¯ãã«ãªã³ã¯ããâ
Project vue-awesome