LoginSignup
0
3

More than 3 years have passed since last update.

Vue.js に関するメモ

Last updated at Posted at 2020-05-04

これを転載したもの
https://github.com/tac0x2a/vue_playground

Vue.js の基本

基本ルートのテンプレート

<body>
  <div id="app">
    <!-- ここに書く -->
  </div>
</body>
var app = new Vue({
  el: '#app',
  ...
})

appはセレクタ(#app)に対応。
アプリと配置する要素を紐付けることをマウントという。
var app に代入してもしなくてもよい。


ディレクティブ

ディレクティブ

ディレクティブとは、 DOM 要素に対して何かを実行することをライブラリに伝達する、マークアップ中の特別なトークンです。
Vue.js でのディレクティブのコンセプトは徹底的にシンプルです。Vue.js のディレクティブは、下記のフォーマットのように、接頭辞のついた HTML 属性の形でのみ表されます。

基本は以下。
ディレクティブ:引数.修飾子 =

(ex) v-bind:value.sync = "message"

Text(v-text="式", {{式}})

<!-- dataオプションにmessageプロパティが登録されているとして  -->

<!-- messageの値を表示 -->
<h1 v-text="message"></h1>

<!-- こう書く場合のほうが多そう -->
<h1>{{message}}</h1>

<!-- 42が表示される -->
<h1>{{40+2}}</h1>

繰り返し(v-for="ループっぽい式")

<!-- dataオプションにitemsプロパティがリストとして登録されているとして  -->

<li v-for="i in items">{{i}}</li>
<li v-for="(item, index) in items">{{i}}</li>

 <!-- 要素ごとに条件でclass設定できたりする -->
<li v-for="item in array" v-bind:class="{rainbow_badge: lv <= 50}" v-if="item != 'a'">

keyとしてユニークな値をとるプロパティを指定することで、要素の識別と効率的な描画処理が可能になる。keyがないと、リストが更新された際に、リスト内の全要素を再描画してしまう。(変化した要素をvueが特定できないため。)

<li v-for="item in array" :key="item.id">

条件

式を評価した結果に応じて要素を消したりする。値の真偽値解釈はJavaScriptの条件式と同じ。

v-if="式", v-show="式"

<!-- dataオプションにshowプロパティが登録されているとして  -->

<!-- DOMごと消える  -->
<div v-if="show">v-if {{show}}</div>
<template v-if="show"></template>

<!-- DOMには残るが、style="display: none;" 属性が付与されるため、消えたように見える -->
<div v-show="show">v-show {{show}} </div>
  • v-ifはDOMごと消えてるため、配下の要素で参照するプロパティの有無を条件に入れる等でエラー回避したりできる。また、監視が解除されて破棄されるため、次に描画されるときは状態が初期化されてしまう。v-ifは単一な要素にしか付与で機内が、template要素に付与することで、template配下の要素をまとめて消したりできる。
  • v-showは消えたように見えるだけ。切り替え頻度が高いものはこちらを使うのが良い。

v-else-if="式", v-else

いわゆるelseif節やelse節に相当。

データバインディング

属性のデータバインディング(v-bind:属性名="属性値の式")

  • <div key="id">: "id" という文字列
  • <div v-bind:key="id">: id というJavaScriptの変数の値が展開される

以下はどちらで書いても同じ

  • <div v-bind:key="id">
  • <div :key="id">

直値で与えた属性と併用する例。

<!-- dataオプションのurlプロパティは展開される。 -->
<!-- 直値で与えた属性と同じ名前のプロパティを指定する場合、プロパティの値で上書きされる -->
<a v-bind:href="url" href="https://default.com" target="_blank">URL</a>

クラスとスタイルのデータバインディング(v-bind:class="{属性名: 条件式, ...}", v-bind:style="{属性名: 式, ...}")

オブジェクトや配列をバインドすると、クラス名やCSSプロパティとして展開される。

<p v-bind:class="{a: isA, b: isB, c: isC }">
<p v-bind:style="{color: textColor, backgroundColor: bgColor}">
var app = new Vue({
  el: '#app',
  data: {
      isA: true,
      isB: false,
      isC: true,
      textColor: 'blue',
      bgColor: 'green',
  }
})

これで動かすと

<p class="a c">
<p style="color: blue; backgroundColor: green;">

となる。
classで指定する式は条件式として評価され、真となる値だけが残るようだ。
styleの方は値が文字列として展開されるようだ。

属性のデータバインディングと同じように、以下はどちらで書いても同じ。

  • <p v-bind:class={...}>
  • <p :class={...}>

オブジェクトデータを直接渡すこともできる。

<p v-bind:style="styleObject">
var app = new Vue({
  el: '#app',
  data: {
      styleObject: {
        color: 'blue',
        backgroundColor: 'green'
      }
  }
})

まとめてバインディングする(v-bind="評価するとobjectになる式")

以下はどちらで書いても同じ。

  • <img v-bind:src="item.src" v-bind:alt="item.alt" v-bind:width="item.width" v-bind:height="item.height">
  • <img v-bind="item">

一部だけ書き換えることもできる。

<img v-bind="item" v-bind:width="item.width*2">

イベントハンドリング(v-on:click="評価するとfunctionになる式", v-on:click="式")

  • v-on:click ボタンクリック時
  • v-on:load 画像などの読み込みが完了したとき
  • v-on:scroll 要素のスクロールイベント
  • v-on:mousewheel マウスホイールイベント
  • v-on:dragstart ドラッグ
  • v-on:input inputに値が入力された
<button v-on:click="handleClick">Click</button>

<!-- 引数を与える場合は()で指定する。ループの中でインデックスを与えたりして使う -->
<button v-on:click="bracket(42)">Click</button>
var app = new Vue({
  ...
  methods: {
    handleClick: function (event) {
      alert(event.target)
    },
    bracket: function (idx) {
      // 配列の要素を置き換える場合は $set を使う必要がある。
      // 代入すると配列要素が更新されただけになってしまうため、再描画されない。

      // $set は値をリアクティブデータとして追加する。
      this.$set(this.array, idx, "[" + this.array[idx] + "]")
      }
  }
})

以下はどちらで書いても同じ。

  • <button v-on:click="bracket(42)">Click</button>
  • <button @click="bracket(42)">Click</button>

もとのイベントはこんな感じで拾える。

<button v-on:click="handleClick($event)">Click</button>
var app = new Vue({
    ...
    handleClick: function (event) {
      alert(event.target)
    },
    ...
})

イベントの修飾子についてはこちら

コンポーネントはv-onでイベントをハンドルできるが、windowbodyについてはaddeventListenerメソッドで登録しておく必要がある。

フォーム入力バインディング(v-model="リアクティブデータの変数")

input 要素 や textarea 要素、 select 要素に双方向 (two-way) データバインディングを作成し、指定したリアクティブデータの変数に入力値がセットされる。

<input v-model="out" />
<input v-model="round" type="range" min="0" max="50" />

v-modelを使わずに、v-bindv-onで頑張ることもできる。自分でバリデーションしたいときはこっち?

<input v-bind:value="out" v-on:input="handleInput" />
var app = new Vue({
  ...
  methods: {
    // 10文字未満に制限する
    handleInput: function (event) {
      if (event.target.value.length < 10) {
        this.out = event.target.value;
      }
    },
  }
  ...
})

いろいろ

<!-- 文字列 -->
<input v-model="out" />

<!-- 複数行であっても文字列 -->
<textarea v-model="out" />

<!-- v-model.numberとすることで、プロパティに数値として値を設定できる -->
<input type="range" v-model.number="r">

<!-- "#008000" みたいな文字列 -->
<input type="color" v-model="col">

<!-- ラジオボックスは文字列 -->
<input type="radio" value="フシギダネ" v-model="poke"> フシギダネ キミにきめた! </label>
<input type="radio" value="ヒトカゲ" v-model="poke"> ヒトカゲ キミにきめた! </label>
<input type="radio" value="ゼニガメ" v-model="poke"> ゼニガメ キミにきめた! </label>

<!-- 択一なselectは文字列 -->
<select v-model="out">
  <option disabled="disabled">以下から選択!</option>
  <option value="a"> A </option>
  <option value="b"> B </option>
  <option value="c"> C </option>
</select>

<!-- 複数選択のselectは配列 -->
<select v-model="out" multiple>
  <option disabled="disabled">以下から選択!</option>
  <option value="a"> A </option>
  <option value="b"> B </option>
  <option value="c"> C </option>
</select>

<!-- チェックボックスはBoolean。値を指定することもできる -->
<input v-model="out" type="checkbox" />
<input v-model="out" type="checkbox" true-value="真" false-value="偽" />

複数のチェックボックスは配列にもできる

<label><input v-model="array" type="checkbox" value="a"> A </label>
<label><input v-model="array" type="checkbox" value="b"> B </label>
<label><input v-model="array" type="checkbox" value="c"> C </label>

<!-- AとCにチェックを入れると ["a", "c"] になる -->
<p>{{array}}</p>
var app = new Vue({
  ...
  data: {
    array: []
  }
  ...
})

修飾子についてはこちら
数値に変換したり(.number)、余白を取り除いたり(.trim)できる。

なお、画像などのtype="file"v-modelを使えないので、changeイベントをハンドルする。

<input type="file" v-on:change="handleChange">

算出プロパティ

計算をキャッシュしておいて、{{halfWidth}}のように参照できる。

var app = new Vue({
  computed: {
    halfWidth: function(){
      ...
      return width/2.0;
    },
    halfRect: function(){
      return {
        w: halfWidth,
        h: width*0.6 / 2.0
      }
    }
  }
})

functionの中でリアクティブデータを参照している場合、値が変更されると再計算される。
計算コストの高い処理結果をキャッシュするのに使える。例えばリストの絞り込み結果とか。

監視

var app = new Vue({
  watch: {
    監視対象のリアクティブデータやプロパティ: function(新しい値, 古い値){
      ...
    },
  }
})

フォームの入力を監視して、値が変更されたら検索APIコールして・・・みたいな使い方で動的検索ができる。

フィルタ

var app = new Vue({
  filters: {
    bracket: function(v){
      return "[" + v + "]"
    },
    upper: function(v){
      return v.toUpeerCase()
    }
  }
})
<p>{{ str | upper | bracket }}</p>

methodsとよく似ているが、文字列を加工するときは便利。
パイプみたいになっていて、左から右へデータが流れていく。

カスタムディレクティブ

v-から始まるディレクティブを自分で作れるらしい。


コンポーネント

JavaScriptとテンプレート(HTML, CSS)を1つにまとめたもの。帰納単位に分離して開発する仕組み。

コンポーネントはWebにも転がっている
awesome-vue
https://github.com/vuejs/awesome-vue

Vue Curated
https://curated.vuejs.org/

element
https://github.com/ElemeFE/element
紹介記事: https://s8a.jp/vue-js-library-element

Onsen UI
https://ja.onsen.io/
モバイル向けのUIを簡単につくれる。良さそう。

コンポーネントを自作する

グローバルに登録

Vue.component('new-component', {
  template: '<p>New Component!!</p>',
  data: function(){
    return {
      ...
    }
  },
  methods: {
    ...
  }
})
<div id="app">
  <!-- どのVueテンプレートからでも参照できる -->
  <new-component></new-component>
  <!-- <p>New Component!!</p> として表示される -->
</div>
  • new Vue()と同じように定義する。ただし、dataはObjectを返すfunctionになっていなければならない。
  • templateで指定するhtmlはツリーになってないとだめ。ルートは1つ。<div>とかでくくっておくのがよい。
  • コンポーネントはネストできる。

ローカルへの登録

var newComponent = {
  template: '<p>New Component!!</p>'
  data: function(){
    return {
      ...
    }
  },
  methods: {
    ...
  }
}

var app = new Vue({
  el: '#app',
  components: {
    //これで<new-components>が使用できるようになる
    'new-components': newComponents
  }
})

基本的にローカル登録にしておいてスコープを絞っといたほうがいい。

コンポーネント間の通信

ネストしたコンポーネントの親から子(props down)

静的に値を渡す。引数の値渡しみたいな感じ?

<!-- 親のテンプレート -->
<child name='Mario', age=10></child>
<child name='Luigi', age=8></child>
Vue.component('child', {
  template: '<p>{{name}}({{age}})</p>',

  props: ['name', 'age'] //ここで受け取る属性を指定する

// 型指定することもできる
// props: {
//   name: String
//   age: Number
// }
})

リアクティブデータを渡す場合
html
<child v-bind:name='Mario', age=10></child>

これで、親側でnameを変更すると、子のnameが変更される。

ネストしたコンポーネントの子から親(event up)

<!-- 親 -->
<child v-on:child-event="parentsHandler"></child>
// 子
this.$emit('child-event')

$emit('イベント名', 引数,...,)を使う。子要素のボタンを押したときに、親要素をどうこうしたいときに。

親子で双方向のデータバインディングする(v-model)

<!-- 親 -->
<child v-model:"date"></child>

<!-- 上記は以下の糖衣構文 -->
<child v-bind:value="date" v-on:input="date = $event"></child>
// 子から以下のように$emitすることで、dateが自動で更新される。
// v-modelで子へ渡されるプロパティはvalueなので、子側のpropsに指定するのを忘れないように!
this.$emit('input', '20210-04-28')

いくつもバインドする場合は .sync 修飾子を使う。

親子ではないコンポーネント間

var bus = new Vue() //イベントバス。

var bus = new Vue({
  data: {
      ... //値をもたせることもできる。
  }
})

というのを作っておいて

// 受け取る方
bus.$on('何らかの-event', function(){
  ...
})
// eventを発行する方
bus.$emit('何らかの-event')

スロット

親コンポーネントから、子コンポーネントのテンプレートの一部に何かを差し込むのに使う機能。

<!-- 子のテンプレート -->
<p>ここに入る→ <slot></slot><p>
<!-- 親 -->
<child>これを入れる</child>

<!-- するとこんな感じになる -->
<p>ここに入る→ これを入れる</p>

<slot> タグが置き換わる。 <slot name=''> とすることで複数のスロットを名前付きで挿入することができる。

ほかにもいろいろ使えるらしい。


Vue でアプリを作る

  • Vuex: 状態管理用ライブラリ。複数コンポーネントでのデータ共有や、アプリの状態の一元管理を行う。
  • Vue Router: 複数の画面とURLを紐付ける、SPA構築用ライブラリ

Vue CLI

アプリ構築用ツール郡のCLI。
かんたんにwebpackで単一ファイルコンポーネントを作ることができる。

webpackとは

内部ではBabel使ってるらしい。

プロジェクトを作る

参考: Creating Project

$ vue create <プロジェクト名>
  # 対話形式で色々設定する。 `vue ui` でブラウザから同様のプロジェクト作成を行える。
$ cd <プロジェクト名>
$ npm run serve

http://localhost:8080/ にアクセスすると、アプリ画面が表示される。

参考: Vue CLI3について

ビルド設定のカスタマイズは、プロジェクトルートに vue.config.js というファイル作成してそこに追加していきます。

単一ファイルコンポーネント(.vueファイル)

単一ファイルコンポーネント(SFC, Single File Components) として、 HTML/JavaScript/CSSをまとめた .vueファイル単位で管理する。

index.html
<div id="app"></div>
index.js
import Vue from "vue";
import App from "./Hello";

Vue.config.productionTip = false;

new Vue({
  el: "#app",
  template: "<App/>",
  components: { App }
});
Hello.vue
<template>
  <p>{{ greeting }} World!</p>
</template>

<script>
export default {
  data: function() {
    return {
      greeting: "Hello"
    }
  }
};
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>
  • <template> : コンポーネントのテンプレート部分。必要なパッケージ入れて lang="jade" とすると Jadeで書けたりする。
  • <script>: コンポーネントのテンプレート以外の部分。
  • <style>: CSSの部分。scoped にすると、このコンポーネントとその配下のコンポーネントで有効になる。こちらもlang=stylusでStylusで書けたりする。

Vuex

Vuexとは何か?

Vuex は Vue.js アプリケーションのための 状態管理パターン + ライブラリ

あなたのアプリがシンプルであれば、Vuex なしで問題ないでしょう。

コンポーネント横断で使えるリアクティブなグローバル変数群?

src/store.js
const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment: state => state.count++
  }
})

export default store
import store from '@/store.js' // @はsrcのエイリアス

console.log(store.state.count) // -> 0
store.commit('mutation')
console.log(store.state.count) // -> 1

複数のコンポーネントで使う場合はnew Vueするときに指定する

src/App.vue
import store from './store.js'
new Vue({
  ...
  store,
  ...
})

適当なコンポーネント.vue

export default {
  craeted() {
    console.log(this.$store.state.count)
    this.$store.commit('increment')
  }
}

this.$state でアクセスする。

Vue Router

コンポーネントとURLを紐付けてコンテンツを生成し、SPAを構築するための拡張ライブラリ。

Vue Router

Vue Router は Vue.js 公式ルータです。これは Vue.js のコアと深く深く統合されており、Vue.js でシングルページアプリケーションを構築します。機能は次の通りです:
・ネストされたルート/ビューマッピング
・モジュール式、コンポーネントベースのルータ構造
・ルートパラメータ、クエリ、ワイルドカード
・Vue.js の transition 機能による、transition エフェクトの表示
・細かいナビゲーションコントロール
・自動で付与される active CSS クラス
・HTML5 history モードまたは hash モードと IE9 の互換性
・カスタマイズ可能なスクロール動作

準備

$ npm install vue-router

使ってみる

慣例として、ルートに直接紐づくコンポーネントはviewspagesのようなディレクトリにまとめることが多い。

src/views/Home.vue
<template>
  <h1>Home</h1>
</template>
src/views/Product.vue
<template>
  <h1>Product</h1>
</template>
src/router.js
import Vue from 'vue'
import VueRouter from 'vue-router'

import Home from '@/views/Home.vue'
import Product from '@/views/Product.vue'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    { path: '/', component: Home },
    { path: '/product', component: Product },
  ]
})

export default router
src/main.js
import Vue from 'vue'
import App from './App.vue'

import router from '@/router.js'

Vue.config.productionTip = false

new Vue({
  router: router,
  render: h => h(App),
}).$mount('#app')
src/App.vue
<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link>
      <router-link to="/product">Product</router-link>
    </nav>
    <router-view />
  </div>
</template>

これで、 http://localhost:8080 にアクセスすると、"Home" と "Product" リンクが生成されて、クリックするとそれぞれのコンポーネントが <router-view />の位置に表示される。

ハッシュモードとヒストリーモード

HTML5 History モード

vue-router のデフォルトは hash モード です - 完全な URL を hash を使ってシミュレートし、 URL が変更された時にページのリロードが起きません。
history モードを使用する時は、URL は "普通" に見えます e.g. http://oursite.com/user/id 。美しいですね!

ヒストリーモードを有効にするには、VueRoutermodeプロパティを'history'にして、サーバの設定を変更する必要がある。

src/router.js
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})
nginxの例
location / {
  try_files $uri $uri/ /index.html;
}

その他サーバの設定方法はこちら参照。

ルート定義のオプション

...
const router = new VueRouter({
  mode: 'history',
  routes: [
    {
      name: 'prod',
      path: '/product/:id', //URLからパラメータを受け取る場合はこう書く。
      //path: '/product/:id(\\d+)', //正規表現で数字のみにマッチさせることもできる
      compnent: Product,
      meta: { requiresAuth: true } //認証が必要な場合はtrue
    },
    {
      name: 'prodlist',
      path: '/product', // パラメータなしの場合はrouteを別にすることもできる。
      compnent: ProductList,
      meta: { requiresAuth: true } //認証が必要な場合はtrue
    }
  ],
  // リダイレクトの設定。リダイレクト先はパスまたは名前で指定する
  { path: '/a', redirect: '/product' },
  { path: '/a', redirect: { name: 'prod'} },
})

受け取ったパラメータはこのように参照する。

this.$route.params.id //URLパラメータを受け取る
this.$route.query.id //クエリパラメータを受け取る場合はこう

$route は マッチしたルートの情報が入ったオブジェクト。

ちなみに、パラメータは$routeではなくpropsとして受け取っておいたほうがいい。ユニットテストがしやすいので。

src/Product.vue
<template>
  <div>
    <h1>Product</h1>
    <div v-if="pid">Param: ID:{{pid}}</div>
    <div v-if="qid">Query: ID:{{qid}}</div>
  </div>
</template>

<script>
export default {
  props: {pid: Number,  qid: Number} //受け取るパラメータ
}
</script>
src/router.js
...
const router = new VueRouter({
  routes: [
    { path: '/', component: Home },
    { path: '/product', component: Product },
    {
      path: '/product/:id(\\d+)',
      component: Product,
      props: r => ({ qid: r.query.id,  pid: r.params.id}) //こんな感じで。
    },
  ]
})
...

ナビゲーション

<template>
  <div id="app">

    <!-- 基本はこれ -->
    <router-link to="/product"></router-link>

    <!-- テンプレートリテラルを使う場合。込み入った記述をするとき便利 -->
    <!-- =より右をJavaScriptの式として評価したい場合は `:to` を使うっぽい -->
    <router-link :to="`/product/${ id }`"></router-link>

    <!-- aタグ以外で囲みたい場合は`tag`で指定する -->
    <router-link to="/product" tag="button"></router-link>

    <!-- objectで指定できる。パラメータを渡す場合に便利か -->
    <!-- paramsを渡す場合は、routerにnameを登録しておく必要がある -->
    <router-link :to="{ path: '/product' }"></router-link>
    <router-link :to="{ path: '/product', query: { id: 42 } }"></router-link>
    <router-link :to="{ name: 'prod', params: { id: 42 } }"></router-link>

  </div>
</template>

アクティブなルートにマッチする router-link には .router-link-exact-active.router-link-active が付与されるので、簡単にハイライトできる。

.router-link-exact-active {background: #ff00ff} //完全一致したルート
.router-link-active {background: #ff00ff} //マッチしたパスを含むルート

コードから遷移するには $router に対していろいろやる

this.$router.push('/product') // push, replace, go
this.$router.push({name: 'prod', params: { id: 1}}) //router-linkのようにパラメータを渡すこともできる

動的ルートのサンプル

ポケモン図鑑(Pokedex)を作る。データは src/DummyPokedex.jsにハードコードしたダミーを使う。

src/App.vue
<template>
  <div id="app">
    <nav>
      <router-link to="/">Home</router-link>
      <router-link to="/pokemon">Pokedex</router-link>
    </nav>
    <img alt="Vue logo" src="./assets/logo.png" />
    <p>
      <router-view />
    </p>
  </div>
</template>

<script>
export default {
  name: "App"
}
</script>
src/api/DummyPokedex.js
const pokedex = [
  { number: 1, name: "フシギダネ", types: ["くさ", "どく"], height: 0.7, weight: 6.9 },
  { number: 4, name: "ヒトカゲ", types: ["ほのお"], height: 0.6, weight: 8.5 },
  { number: 7, name: "ゼニガメ", types: ["みず"], height: 0.5, weight: 9.0},
]

//ダミーデータとアクセス用のAPIを定義する
export default {
  fetchAll() { return pokedex },
  findFirst(number) { return pokedex.find(p => p.number == number) },

  // DB等から読み込んでるように振る舞わせるため、`setTimeout` で2秒後にコールバックする
  asyncFindFirst(number, callback) {
    setTimeout(() => {
      callback(this.findFirst(number))
    }, 2000) // 2000ms 後に callbackする
  }
}
src/router.js
import Vue from 'vue'
import VueRouter from 'vue-router'

import Home from '@/views/Home.vue'
import Pokedex from '@/views/Pokedex.vue'
import Pokemon from '@/views/Pokemon.vue'

Vue.use(VueRouter)

const router = new VueRouter({
  routes: [
    { path: '/', component: Home },
    { path: '/pokemon', component: Pokedex },
    {
      path: '/pokemon/:number(\\d+)',
      component: Pokemon,
      props: route => ({
        number: Number(route.params.number)
      })
    },
  ]
})

export default router
src/views/Pokedex.vue
<template>
  <div>
    <h1>Pokedex</h1>
    <ul>
      <!-- ポケモン一覧をを表示する -->
      <li v-for="{number, name} in pokedex" :key="number">
        <router-link :to="`/pokemon/${number}`">No.{{number}} {{name}}</router-link>
      </li>
    </ul>
  </div>
</template>

<script>
import Pokedex from '@/api/DummyPokedex.js'

export default {
  computed: {
    pokedex: () => Pokedex.fetchAll()
  }
}
</script>
src/views/Pokemon.vue
<template>
  <div>
    <div v-if="pokemon">
      <h1>No. {{pokemon.number}} {{pokemon.name}}</h1>
      <h2>体長:{{pokemon.height}}[m] 重さ:{{pokemon.weight}}[kg]</h2>
      <h2>タイプ</h2>
      <p v-for="type in pokemon.types" :key="type">{{type}}</p>
    </div>
    <div v-else>
      <h2>Loading...</h2>
    </div>
  </div>
</template>

<script>
import Pokedex from '@/api/DummyPokedex.js'

export default {
  props: {number: Number},
  data(){
    return {pokemon: null}
  },
  // computed では this.numberを参照できないので、watch で numberを監視するように。
  watch: {
    number: {
      handler(){
        // 遅延読み込みした結果を格納する
        Pokedex.asyncFindFirst(this.number, pokemon => {
          this.pokemon = pokemon
        })
      }, immediate: true //ここがtrueじゃないと、すぐにhandlerが呼ばれない。
    }
  }
}
</script>

src/views/Pokemon.vue の下に子コンポーネントを作る場合は、src/views/Pokemon/*.vue とするのがいいらしい。

遷移アニメーション

<transition name="viewwww">
  <router-view />
</transition>
...
<style>
.viewwww-enter-active {
  transition: opacity 0.5s;
}
.viewwww-enter, .viewwww-leave-to {
  opacity: 0;
}
</style>

nameに指定したviewwwwが一致してないといけない。

ナビゲーションガード

遷移を操作するためのフック。

  • to(): 遷移後のrouteオブジェクトを受け取る
  • from(): 遷移前のrouteオブジェクトを受け取る
  • next(): これを呼ぶとフックが解決してrouteの遷移が行われる。遷移を中止する場合はnext(false)をコールする。next('/pokemon')などで任意のrouteにリダイレクトもできる。
const router = new VueRouter({
  routes: [
    ...
    {
      path: '/pokemon',
      component: Pokedex
      beforeEnter(to, from, next){ //このrouteへ遷移する前に呼ばれる。
        next() //遷移してもOKな場合に呼ぶ
      }
    },
    ...
  ]
})
//グローバルなガードも使える
router.beforEeach((to, from, next) => {
//コンポーネントガード解決前に呼ばれる
...
})

router.afterResolve((to, from, next) => {
//コンポーネントガード解決後に呼ばれる
...
});

router.afterEeach((to, from) => { // 遷移が終わってから呼ばれるのでnextは使えない。
//すべてのルートの遷移後に呼ばれる
...
});
<script>
export default {
  // beforeRoute{Enter, Update, Leave} が使える

  beforeRouteEnter(to,from,next){
    // この時点ではコンポーネントのインスタンスはまだ作られていないので、thisにアクセスできないことに注意。
    next(vm => {
      // vm には VueComponent が入っている
      // このコールバックでthisにアクセスできる。
    })
  }
}
</script>

beforEeachとかで、認証認可のチェックができる?


ES2015(ES6)関連

文法いろいろ

// 変数宣言
// var x = 0 //スコープ広い
let x = 0 //スコープ内でのみ有効
const y = 42 //再代入不可

// function
new Vue({
  methods: {
    // 以下は handle: function(){ ... } と同じ。
    // プロパティとして関数を宣言するときは function を省略できる。
    handle(){  ...  }
  }
})

//アロー関数
let hoge = () => "hoge"
let fuga = arg => "fuga and " + arg
let piyo = (arg1, arg2) => {
  let joined = arg1 + "piyo" + arg2;
  return joined;
}

//テンプレートリテラル
let template = `
  <div class="sample">
    <p>${ this.variable }</p>
  </div>`

// オブジェクトプロパティのショートバンド
let short = {
  hoge, fuga // 変数名がプロパティの名前になる
}
// let short = {
//   hoge: hoge,
//   fuga: fuga
// }

// 多重代入(分割代入)
let [a,b] = [1,2] // aに1, bに2が代入される
let { a } = {a:'A', b:'B', c:'C'} // a に 'A'が 代入される

// スプレッド演算子
let args = [1,2]
piyo(...args) // piyo(1,2)と同義
let args_ex = [ ...args, 3] // [1,2,3]

モジュール定義とインポート

Sample.js
var state = {
  count: 1
}

export default state

export default state は、デフォルトのimport文で呼ばれたときに返すデータを定義している。

import Sample from './Sample.js'

みたいに書くと、stateのオブジェクトをSampleという変数名としてインポートする。

export default vs module.exports =

こちら参照

・基本的にはexport defaultを使う
・複数のモジュールをexportするときはexportを使う
・受け取り側はimportを使う

require vs import

こちら参照

モジュール読み込みの仕様の主要なものとして、ESM (ECMAScript Modules)とCJS (CommonJS Modules)があります。
importを使うのがESM方式で、requireを使うのがCJS方式
require文は、CommonJSの仕様で、Nodejsの環境で動作してくれる書き方です。Nodejs環境ということはつまり、サーバサイドでの実行ということになります。

import を使うのが良さそう。


メモ

開発環境

Ubuntu(WSL)環境にNode.jsをインストールする

$ sudo apt update
$ sudo apt install nodejs npm
$ sudo npm install n -g
$ sudo n stable
$ # sudo apt purge -y nodejs npm #古いのは消すex

Vue CLI

$ sudo npm install -g @vue/cli
$ vue --version
@vue/cli 4.3.1

VS Codeに入れた拡張

  • ESLint
  • Prettier
  • Veture (主な使い方はこここのあたりも参考に。)
  • Vue Peek
  • Auto Rename Tag

いろいろ

  • <ol>: 連番
  • <ul>: だけ。
0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3