#mynavi(JSライブラリ)
#setlinebreak(on);

&color(red){以下、バージョンの混在に注意。};

* 目次 [#p3a3c85c]
#contents
- 参考
-- https://jp.vuejs.org/v2/guide/
- 関連
-- [[Vue.jsでコンポーネント化された画面を切り替える]]
-- [[Angular2]]
-- [[React>React.js]]
-- [[GraphQL入門]]

//http://www.tohoho-web.com/ex/vuejs.html

* Vue.js の読み込み [#sd996360]
#html(<div style="padding-left:10px;">)

** CDNを利用する場合 [#oe203125]
#html(<div style="padding-left:10px;">)

CDNを利用する場合はインストールは不要。
※ただし後述する 単一ファイルコンポーネント等は使用できない。

#myhtml2(){{
<!-- 開発用 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<!-- 開発用(バージョン指定)
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script>

<!-- 本番用 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

<!-- 本番用(バージョン指定) -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.min.js"></script>
}}
#html(</div>)

** vue-cli を使用する場合 [#ce9576f6]
#html(<div style="padding-left:10px;">)
#myterm2(){{
npm i -g npm to update
npm install -g @vue/cli
}}
#html(</div>)

** ソースコード [#k08c67a9]
#html(<div style="padding-left:10px;">)
https://github.com/vuejs/vue/releases
#html(</div>)

#html(</div>)

* Vue DevToolのインストール [#q1682014]
#html(<div style="padding-left:10px;">)
https://github.com/vuejs/vue-devtools#vue-devtools
#html(</div>)

* vue-cli の基本 [#j19fd50d]
#html(<div style="padding-left:10px;">)

vue-cli を使用してプロジェクトの作成やローカル起動、ビルド等を行う事ができる。

** vue-cli のインストール [#kdc197f2]
#myterm2(){{
npm i -g npm to update
npm install -g @vue/cli
}}

** プロジェクトの作成 [#ic2d9757]
#myterm2(){{
vue create sample-project
}}

** ローカル起動 [#yf413db0]
#myterm2(){{
cd sample-project
npm run serve
}}
※ http://localhost:8080/ で確認

** ビルド [#m8827021]
#myterm2(){{
npm run build
}}
※ dist 以下に出力される
※ 参考: https://jp.vuejs.org/v2/guide/deployment.html

#html(</div>)

* 基本的な使い方 [#zb036805]
#html(<div style="padding-left:10px;">)

Vueインスタンスを生成する事により、画面にデータを描画する事ができる。
また、Vueインスタンスを介して描画内容を変更する事も可能。

** Vueインスタンスの生成 [#qfd25e7d]
#html(<div style="padding-left:10px;">)

以下の通りVueインスタンスを生成して画面描画等を行う。
#mycode2(){{
var vm = Vue({
    .
    .
})
}}

指定できるオプション
|オプション| 内容 |h
| data | UIの状態/データ |
| el | Vueインスタンスをマウントする要素 |
| filters | データの整形に使用する |
| methods | イベント発生時等の処理を関数として定義する |
| computed | データから派生して算出される値を関数として定義する |

#html(</div>)

** elプロパティを使用してマウントする場合 [#nab6780e]
#html(<div style="padding-left:10px;">)

#mycode2(){{
<div id="app">
  &#123;&#123; message &#125;&#125;
</div>

<script>
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

// 2秒後にメッセージを書き換える
setTimeout(function(){
    app.message = 'Change message!'
}, 2000);
</script>
}}
#html(</div>)

** $mountメソッドによるマウント [#f85c0a45]
#html(<div style="padding-left:10px;">)

後から動的に読み込んだコンテンツをマウントする場合等は、$mount メソッドを利用する。
#mycode2(){{
<div id="app"></div>

<script>
var vm = new Vue({
    template: '<p>&#123;&#123;message&#125;&#125;</p>',
    data: {
        message : 'Message!'
    }
})
vm.$mount('#app')
</script>
}}

#html(</div>)

** filters プロパティによるデータの装飾 [#f299f7ef]
#html(<div style="padding-left:10px;">)

filters プロパティを使用する事でローカルなフィルタを定義する事ができる
https://jp.vuejs.org/v2/guide/filters.html

#mycode2(){{
<div id="app">
&#123;&#123; message | toUpper &#125;&#125;
</div>

<script>
var vue = new Vue({
    el: '#app',
    data: {
        message: 'Hello World!'
    },
    filters: {
        toUpper : function(text){
            return text.toUpperCase()
        }
    }
})
</script>
}}

グローバルなフィルタを定義したい場合は、Vue.filter() を使用する
#mycode2(){{
<div id="app">
&#123;&#123; message | toUpper &#125;&#125;
</div>

<script>
Vue.filter('toUpper', function(text) {
  return text.toUpperCase()
})
var vue = new Vue({
    el: '#app',
    data: {
        message: 'Hello World!'
    }
})
}}

#html(</div>)

** computed プロパティによるデータの装飾 [#j8667829]
#html(<div style="padding-left:10px;">)

computed プロパティ使用すると加工済みデータの描画等を行う事が出来る。
filters プロパティと違い、対象データはVueインスタンスから得る。
https://jp.vuejs.org/v2/guide/computed.html

#mycode2(){{
<div id="app">
    <p>Message       : &#123;&#123; message &#125;&#125;</p>
    <p>Upper message : &#123;&#123; upperMessage &#125;&#125;</p>
</div>

<script>
var vue = new Vue({
    el: '#app',
    data: {
        message: 'Hello World!'
    },
    computed: {
        upperMessage: function(value){
            return this.message.toUpperCase();
        }
    }
})
</script>
}}

#html(</div>)

** $watchメソッドによる状態の監視 [#g7f0b773]
#html(<div style="padding-left:10px;">)

Vue.js のリアクティブシステムによる検知/要素の更新の他に、$watchメソッドによる状態の監視を行う事もできる。

#mycode2(){{
<div id="app">
    <input type="text" v-model="message" />
</div>

<script>
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!',
    watch_message: ''
  }
})

// メッセージが変わったらコンソールにログ出力
app.$watch(function(){
    return this.message;
}, function(){
    console.log('changed!');
});

// 2秒後にメッセージを変更
setTimeout(function(){
    app.message = 'Change message!'
}, 2000);

</script>
}}
#html(</div>)

#html(</div>)


* コンポーネント [#tb7bef41]
#html(<div style="padding-left:10px;">)

** コンポーネントの基本 [#fc056328]
#html(<div style="padding-left:10px;">)

コンポーネントを利用する事で画面を部分的に部品化して再利用する事ができる。
参考: https://jp.vuejs.org/v2/guide/components.html

例) クリックカウンターボタンをコンポーネント化して再利用する
#mycode2(){{
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script>
</head>
<body>

<div id="components-demo">
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

<script>
Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click='count++'>click count is &#123;&#123; count &#125;&#125;.</button>'
})
new Vue({ el: '#components-demo' })
</script>

</body>
</html>
}}

#html(</div>)

** コンポーネントの定義 [#l2aae90a]
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

** コンポーネントの状態をキャッシュする [#mefa900a]
#html(<div style="padding-left:10px;">)
#TODO(keep-alive)
#html(</div>)

** コンポーネント間の通信 [#o38b910b]
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

** コンポーネントへのデータの受渡し [#c2f2cd46]
#html(<div style="padding-left:10px;">)
#TODO(props)
#html(</div>)

** 単一ファイルコンポーネント [#i8a77772]
#html(<div style="padding-left:10px;">)

画面や部品単位でvueファイル化する事によってコンポーネント化する事ができる。
※以下、ドキュメントまま。

関連: [[Vue.jsでコンポーネント化された画面を切り替える]]

#mycode2(){{
<template>
  <p>&#123;&#123; greeting &#125;&#125; World!</p>
</template>

<script>
module.exports = {
  data: function () {
    return {
      greeting: 'Hello'
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>
}}

#html(</div>)

#html(</div>)

* ディレクティブ [#f5c8cd54]
#html(<div style="padding-left:10px;">)

** v-on ディレクティブによるイベントハンドリング [#s1153674]
#html(<div style="padding-left:10px;">)
https://jp.vuejs.org/v2/guide/events.html

- メソッドイベントハンドラ
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

- イベント修飾子
#html(<div style="padding-left:10px;">)
#TODO
.stop
.prevent
.capture
.self
.once
.passive
#html(</div>)

- キー修飾子
#html(<div style="padding-left:10px;">)
https://jp.vuejs.org/v2/guide/events.html#%E3%82%AD%E3%83%BC%E4%BF%AE%E9%A3%BE%E5%AD%90
#TODO
#html(</div>)


#html(</div>)

**  v-if ディレクティブによる条件付きレンダリング [#c8b15916]
#html(<div style="padding-left:10px;">)

v-if ディレクティブを使用して条件付きレンダリングを行う事ができる。

https://jp.vuejs.org/v2/guide/conditional.html

#mycode2(){{
<div id="app">
  <span v-if="display">Message1!</span>
  <span v-else>Message2!</span>
</div>

<script>
var app = new Vue({
  el: '#app',
  data: {
    display: true
  }
})

// 2秒後に表示を切り替える
setTimeout(function(){
    app.display = false
}, 2000);
</script>
}}

他に v-else-if や v-else も使用可能。
https://jp.vuejs.org/v2/guide/conditional.html#v-else
https://jp.vuejs.org/v2/guide/conditional.html#v-else-if
#html(</div>)

** v-bind ディレクティブによるプロパティのバインド [#i8d02a44]
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

** v-once で1回だけ描画する [#le63d8c9]
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

** v-text ディレクティブによるテキストの描画 [#q6a4c47f]
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

** v-html ディレクティブによるHTMLの描画 [#cefcbaf0]
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

**  v-model ディレクティブによる双方向データバインディング [#k1e776f5]
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

#html(</div>)

* データ通信 [#v20b9afb]
#html(<div style="padding-left:10px;">)

axios を使ってデータ通信を行う簡単なサンプル。

npm インストール
#myterm2(){{
npm install --save-dev axios
}}

利用例
#mycode2(){{
import Vue from 'vue';
import axios from 'axios';
export default {
  name: 'Page1',
  mounted: function(){
    axios
      .get('/path_to/sample.json')
      .then(response => {
        console.log(response)
      })
  },
}
}}

#html(</div>)

* ミックスイン [#ec0c1ace]
#html(<div style="padding-left:10px;">)

https://jp.vuejs.org/v2/guide/mixins.html

以下、ミックスインを使用して共通関数を定義する例を記載する。

src/components/MyMixin.js
#mycode2(){{
import axios from 'axios';

export default {
  name: 'MyMixin',
  data: function(){
    return {
      CONTEXT_ROOT: "/"
    }
  },
  methods: {
    getData: function(url, option, callback){
      console.log("get request: "+ this.CONTEXT_ROOT + url);
      axios
        .get(this.CONTEXT_ROOT + url, option)
        .then(response => {
          console.log(response);
          callback(response)
      })
    }
  }
}
}}

src/components/Page1.vue
#mycode2(){{
<template>
  <div class="main">
    <h1>Page1 content</h1>
    <div>&#123;&#123; results &#125;&#125;</div>
  </div>
</template>

<script>
import myMixin from '../components/MyMixin.js';

export default {
  mixins: [myMixin],
  name: 'Page1',
  data: function(){
    return {
      results: "データを読み込んでいます.."
    }
  },
  mounted: function(){
    this.getData(
      'sample.json',
      null,
      response => {
        this.results = response.data
      }
    );
  }
}
</script>
}}

#html(</div>)

* トランジション [#if82cd9f]
#html(<div style="padding-left:10px;">)
#TODO
#html(</div>)

* Vue Router を利用したSPA [#r456a4a8]
#html(<div style="padding-left:10px;">)

Vue CLI を使用してプロジェクトの作成を行う場合は、マニュアルモードで作成する。(以下 Vue CLI v3.11.0 にて作成する例)

** プロジェクトの作成 [#r312d6d3]
#myterm2(){{
vue create sample-vue-router

# 今回は手動インストールで以下の通り選択した。
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Use history mode for router? (Requires proper server setup for index fallback in production) No     ※1
? Pick a linter / formatter config: Basic
? Pick additional lint features: (Press  to select,  to toggle all,  to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) n
}}
※1 ... historyモードの場合は、URLはロケーションハッシュで表現しない。
   (Hisory API を使用してページのリロードなしに完全なURLとして表現される)


** 画面等の作成/変更 [#z4f966b0]

src/main.js
#mycode2(){{
import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
}}

src/App.vue
#mycode2(){{
<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/page1">Page1</router-link> |
      <router-link to="/page2">Page2</router-link> |
    </div>
    <div id="main">
      <router-view/>
    </div>
  </div>
</template>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>
}}

src/router.js
#mycode2(){{
import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    { path: '/'     , name: 'home' , component: () => import('./views/Home.vue')  },
    { path: '/page1', name: 'page1', component: () => import('./views/Page1.vue') },
    { path: '/page2', name: 'page2', component: () => import('./views/Page2.vue') },
  ]
})
}}

src/views/Home.vue
#mycode2(){{
<template>
  <h1>Home View</h1>
</template>

<script>
export default {
  name: 'home',
  components: {}
}
</script>
}}

src/views/Page1.vue
#mycode2(){{
<template>
  <h1>Page1</h1>
</template>

<script>
export default {
  name: 'page1',
  components: {}
}
</script>
}}

src/views/Page2.vue
#mycode2(){{
<template>
  <h1>Page1</h1>
</template>

<script>
export default {
  name: 'page2',
  components: {}
}
</script>
}}


#html(</div>)

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS