20200206のvue.jsに関する記事は8件です。

vue.jsの下準備とimportについて

Vue.jsの開発を始めるまでの下準備と、Vue.jsで必ず必要になるimportについて、正確に理解したいと思います。

WebCLIとは

WebCLIとは、Vue.jsで作成するアプリの骨格を作ってくれるコマンドラインツールのことです。
Vue.jsを学習する中で、最初はCDN経由でVue.jsを呼び出して使っている方も多くいると思います。
CDNとはコンテンツを配布するためのネットワークのことです。
WebCLIを使うと、プロジェクトを作成するのもターミナル経由で行うことができるようになります。

vue create プロジェクト名

でプロジェクトの作成をすることができます。

プロジェクトの骨格

CLI経由で作成されたプロジェクトは多くのファイルから構成されていますが、主に使うのはsrc(ソースコード)に入っているファイルになります。

components

コンポーネント。細かく使い回す部品を管理するフォルダ

views

ページに関するvueファイルを入れるフォルダ。

App.vue

アプリ共通で管理するコンポーネントが集まったファイル。ヘッダーやフッターなどが入っている。

main.js

最初に読み込まれるファイル。この中に、最初に読み込ませたいファイル、やるべき処理を入れておく。
main.jsには以下のようなコードがある。

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

まず、 new Vue は新しくVueインスタンスを作成するということです。
その中にはオプションオブジェクトが入っており、これはこのようなコードに変換されます。

new Vue({
  el: '#app',
  components: { App },
  template: '<App />'
})

つまり、アプリを開始したときにAppエレメントがインスタンスとして作成されるということです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js v3 をつくって学ぶ リアクティブシステム

本記事では、Vue.js v3 のコア部分であるリアクティブシステムを実装し、その仕組みを学びます。

今回実装するリアクティブシステムを用いれば、以下のような簡単なアプリケーションが作れます。

simple-vue-app.gif

最終的なコードはGitHubにあります。
https://github.com/hareku/simple-vue-reactivity

リアクティブとは

「リアクティブである」とは、「その値が監視され、変更が検知される状態のこと」を指します。

Vue.jsやReactでは、コンポーネントが保持している状態を変更すれば、その変更が検知されてHTMLに反映されます。それらを実現するためには、値の変更を検知可能な状態にするリアクティブシステムが必要です。

Vue.js v3 におけるリアクティブシステム

Vue.js のリアクティブシステムは、主に以下の3つで構成されます。

  • ref
  • effect
  • computed

まずはrefeffect を使ったサンプルコードを見てみましょう。

ref-effect-example.ts
const counter = ref(0) // 0 は object になり、valueプロパティでアクセスできる

// counter.value が変更されたら、effectの引数に渡した関数が自動で再実行される
let double = 0
effect(() => {
  double = counter.value * 2
})

console.log(double) // 0
counter.value = 5
console.log(double) // 10 <- Changed!

このように ref でリアクティブにした値を effect に渡した関数内で参照すれば、変更を検知して自動で関数を再実行してくれます。

これは一見すると魔法のようですが、単純な仕組みがあります。
それでは、これらのリアクティブシステムを実装していきましょう。

リアクティブシステムの実装

※Vue.js はオブジェクトもリアクティブにできるのですが、今回は簡略化のためオブジェクトには対応しません。数値や文字列などのオブジェクトではない値のみ、リアクティブにします。

Ref の実装

ref 関数は、引数で渡した値をリアクティブにします。

ref に渡した値が value をキーとしたオブジェクトに変換される理由は、getter/setter によるフック処理を行うためです。

ref.ts
export function ref(value: any) {
  return {
    get value() {
      // TODO: track
      return value
    },
    set value(newVal) {
      value = newVal
      // TODO: trigger
    }
  }
}

JavaScript では、object のプロパティ名に get/set を付けることで getter/setter を実装できます。

TODO の通り、getter に「値が使われていることを知らせる処理 (track)」と、setter に「値が変更されたことを知らせる処理 (trigger)」が必要です。これらの処理は、次に解説する effect 関数に依存しているため、そちらで実装します。

Effect の実装

それでは effect 関数を実装します。これはとてもシンプルです。

effect.ts
let activeEffect: Function | null = null

export function effect(fn: Function) {
  activeEffect = fn
  fn()
}

effect 内では、引数に渡された関数を activeEffect という変数に格納しています。この変数は次のトラッキング処理で用います。

トラッキング処理(track)

次は ref の getter で必要なトラッキング処理である track を実装します。

ref.ts
const ref = {
  get value() {
    track(ref) // これを実装する
    return value
  },
  set value(newVal) {
    value = newVal
    // TODO: trigger
  }
}

track は、どの effect がどういった ref に依存しているかという依存関係を管理します。
一度 track のコードを見てみましょう。

effect.ts
// Set はユニークな値のみを格納できる配列
// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Set
type Deps = Set<Function>

// WeakMap は Object をキーにできるオブジェクト
// targetMap では ref をキーとして、参照している effect のリストを格納する
const targetMap = new WeakMap<object, Deps>()

export function track(target: object) {
  // target (ref) に依存している関数リスト (deps) を取得する
  let deps = targetMap.get(target)

  // deps がなければ初期化する
  if (deps === undefined) {
    deps = new Set()
    targetMap.set(target, deps)
  }

  // 現在実行中の effect 関数を依存関係 (deps) に追加する
  if (activeEffect && !deps.has(activeEffect)) {
    deps.add(activeEffect)
  }
}

複雑に見えますが、やっていることは WeakMap で ref に依存している effect リストを管理しているだけです。

これらの依存関係をもとに、次のトリガー処理で、特定の ref に依存している effect をすべて再実行できます。

トリガー処理(trigger)

ref の setter 時の処理であるトリガーを実装します。

ref.ts
const ref = {
  get value() {
    track(ref)
    return value
  },
  set value(newVal) {
    value = newVal
    trigger(ref) // これを実装する
  }
}
effect.ts
export function trigger(target: object) {
  // target に依存している effect リストを取得する
  const deps = targetMap.get(target)
  if (deps === undefined) {
    return
  }

  // target に依存している effect を全て再度実行する
  deps.forEach(effect => {
    effect()
  })
}

これにより、 ref の value が更新されるたびに、依存関係にある effect を全て再実行することができます。これが Vue.js におけるリアクティブシステムの仕組みです。

computed

先ほど実装した refeffect を組み合わせれば、Vue.js の computed を実装できます。

まずは computed の仕様の確認のため、jest でテストを書いてみます。

computed.test.ts
describe('reactivity/computed', () => {
  it('should observe ref', () => {
    const counter = ref(0)
    const double = computed(() => counter.value * 2)

    expect(double.value).toBe(0)
    counter.value = 5
    expect(double.value).toBe(10)
  })
})

computed を実装すれば、わざわざ effect の外に定義していた let double のような変数を省略することができます。computedはこのように実装します。

computed.ts
export function computed<T = any>(getter: () => T): { value: T } {
  let value: T
  effect(() => {
    value = getter()
  })

  return {
    get value() {
      return value
    }
  }
}

アプリケーションの実装

それでは実装したリアクティブシステムを用いて、冒頭のサンプルアプリケーションを実装してみましょう。

simple-vue-app.gif

HTML

JavaScript 側で操作するために、各タグに適当な id を付与しておきます。

app.html
<div>
  <span id="count"></span> * 2 = <span id="multiplied"></span>
</div>
<div>
  <button id="increment">Increment ++</button>
  <button id="decrement">Decrement --</button>
</div>

JavaScript

まずは、 count とそれを2倍した値である multiplied をリアクティブな値として作ってみます。

app.ts
const count = ref(0)
const multiplied = computed(() => count.value * 2)

そして、effect 関数内で HTML の操作を行います。

app.ts
const countElement = document.getElementById('count')
const multipliedElement = document.getElementById('multiplied')

effect(() => {
  countElement.innerText = String(count.value)
  multipliedElement.innerText = String(multiplied.value)
})

次に値を増減させるため、ボタンにクリックイベントを登録します。

app.ts
const incrementButton = document.getElementById('increment')
const decrementButton = document.getElementById('decrement')

incrementButton.addEventListener('click', () => {
  count.value++
})
decrementButton.addEventListener('click', () => {
  count.value--
})

addEventListener に渡した関数内で count.value を変更しているので、変更する度に effect 内の HTML 操作が実行され、Viewが更新されます。

これでアプリケーションの完成です。

最終的なアプリケーションコード

app.ts
import { ref } from '../ref'
import { effect } from '../effect'
import { computed } from '../computed'

const countElement = document.getElementById('count')
const multipliedElement = document.getElementById('multiplied')
const incrementButton = document.getElementById('increment')
const decrementButton = document.getElementById('decrement')

if(countElement && multipliedElement && incrementButton && decrementButton) {
  const count = ref(0)
  const multiplied = computed(() => count.value * 2)

  incrementButton.addEventListener('click', () => {
    count.value++
  })
  decrementButton.addEventListener('click', () => {
    count.value--
  })

  effect(() => {
    countElement.innerText = String(count.value)
    multipliedElement.innerText = String(multiplied.value)
  })
}

次なるステップ

本記事の解説は以上になります。

さらに理解を深めるためのステップとしては、オブジェクトのリアクティブ化があります。対応方法として、依存関係を管理していた WeakMap をさらに深くし、オブジェクトの各キーごとの effect を管理する手法があります。
また他にできることとして、プロパティの追加や削除への対応や、監視を浅く (shallowに) してパフォーマンスを改善することなどがあります。

実装したい方は Vue.js v3 のソースコード (@vue/reactivity) が参考になります。
https://github.com/vuejs/vue-next/tree/master/packages/reactivity

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js ネコ本チュートリアルのToDoリストを少しアレンジしてみた

はじめに

最近Vue.jsの学習を始めたので、アウトプットがてらToDoリストを作成してみました。
※プログラミングの勉強を始めて3か月ほどなので突っ込みどころありましたらご教授いただけますと幸いです。

自作したToDoリスト

以下が、自作したToDoリストです。
コメント 2020-02-06 211639.jpg
自作ToDoリスト
勉強がてらデザインにはBootstrapを使用してみました。

参考

参考にさせていただいたのは以下のチュートリアルです。
ToDoリストを作りながら学習しよう!

個人的にはVue.jsを学ぶ上で大変お世話になっている本(通称ネコ本)です。

Let's アレンジ

アレンジがカタカナになってるのは見栄えです。(センス・・・)

本チュートリアルでは、状態が完了と着手中の2パターンの切り替えになってるところを、
アレンジ精神で3パターンの切り替えにしたいなと思い保留を追加してみました。

具体的に変更したところは2点。

①使用するデータを追記

変更前

main.js
  data: {
    todos: [],
    current: -1,
    options: [
      { value: -1, label: 'すべて' },
      { value: 0, label: '作業中' },
      { value: 1, label: '完了' }
    ]
  },

⇓⇓⇓

変更後

main.js
  data: {
    todos: [],
    current: -1,
    options: [
      { value: -1, label: 'すべて'},
      { value: 0, label: '着手'},
      { value: 1, label: '完了'},
      { value: 2, label: '保留'}
    ]
  },

※個人的に扱いやすいように数字を変更してます。

②メソッドを変更する

main.js
    doChangeState: function (item) {
      item.state = !item.state ? 1 : 0
    },

⇓⇓⇓

変更後

main.js
    doChangeState: function(item){
      if(2 > item.state){
        item.state = item.state + 1
      } else {
        item.state = 0
      }
    },

三項演算子から条件分岐に変更しました。

JavaScript初心者なので、三項演算子だとわかるまでめちゃくちゃ理解に苦しみました。
(もう少し基礎を学んだほうがいいのは間違いない・・・)

補足

三項演算子は以下の形で条件式がtrueなら式1をfalseなら式2を返します。

条件式 ? 式1 : 式2 

まとめ

Laravelを学んでいく中でフロントサイドでVue.jsを使ってみたくなり学び始めました。

両FWともに様々なチュートリアルがありますが、アレンジ~自作ポートフォリオ完成までには、
しっかり1つ1つのスクリプトの意味を理解していかなければいけないと痛感しました。

引き続きアウトプットしながら学習をしていきたいと思います。
拙いアウトプットですがどなたかの参考になりましたら幸いです。

追記

PWA化してみました。
iPhoneですとSafariで以下にアクセスしてホーム画面に追加していただくと機内モードでも利用できます。
[自作ToDoリスト※PWA化]https://asobi.fun/index.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vueとaxiosを使って外部APIからデータを取得する

new Vue({
  el: '#fetchUsers',
  data: {
    users: []
  },
  mounted() {
    axios.get('/users')
      .then(response => (this.users = response.data))
    }
});
<div id="fetchUsers">
  {{users}}
</div>

結果

{userId: 1, userName: sato}, {userId: 2, userName: tanala}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vuetify2系で SortableJS つかって v-simple-table を ドラッグ&ドロップさせる

■ 参考
drag-n-drop in Vuetify — Part II - Vuetify - Medium
https://medium.com/vuetify/drag-n-drop-in-vuetify-part-ii-2b07b4b27684
SortableJS/Sortable
https://github.com/SortableJS/Sortable
Vuetify Simple tables
https://vuetifyjs.com/ja/components/simple-tables

■ 完成品

See the Pen Vuetify 2.x v-simple-table drag and drop by mykysyk (@mykysyk) on CodePen.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxtのページ表示速度が遅かったので、色々改善方法のメモ

はじめに

Nuxt, TypeScriptで速度とかを深く考えず実装を進めていったら、
ページ表示速度が著しく遅かったので色々と勉強したメモ。

前提

Nuxt 2.11.0
TypeScript導入済み
Nuxt generateして運用

速度改善

どこが遅いのか、とかを色々しらべると
- 画像が多い画面なので画像の読み込みに時間がかかる。
- node moduleが重い
- componentsのimportが無駄なものがあったり、importの仕方がまずい
とかが原因と思われました。
ちなみに改善する前のGoogle のpagespeed insights で測ったら真っ赤っかでした。

画像の読み込み改善

画像の遅延読み込みの実装

vue-lazyloadを使います。

yarn add vue-lazyload

nuxtで使えるようにしていきます。

~/plugins/vue-lazyload.ts
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload, {
  preLoad: 1.1,
  attempt: 1,
  observer: true,

  observerOptions: {
    rootMargin: '0px',
    threshold: 0.1
  }
})

オプションは、vue-lazyloadのドキュメントを読んでください。たぶん、このまま使って大丈夫です。
pluginをnuxt.config.tsで読み込みます。

nuxt.config.ts
  plugins: [
    { src: '~plugins/vue-lazyload', ssr: false }
  ]

vue用に作られたmodulesをnuxtで使う場合pluginを書いて、configで読み込んだらだいたい使える気がします。
これでlazyloadの準備ができました。

実際componentsなどで使う場合

hoge.vue
<template lang="pug">
div
  img(v-lazy='hoge.jpg', alt='')
</template>

とう感じに、src の代わりに v-lazy を使ってください。
これでlazyloadが実装できました。
これだけで画像関連は十分ですが、せっかくなのでwebpも使える様にします。

Webpと通常の画像の出し分け

lazyloadの実装に使ったvue-lazyloadを使ったらいい感じにwebpの出し分けも実装できました。
pluginを書き直しましょう。

~/plugins/vue-lazyload.ts
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload, {
  preLoad: 1.1,
  attempt: 1,
  observer: true,

  observerOptions: {
    rootMargin: '0px',
    threshold: 0.1
  },
  filter: {
    webp(listener: any, options: any) {
      if (!options.supportWebp) return
      listener.src = 'hoge.webp'
    }
  }
})

filterを追加します。
ここで、ブラウザがwebpに対応していればwebpのパスを返す処理を追加しています。
もしくはパスの最後にパラメータを追加すると、変換して返してくれるような機能があればこんな感じで。
これはcontentfulです。

~/plugins/vue-lazyload.ts
  filter: {
    webp(listener: any, options: any) {
      if (!options.supportWebp) return
      listener.src += '?fm=webp'
    }
  }

以上で、画像はlazyloadとwebpが実装できました。

ここまでやったら、多分だいたいOKなんじゃないかと思いますが、次へ。

componentsのdynamic import

Nuxt,vueでcomponentをimportする場合

import fuga from '~/components/fuga.vue'

だいたい、こうしますが。

const fuga = () => import('~/components/fuga.vue')

こうすると、dynamic importになってbundleサイズが軽くなって速度が改善されます。
これをしてエラーが出ないcomponentならこうやったほうがいいですが、
たまにエラーが出るので、その場合は臨機応変に、従来通りのimportするかエラーを直すか。

webpackのbundleの設定

nuxt でwebpackのbundleを分割するように設定します。

nuxt.config.ts
const nuxtConfig = {
  splitChunks: {
    layouts: true,
    pages: true,
    commons: {
      test: /[\\/]node_modules[\\/]/,
      name: 'vendor',
      chunks: 'initial'
    }
  }

spliChunksの部分の設定をしてやると、よかったです。
おわり。

おわり 

おわり

参考

https://webpack.js.org/guides/lazy-loading/
https://crieit.net/posts/Nuxt-Vue-dynamic-import-sed

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

vue.js初心者がaxiosを利用しAPIを叩きデータを表示させるまで

はじめに

Vue.js は学習コストが低いと言われていますが初学者の方からしたら、
理解するのになかなか時間がかかってしまうと思います。
私も深く理解できているわけではありませんが、
これから紹介する書き方のみで
フロントのコーディングやアプリケーションを作る速さが格段にアップしたので、
この記事でVue.jsのコツを掴んでいただけたら幸いです。

Vue CLIのダウンロード

$ npm install -g @vue/cli

プロジェクトを作る

まずは以下のコマンドで vue のファイルを作ります。

$ vue create new-project

※この場合 new-project というディレクトリが作成されます。
スクリーンショット 2020-02-05 11.48.57.png
ファイルの内容をデフォルトで作るか自分でカスタマイズするか聞かれます。
今回は Router、 Vuex という機能を使うので
Manually select featuresを選択します。
スクリーンショット 2020-02-05 11.50.45.png
spaceキー Router Vuex を選択しEnterキー を押します。
以後も質問形式で設定を聞かれますが特にこだわりがなければ全て Enterキー で構いません。

$ cd new-project
$ npm run serve

http://localhost:8080/ このようなurlが出てきたら、
ブラウザからアクセスし以下のような画面が出れば準備完了です。
スクリーンショット 2020-02-05 17.09.31.png

Hello Worldを赤色で表示

早速Vueをいじっていきます。

Vue は単一ファイルコンポーネントでコードを記述するのが基本です。
以下のような形式を単一ファイルコンポーネントと言います。

<template></template>
<script></script>
<style></style>

見てわかるように
<template>には HTML
<script>には JavaScript
<style>には css
を記述していきます。

Home.vueの <template> <script> <style> の中身を全て削除し以下のコードを書きます。
templatehomeクラスタグのみ残しておいてください。
・スタイルタグは追加してください。

<template>
  <div class="home">
    <h1>Hello World</h1>
  </div>
</template>

<script></script>

<style scoped>
  .home{
    color: red;
  }
</style>

マスタッシュ記法

ここからスクリプトタグを使っていきます。
データバインディングという操作を行います。
以下のようなコードを書きます

<template>
  <div class="home">
    <h1>{{hoge}}</h1>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        hoge: "ハローワールド"
      }
    }
  }
</script>

h1タグの中身がハローワールドに変わったのが確認できたと思います。

マスタッシュ リスト表示方法

<template>
  <div class="home">
    <p>{{Vegetable.name}}</p>
    <p>{{Vegetable.price}}</p>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        Vegetable: {
          name: "にんじん",
          price: 3000000
        }
      }
    }
  }
</script>

Vegetable リストの中の namepriceというように取り出します。

v-bind スタイル付与

h1タグを青色にします。

<template>
  <div class="home">
    <h1 v-bind:style="vStyle">{{hoge}}</h1>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        hoge: "ハローワールド",
        vStyle: {
          color: "blue"
        }
      }
    }
  }
</script>

filter 小数点をつける

高級なにんじんの値段に小数点をつけます。

<template>
  <div class="home">
    <p>{{Vegetables.price | filter}}</p>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        Vegetables: {
          price: 3000000
        }
      }
    },
    filters: {
      filter(val) {
        return val.toLocaleString();
      }
    }
  }
</script>

数字以外に、文字にも適用できるfilterがあります。

v-if else 表示 非表示の切り替え

<template>
  <div class="home">
    <p v-if="false">on</p>
    <p v-else>off</p>
  </div>
</template>

v-if の条件が
・true であれば on
・false であれば off
が表示されます

v-model inputタグと同期

input に入力した内容を pタグに表示させます。

<template>
  <div class="home">
    <input v-model="text" type="text">
    <p>{{text}}</p>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        text: "",
      }
    }
  }
</script>

inputに入力されたデータを入れるために空のデータを用意してあげます。
textデータから値、テキストを取得して描画されます。

v-on clickイベント

<template>
  <div class="home">
    <div @click="push()">click me!!</div>
  </div>
</template>

<script>
  export default{
    methods:{
      push(){
        console.log("click year!!!!")
      }
    }
  }
</script>

検証画面のコンソールから確認してください。
click イベント以外にもイベントはあります。

v-for 配列でタグの複製

<template>
  <div class="home">
      <div v-for="data in Vegetables" :key="data.key">
      <p>{{data.name}}</p>
      <p>{{data.price}}</p>
    </div>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        Vegetables:[
          {name: "じゃがいも", price: 300, key: "imo"},
          {name: "イチゴ", price: 400, key: "strawberry"},
          {name: "カボチャ", price: 500, key: "pumpkin"},
        ]
      }
    }
  }
</script>

Vegetables配列の中のデータと同じ数タグを複製しそれぞれ該当するマスタッシュ記法で書かれたタグにデータ(name、price、key)が格納されます。

イメージ図

Vegetables配列/
 ├ data/
 │ ├ name/ じゃがいも
 │ ├ price/ 300
 │ └ key/ imo
 ├ data/
 │ ├ name/ イチゴ
 │ ├ price/ 400
 │ └ key/ strawberry
 └ data/
   ├ name/ カボチャ
   ├ price/ 500
   └ key/ pumpkin

component の使い方 一例

components ディレクトリの中の HelloWorld.vue のそれぞれ
<template> <script> <style>
の中身を消して以下のコードを記述します。
※helloクラスタグのみ残してください。

HelloWorld.vue

<template>
  <div class="hello">
    <h2>僕は子コンポーネント</h2>
  </div>
</template>

<script>
</script>

<style scoped>
  h2{
    font-size: 50px;
  }
</style>

Home.vue

<template>
  <div class="home">
    <HelloWorld></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from "../components/HelloWorld"

  export default{
    components: {
      HelloWorld
    }
  }
</script>

importcomponents の中の HelloWorld.vue を呼び出します。
※HelloWorld.vue を呼び出す際拡張子の .vue をつける必要はありません。
・components プロパティに登録します。
・登録したものは template タグ内で使用できるようになるのでコードを記述します。

components ディレクトリにファイルを作り上記の方法をたどると同じようにコンポーネントを作ることができます。

props 親から子コンポーネントにデータを渡す

この記事では、Home.vue の中にある HelloWorld.vue が子コンポーネントにあたります。

Home.vue

<template>
  <div class="home">
    <HelloWorld v-bind:parentText="sendChild"></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from "../components/HelloWorld"

  export default{
    data(){
      return{
        sendChild: "親のコンポーネントからテキストを受けっとたよ!"
      }
    }
    components: {
      HelloWorld
    }
  }
</script>

・子に渡すデータに名前をつけて(parenText)親のデータ(sendChild)をバインディングします。

HelloWorld.vue

<template>
  <div class="hello">
    <p>{{parentText}}</p>
  </div>
</template>

<script>
export default {
  props: ['parentText'],
}
</script>

props プロパティで値を受け取った物は data として扱うことができるのでマスタッシュ記法で表示します。

Router Link(Vue Router) ページ遷移

views ディレクトリの中に RouterLink.vue ファイルを作成します。
以下のように記述します。

<template>
  <div class="router">
    <p>Router Link の使用ができました!!</p>
  </div>
</template>

Router Link を使用するために router ディレクトリの中の index.js に
RouterLink.vue を登録します。
以下のようなコードを記述します。

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import RouterLink from '../views/RouterLink.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/routerlink',
    name: 'routerlink',
    component: RouterLink
  },
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

最後にリンクを使いたいファイルに以下のようなコードを記述していきます。
ここでは Home.vue に記述します。

<template>
  <div class="home">
    <router-link to="/routerlink">router-link</router-link>
  </div>
</template>

to でページのリンク先を指定します
router-link をクリックすることでページ遷移をすることができます。
webページのリンクの方を見てもらうと http://localhost:8080/routerlink
このようにリンクの末尾が変わっていることが確認できると思います。

ぐるなびAPI お店のデータを取得から表示

axios を用いてレストラン検索APIを叩き Vuex の store という機能を使って表示まで行います。
まずは axios のインストールから行います。
以下のコマンドを順に実行していってください。

$ npm install --save axios
$ npm install --save

次に、ぐるなびAPIを使用するためにこちらのサイトで会員登録をします。
登録することができたら以下のような画面に行き、
仕様書ページ、レストラン検索APIを参考にパラメータと値を入れていきます。
・左側にパラメータ(例 keyid)
・右側に値

スクリーンショット 2020-02-05 23.53.37.png

この記事では、
・表示件数
・wifiの有無
を条件に絞ります。

スクリーンショット 2020-02-06 1.03.59.png

入力ができたらクエリを送信ボタンを押し URL を、コピーします。
store ディレクトリの中の index.js ファイルに、以下のようなコードを入力し
コピーした URL をここに挿入とういう部分にペーストしてください。

store / index.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    dataSet: []
  },
  mutations: {
    mutateDataSet(state, payload) {
      state.dataset = payload
    }
  },
  actions: {
    commitDataSet(store) {
      return axios.get("ここに挿入")
        .then(response => {
          store.commit('mutateDataSet', response.data.rest)
        })
        .catch((reason) => {
          console.log(reason.message)
        })
    }
  }
})

importでaxiosを使えるようにします。
表示させたいページ(RouterLink.vue)に以下のコードを記述します。

RouterLink.vue

<template>
  <div class="about">
    <ul v-for="(value, index) in shopName" :key="index">
      <li>{{value}}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      shopName: ""
    };
  },
  created() {
    this.$store.dispatch('commitDataSet')
  },
  mounted() {
    var list = [];
    this.$store.state.dataSet.forEach(function(value) {
      list.push(value.name);
    });
    this.shopName = list;
  }
};
</script>

・created 内で store にアクセスして dispatch メソッドで action 内の関数を実行します。
・store の action メソッドが実行され値が取得されます。
・commit で mutations にアクセスし、データを入れます。
・mutations から state にアクセスし dataSetにデータが入ります。
・mounted で state 内のデータにアクセスし、forEach メソッドでデータが一個ずつ配列として list に入ります。
・list を shopName に代入することで RouterLink.vue 内で data として扱うことができるようになります。
・配列 shopName を v-for で表示させれば実装完了です。

いろいろ条件を変えて遊んでみてください。

イメージ

RouterLink.vue      store / index.js
 └ created ーー> action(commitDataSet)実行
                ↓
               mutation
                ↓
   mounted     <ーー state
     ↓
   描画

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.js初心者がaxiosを利用しAPIを叩きデータを表示させるまで

はじめに

Vue.js は学習コストが低いと言われていますが初学者の方からしたら、
理解するのになかなか時間がかかってしまうと思います。
私も深く理解できているわけではありませんが、
これから紹介する書き方のみで
フロントのコーディングやアプリケーションを作る速さが格段にアップしたので、
この記事でVue.jsのコツを掴んでいただけたら幸いです。

Vue CLIのダウンロード

$ npm install -g @vue/cli

プロジェクトを作る

まずは以下のコマンドで vue のファイルを作ります。

$ vue create new-project

※この場合 new-project というディレクトリが作成されます。
スクリーンショット 2020-02-05 11.48.57.png
ファイルの内容をデフォルトで作るか自分でカスタマイズするか聞かれます。
今回は Router、 Vuex という機能を使うので
Manually select featuresを選択します。
スクリーンショット 2020-02-05 11.50.45.png
spaceキー Router Vuex を選択しEnterキー を押します。
以後も質問形式で設定を聞かれますが特にこだわりがなければ全て Enterキー で構いません。

$ cd new-project
$ npm run serve

http://localhost:8080/ このようなurlが出てきたら、
ブラウザからアクセスし以下のような画面が出れば準備完了です。
スクリーンショット 2020-02-05 17.09.31.png

Hello Worldを赤色で表示

早速Vueをいじっていきます。

Vue は単一ファイルコンポーネントでコードを記述するのが基本です。
以下のような形式を単一ファイルコンポーネントと言います。

<template></template>
<script></script>
<style></style>

見てわかるように
<template>には HTML
<script>には JavaScript
<style>には css
を記述していきます。

Home.vueの <template> <script> <style> の中身を全て削除し以下のコードを書きます。
templatehomeクラスタグのみ残しておいてください。
・スタイルタグは追加してください。

<template>
  <div class="home">
    <h1>Hello World</h1>
  </div>
</template>

<script></script>

<style scoped>
  .home{
    color: red;
  }
</style>

マスタッシュ記法

ここからスクリプトタグを使っていきます。
データバインディングという操作を行います。
以下のようなコードを書きます

<template>
  <div class="home">
    <h1>{{hoge}}</h1>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        hoge: "ハローワールド"
      }
    }
  }
</script>

h1タグの中身がハローワールドに変わったのが確認できたと思います。

マスタッシュ リスト表示方法

<template>
  <div class="home">
    <p>{{Vegetable.name}}</p>
    <p>{{Vegetable.price}}</p>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        Vegetable: {
          name: "にんじん",
          price: 3000000
        }
      }
    }
  }
</script>

Vegetable リストの中の namepriceというように取り出します。

v-bind スタイル付与

h1タグを青色にします。

<template>
  <div class="home">
    <h1 v-bind:style="vStyle">{{hoge}}</h1>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        hoge: "ハローワールド",
        vStyle: {
          color: "blue"
        }
      }
    }
  }
</script>

filter 小数点をつける

高級なにんじんの値段に小数点をつけます。

<template>
  <div class="home">
    <p>{{Vegetables.price | filter}}</p>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        Vegetables: {
          price: 3000000
        }
      }
    },
    filters: {
      filter(val) {
        return val.toLocaleString();
      }
    }
  }
</script>

数字以外に、文字にも適用できるfilterがあります。

v-if else 表示 非表示の切り替え

<template>
  <div class="home">
    <p v-if="false">on</p>
    <p v-else>off</p>
  </div>
</template>

v-if の条件が
・true であれば on
・false であれば off
が表示されます

v-model inputタグと同期

input に入力した内容を pタグに表示させます。

<template>
  <div class="home">
    <input v-model="text" type="text">
    <p>{{text}}</p>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        text: "",
      }
    }
  }
</script>

inputに入力されたデータを入れるために空のデータを用意してあげます。
textデータから値、テキストを取得して描画されます。

v-on clickイベント

<template>
  <div class="home">
    <div @click="push()">click me!!</div>
  </div>
</template>

<script>
  export default{
    methods:{
      push(){
        console.log("click year!!!!")
      }
    }
  }
</script>

検証画面のコンソールから確認してください。
click イベント以外にもイベントはあります。

v-for 配列でタグの複製

<template>
  <div class="home">
      <div v-for="data in Vegetables" :key="data.key">
      <p>{{data.name}}</p>
      <p>{{data.price}}</p>
    </div>
  </div>
</template>

<script>
  export default{
    data(){
      return{
        Vegetables:[
          {name: "じゃがいも", price: 300, key: "imo"},
          {name: "イチゴ", price: 400, key: "strawberry"},
          {name: "カボチャ", price: 500, key: "pumpkin"},
        ]
      }
    }
  }
</script>

Vegetables配列の中のデータと同じ数タグを複製しそれぞれ該当するマスタッシュ記法で書かれたタグにデータ(name、price、key)が格納されます。

イメージ図

Vegetables配列/
 ├ data/
 │ ├ name/ じゃがいも
 │ ├ price/ 300
 │ └ key/ imo
 ├ data/
 │ ├ name/ イチゴ
 │ ├ price/ 400
 │ └ key/ strawberry
 └ data/
   ├ name/ カボチャ
   ├ price/ 500
   └ key/ pumpkin

component の使い方 一例

components ディレクトリの中の HelloWorld.vue のそれぞれ
<template> <script> <style>
の中身を消して以下のコードを記述します。
※helloクラスタグのみ残してください。

HelloWorld.vue

<template>
  <div class="hello">
    <h2>僕は子コンポーネント</h2>
  </div>
</template>

<script>
</script>

<style scoped>
  h2{
    font-size: 50px;
  }
</style>

Home.vue

<template>
  <div class="home">
    <HelloWorld></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from "../components/HelloWorld"

  export default{
    components: {
      HelloWorld
    }
  }
</script>

importcomponents の中の HelloWorld.vue を呼び出します。
※HelloWorld.vue を呼び出す際拡張子の .vue をつける必要はありません。
・components プロパティに登録します。
・登録したものは template タグ内で使用できるようになるのでコードを記述します。

components ディレクトリにファイルを作り上記の方法をたどると同じようにコンポーネントを作ることができます。

props 親から子コンポーネントにデータを渡す

この記事では、Home.vue の中にある HelloWorld.vue が子コンポーネントにあたります。

Home.vue

<template>
  <div class="home">
    <HelloWorld v-bind:parentText="sendChild"></HelloWorld>
  </div>
</template>

<script>
import HelloWorld from "../components/HelloWorld"

  export default{
    data(){
      return{
        sendChild: "親のコンポーネントからテキストを受けっとたよ!"
      }
    },
    components: {
      HelloWorld
    }
  }
</script>

・子に渡すデータに名前をつけて(parenText)親のデータ(sendChild)をバインディングします。

HelloWorld.vue

<template>
  <div class="hello">
    <p>{{parentText}}</p>
  </div>
</template>

<script>
export default {
  props: ['parentText'],
}
</script>

props プロパティで値を受け取った物は data として扱うことができるのでマスタッシュ記法で表示します。

Router Link(Vue Router) ページ遷移

views ディレクトリの中に RouterLink.vue ファイルを作成します。
以下のように記述します。

<template>
  <div class="router">
    <p>Router Link の使用ができました!!</p>
  </div>
</template>

Router Link を使用するために router ディレクトリの中の index.js に
RouterLink.vue を登録します。
以下のようなコードを記述します。

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import RouterLink from '../views/RouterLink.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/routerlink',
    name: 'routerlink',
    component: RouterLink
  },
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

最後にリンクを使いたいファイルに以下のようなコードを記述していきます。
ここでは Home.vue に記述します。

<template>
  <div class="home">
    <router-link to="/routerlink">router-link</router-link>
  </div>
</template>

to でページのリンク先を指定します
router-link をクリックすることでページ遷移をすることができます。
webページのリンクの方を見てもらうと http://localhost:8080/routerlink
このようにリンクの末尾が変わっていることが確認できると思います。

ぐるなびAPI お店のデータを取得から表示

axios を用いてレストラン検索APIを叩き Vuex の store という機能を使って表示まで行います。
まずは axios のインストールから行います。
以下のコマンドを順に実行していってください。

$ npm install --save axios
$ npm install --save

次に、ぐるなびAPIを使用するためにこちらのサイトで会員登録をします。
登録することができたら以下のような画面に行き、
仕様書ページ、レストラン検索APIを参考にパラメータと値を入れていきます。
・左側にパラメータ(例 keyid)
・右側に値

スクリーンショット 2020-02-05 23.53.37.png

この記事では、
・表示件数
・wifiの有無
を条件に絞ります。

スクリーンショット 2020-02-06 1.03.59.png

入力ができたらクエリを送信ボタンを押し URL を、コピーします。
store ディレクトリの中の index.js ファイルに、以下のようなコードを入力し
コピーした URL をここに挿入とういう部分にペーストしてください。

store / index.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    dataSet: []
  },
  mutations: {
    mutateDataSet(state, payload) {
      state.dataSet = payload
    }
  },
  actions: {
    commitDataSet(store) {
      return axios.get("ここに挿入")
        .then(response => {
          store.commit('mutateDataSet', response.data.rest)
        })
        .catch((reason) => {
          console.log(reason.message)
        })
    }
  }
}) 

importでaxiosを使えるようにします。
表示させたいページ(RouterLink.vue)に以下のコードを記述します。

RouterLink.vue

<template>
  <div class="about">
    <ul v-for="(value, index) in shopName" :key="index">
      <li>{{value}}</li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      shopName: ""
    };
  },
  created() {
    this.$store.dispatch('commitDataSet')
  },
  mounted() {
    var list = [];
    this.$store.state.dataSet.forEach(function(value) {
      list.push(value.name);
    });
    this.shopName = list;
  }
};
</script>

・created 内で store にアクセスして dispatch メソッドで action 内の関数を実行します。
・store の action メソッドが実行され値が取得されます。
・commit で mutations にアクセスし、データを入れます。
・mutations から state にアクセスし dataSetにデータが入ります。
・mounted で state 内のデータにアクセスし、forEach メソッドでデータが一個ずつ配列として list に入ります。
・list を shopName に代入することで RouterLink.vue 内で data として扱うことができるようになります。
・配列 shopName を v-for で表示させれば実装完了です。

いろいろ条件を変えて遊んでみてください。

イメージ

RouterLink.vue      store / index.js
 └ created ーー> action(commitDataSet)実行
                ↓
               mutation
                ↓
   mounted     <ーー state
     ↓
   描画

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む