20200926のvue.jsに関する記事は10件です。

【Vue】コンポーネント間のデータ(とメソッド)の受け渡し

はじめに

Vueの基礎的な部分、コンポーネント間のデータの受け渡しの備忘録。
ついでに、親コンポーネントのメソッドを子コンポーネントで利用する方法も載せた。

なお、デザインテンプレートにvuetifyを使っている。

環境

  • vue: 2.6.10
  • vuetify: 2.1.0

サンプルコード

親コンポーネント

parentComponent.vue
<template>
  <v-card>
    <child-component
      :users
      :teamId
      @showList="showUserList"
    />
  </v-card>
</template>

<script>
import childComponent from "@/components/molcules/childComponent"

export default {
  components: {
    "child-component": childComponent,
  },
  data() {
    return {
      users: [
        "Alice",
        "Bob",
      ],
      teamId: 3,
    }
  },
  methods: {
    showUserList(item) {
      console.log("showUserList: " + item)
    },
  },
}
</script>

子コンポーネント

childComponent.vue
<template>
  <v-card>
    {{ teamId }}
    <v-list
      v-for="(user, index) in users"
      :key="index"
    >
      {{ user }}
    </v-list>
    <v-btn
      @click="showList"
    >
    </v-btn>
  </v-card>
</template>

<script>
export default {
  props: {
    users: {
      type: Array,
      required: false,
      default: () => []
    },
    teamId: {
      type: Number,
      required: true,
      default: () => 0
    }
  },
  methods: {
    showList(item) {
      this.$emit("showUserList", item)
    },
  },
}
</script>

おわりに

取り急ぎコードのみ載せた。
後日、余力があれば解説のほうも追記する。

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

Vue3の環境にVuetifyがインストールできない

Vue3の環境にVuetifyがインストールできない

vue add vuetifyを実行した時、次のようなエラーがでて、インストールが完了しません。

 Error: You cannot call "get" on a collection with no paths. Instead, check the "length" property first to verify at least 1 path exists.
Error: You cannot call "get" on a collection with no paths. Instead, check the "length" property first to verify at least 1 path exists.
    at Collection.get (/home/masa/.n/lib/node_modules/@vue/cli/node_modules/jscodeshift/src/Collection.js:213:13)
    at injectOptions (/home/masa/.n/lib/node_modules/@vue/cli/lib/util/codemods/injectOptions.js:15:6)
    at runTransformation (/home/masa/.n/lib/node_modules/@vue/cli/node_modules/vue-codemod/dist/src/run-transformation.js:61:17)
    at /home/masa/.n/lib/node_modules/@vue/cli/lib/Generator.js:290:23
    at Array.forEach (<anonymous>)
    at Generator.resolveFiles (/home/masa/.n/lib/node_modules/@vue/cli/lib/Generator.js:276:24)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async Generator.generate (/home/masa/.n/lib/node_modules/@vue/cli/lib/Generator.js:175:5)
    at async runGenerator (/home/masa/.n/lib/node_modules/@vue/cli/lib/invoke.js:111:3)
    at async invoke (/home/masa/.n/lib/node_modules/@vue/cli/lib/invoke.js:92:3)

解決策

vuetify3がリリースされるまで待つ

https://github.com/vuetifyjs/vuetify/issues/11162#issuecomment-616353160

以下の試したことを実行すると上のエラーは解消するが別のエラーがでて動きません。

試したこと

main.jsに次のコードを書いてから、vue add vuetifyを実行する。

new Vue({
    render: h => h(App),
}).$mount('#app');
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt v2でStorybook 6.0.xを導入する

以前にこちらの記事でインストールからscssの利用設定、CSF記法を備忘録的にまとめました。
久しぶりにStorybookを新規立ち上げてみたところ、設定ファイル周りの仕様が変わっておりましたので、改めてインストールから基本設定の部分までをメモしておきます。
TypeScriptの利用設定等も同様に行えるはずです(未確認)。

0. Nuxtプロジェクトの作成

Nuxtプロジェクトはsrc以下に移動し、scssの設定も完了しているものとする。
作成するファイルの通り、Storybookでのscssとエイリアスの稼働確認を行います。

0.1. /src/assets/以下の構成とファイル内容

assets
├── img
│   └── hoge.png
│   └── hoge_bg.png
│   └── hoge_bg2.png
└── scss
    ├── _mixins.scss // なくてもOK
    ├── _variables.scss
    ├── global.scss
    └── reset.scss // なくてもOK
_variables.scss
// 変数稼働チェック
$font-color-green: Green;
global.scss
/* `layouts/default.vue`のスタイル設定を一部移動し、改変 */

@import './reset';
@import './_variables';
@import './_mixins';

html {
  font-family: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI',
    Roboto, 'Helvetica Neue', Arial, sans-serif;
  font-size: 16px;
  word-spacing: 1px;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
  // エイリアス稼働チェック
  background: url(~assets/img/hoge_bg.png);
}

a {
  // 変数稼働チェック
  color: $font-color-green;
}

0.2. src/components/StorybookTest.vueを作成。

Storyで表示する確認用のコンポーネント。
あくまでscssとエイリアス設定が効くかの確認なので要素を並べただけですのであしからず。

StorybookTest.vue
<template>
  <div class="outer">
    <div class="inner">
      <a href="#">Storybook Test</a>
      <!-- エイリアスの確認 -->
      <img src="~/assets/img/hoge.png" alt="" />
    </div>
  </div>
</template>

// scssの確認
<style lang="scss" scoped>
.outer {
  width: 110px;
  height: 200px;
  margin: auto;
  .inner {
    text-align: center;
    /* エイリアスの確認 */
    background: url('~assets/img/hoge_bg.png');
  }
}
</style>

1. Storybookインストール

ここは以前と変わりません。CLIでのインストール時にsbをつけておくと、フレームワーク等を自動で判別して必要なモジュールを追加してくれます。

npx -p @storybook/cli sb init

インストールが完了すると、.storybookstoriesというディレクトリが生成されます。
storiesディレクトリは以前から変わらず、storyファイルを格納します。
一方、.storybookディレクトリ内に生成されるファイルが以下のように変更されておりました。

.storybook
├── main.js
└── preview.js

2. 設定ファイルの変更

以前は、Nuxtプロジェクトで使用しているscssファイルをStorybookでも利用するための設定やエイリアスの設定を、.storybook/webpackconfig.jsというファイル内で定義しておりましたが、これらがインストール時に生成された.storybook/main.jsに記述を移します。

2.1 scssの読み込み設定

storybook/main.js
- const { resolve } = require('path')
+ const path = require('path')
  const rootPath = path.resolve(__dirname, '../src/')

  module.exports = {
    "stories": [
      "../**/*.stories.mdx",
      "../**/*.stories.@(js|jsx|ts|tsx)"
    ],
    "addons": [
      "@storybook/addon-links",
      "@storybook/addon-essentials"
    ],

+    webpackFinal: async(config, {configType}) => {
+      config.module.rules.push({
+        test: /\.scss$/,
+        use: [
+          'style-loader',
+          'css-loader',
+          'sass-loader'
+        ],
+        include: rootPath,
+      })
+
+      config.resolve.modules = [
+        ...(config.resolve.modules || []),
+        rootPath
+      ];
+
+      return config
+    }
  }

2.2 Nuxtプロジェクトで使用しているscssをStorybookでも使用する

reset.scssやglobal.scssなど、Nuxtプロジェクトで使用しているassets以下にある共通のscssをStorybookにも適用する。
これは.storybook/preview.jsに必要なscssをimportしてあげるだけで良い。

storybook/preview.js
// 他のscssファイルもimportしているので、ここではglobal.scssの記述のみ
+ import '../src/assets/scss/global.scss'

// 以下はStorybookインストール時に自動で定義されている
export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
}

3. 確認

Storyファイルの作成

stories/StorybookTest.stories.js
import StorybookTest from '../src/components/StorybookTest.vue'

/* コンポーネントの設定 */
export default {
  title: 'Storybook稼働確認', // ナビゲーションパネルでの表示名となる
  component: StorybookTest, // 対象となるコンポーネントを定義する
}

/* story記述 */
// default
export const STTest = () => ({
  // 変数名がナビゲーションパネルでの表示名となる
  components: { StorybookTest }, // 対象となるコンポーネントを指定する
  template: '<storybook-test />', // レンダリングするhtmlを記述する
})

以上までの設定でscssとエイリアスの設定は完了。最後にStorybookを起動して確認してみる。

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

Vue CLI 3 よく使うであろうコマンド コピペ用

「こんなコマンドも使用頻度高め!」と言うのがあれば、コメントください:relieved:

テストする時

npm run serve

プラグイン追加

vue add vue-router

vue add vuetify

プロジェクトを作る時

vue create my-project

環境に関するデバッグ情報を出力

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

Vue CLI よく使うであろうコマンド コピペ用

「こんなコマンドも使用頻度高め!」と言うのがあれば、コメントください:relieved:

テストする時

npm run serve

プラグイン追加

vue add vue-router

vue add vuetify

プロジェクトを作る時

vue create my-project

環境に関するデバッグ情報を出力

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

Vue v3.0.0記念Code nameまとめ

Vue v3.0.0 One Pieceが2020/09/18にリリースされました。
https://github.com/vuejs/vue-next

記念に過去からのCode nameをまとめてみました。

Version Code name 作品名
v3.0.0 One Piece ONE PIECE
v2.6.0 Macross 超時空要塞マクロス
v2.5.0 Level E レベルE
v2.4.0 Kill la Kill キルラキル
v2.3.0 JoJo's Bizarre Adventure ジョジョの奇妙な冒険
v2.2.0 Initial D 頭文字D
v2.1.0 Hunter X Hunter HUNTER×HUNTER
v2.0.0 Ghost in the Shell 攻殻機動隊
v1.0.0 Evangelion 新世紀エヴァンゲリオン
v0.12.0 Dragon Ball ドラゴンボール
v0.11.0 Cowboy Bebop カウボーイビバップ
v0.10.0 Blade Runner ブレードランナー
v0.9.0 Animatrix アニマトリックス

命名は見ればわかるようにアニメ好きですね
「F,N」を除いてアルファベット順になっています。
急ににわか認定されそうなものが出てきましたが、基本的に有名どころなので次はどんな作品がくるでしょうか

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

Vue v3.0.0リリース記念Code name振り返り

Vue v3.0.0 One Pieceが2020/09/18にリリースされました。
https://github.com/vuejs/vue-next

記念に過去からのCode nameをまとめてみました。

Version Code name 作品名
v3.0.0 One Piece ONE PIECE
v2.6.0 Macross 超時空要塞マクロス
v2.5.0 Level E レベルE
v2.4.0 Kill la Kill キルラキル
v2.3.0 JoJo's Bizarre Adventure ジョジョの奇妙な冒険
v2.2.0 Initial D 頭文字D
v2.1.0 Hunter X Hunter HUNTER×HUNTER
v2.0.0 Ghost in the Shell 攻殻機動隊
v1.0.0 Evangelion 新世紀エヴァンゲリオン
v0.12.0 Dragon Ball ドラゴンボール
v0.11.0 Cowboy Bebop カウボーイビバップ
v0.10.0 Blade Runner ブレードランナー
v0.9.0 Animatrix アニマトリックス

命名は見ればわかるようにアニメ好きですね
「F,N」を除いてアルファベット順になっています。
急ににわか認定されそうなものが出てきましたが、基本的に有名どころなので次はどんな作品がくるでしょうか

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

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #3 個別記事ページの作成

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #2 NuxtとRailsとの疎通テスト

個別記事ページの作成

$ mkdir pages/posts
$ touch pages/posts/_id.vue
pages/posts/_id.vue
<template>
  <v-layout
    column
    justify-center
    align-center
  >
    <v-flex
      xs12
      sm8
      md6
    >
      <v-card>
        <v-card-title class="headline">
          {{ post.subject }} - {{ post.user.name }}
        </v-card-title>
        <v-card-text>
          {{ post.body }}
        </v-card-text>
      </v-card>
    </v-flex>
  </v-layout>
</template>

<script>
export default {
  validate ({ params }) {
    return /^\d+$/.test(params.id)
  },
  async asyncData ({ $axios, params }) {
    const response = await $axios.$get(`/v1/posts/${params.id}`)
    return {
      post: response.post
    }
  }
}
</script>

Nuxtでは上記のようにpages/hoge/_id.vueとすることで、hoge/{id}のような動的ページが作られます。

バリデートは数値型のみ許容するように設定しています。以下、公式ドキュメント参照。
ルーティング - NuxtJS

そしてasyncDataというSSR用のメソッドでv1/posts/${params.id}とすることで、URLのid部分の数値から固定のpostを取得しているわけです。

なお、今回はpostの値をVuexのstoreに保存していません。
storeはなんでもかんでも保存を保存しておく場所ではなく、他のmoduleやサイト全体で使う必要があるか考え、そうでなければ不用意に突っ込まないほうがいいです。

もしブラウザで以下の通り表示されたら、とりあえずOKです。

show.png

indexから個別ページにリンクを設置

indexから個別ページにリンクを貼ります。

pages/index.vue
       <v-card v-for="post in posts" :key="post.id">
         <v-card-title class="headline">
-          {{ post.subject }} - {{ post.user.name }}
+          <n-link :to="`/posts/${post.id}`">
+            {{ post.subject }} - {{ post.user.name }}
+          </n-link>
         </v-card-title>
         <v-card-text>

list.png

リンクになっていますね。

CORS対策

ではindexから個別ページに飛んでみましょう。

error.png

エラーになりましたか?
実はこれがエラーメッセージ読んでも原因が特定しづらく結構厄介なものです。
以前この問題の対応策を書き残していますので、詳細を知りたい方は以下の記事を。
Nuxt.jsでURL直叩きの時はページが表示されるのに、nuxt-linkやブラウザバックでAn error occurredになる

さて上記記事にも書きましたが、原因はページ遷移した場合はSSR(サーバサイドレンダリング)ではなくCSR(クライアントサイドレンダリング)になるため、CORS(オリジン間リソース共有)の対策が必要です。

nuxt.config.js
   ** Nuxt.js modules
   */
   modules: [
-    '@nuxtjs/axios'
+    '@nuxtjs/axios',
+    '@nuxtjs/proxy'
   ],
-  axios: {},
+  axios: {
+    proxy: true
+  },
+  proxy: {
+    '/v1/': {
+      target: 'https:/xxxxxxxxxxx.ap-northeast-1.amazonaws.com:8080/'
+    }
+  },

targetはご自身のRails APIエンドポイントに置き換えてください。

この設定が済めば、indexも個別ページも、ブラウザバックやn-link(nuxt-link)による遷移時も正常に表示されるはずです。

続き

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #4 サインアップページの作成
連載目次へ

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

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #2 NuxtとRailsとの疎通テスト

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #1 環境構築

axiosの導入

URLのリクエストを送る際はaxiosを使います。
create_nuxt_appの時にaxiosを入れているはずですが、もし入れるのをミスっていた場合は以下の手順で追加します。

$ yarn add @nuxtjs/axios
nuxt.config.js
export default {
   ** Nuxt.js modules
   */
   modules: [
+    '@nuxtjs/axios'
   ],

APIとの疎通テスト

pages/index.vue
           Welcome to the Vuetify + Nuxt.js template
         </v-card-title>
         <v-card-text>
+        <ul>
+          <li v-for="post in posts" :key="post.id">
+            {{ post.subject }}
+            {{ post.body }}
+          </li>
+        </ul>
...
   components: {
     Logo,
     VuetifyLogo
+  },
+  async asyncData({ $axios }) {
+    const response = await $axios.$get('/v1/posts');
+    return {
+      posts: response.posts
+    };
   }
 }
 </script>

雑ではありますが、Railsのseedで作ったデータが無事に取得できましたね。

sample.png

とりあえずこれでフロントエンドとバックエンドの連携確認は取れました。

Vuexで書き換える

特にルール無く記述していくことも可能なのですが、Vuexを利用して書いていきます。

Vuex は Vue.js アプリケーションのための 状態管理パターン + ライブラリです。 これは予測可能な方法によってのみ状態の変異を行うというルールを保証し、アプリケーション内の全てのコンポーネントのための集中型のストアとして機能します。 また Vue 公式の開発ツール拡張と連携し、設定なしでタイムトラベルデバッグやステートのスナップショットのエクスポートやインポートのような高度な機能を提供します。

vuex.png

文章・画像引用:Vuex とは何か? | Vuex

文章を読んだり画像をパッと見ただけではなかなか理解しづらいかもしれません。
actionsやらmutationsやらdispatch, commit…なにこれ?と思うかもしれませんが、

  • storeにstatemutationsactionsの3つ(+gettersの4つ)を持ってそれぞれを呼び出すというパターン
  • stateは値を持つだけ
  • mutationsはstateの値をセットするだけ
  • actionsで処理して、stateを変更する時は直接stateを呼ばずmutationsを呼ぶ
  • gettersはstateの値を取得するだけ
  • mutationsを呼ぶことをcommitと言う
  • actionsを呼ぶことをdispatchと言う

となります。

とりあえず以下のようにファイルを編集します。

store/posts.js
export const state = () => ({
  posts: []
})

export const getters = {
  posts (state) {
    return state.posts
  }
}

export const mutations = {
  setPosts (state, data) {
    state.posts = data
  }
}

export const actions = {
  async fetchPosts () {
    return await this.$axios.$get('/v1/posts')
  }
}

pages/index.vue
<template>
  <v-layout
    column
    justify-center
    align-center
  >
    <v-flex
      xs12
      sm8
      md6
    >
      <v-card v-for="post in posts" :key="post.id">
        <v-card-title class="headline">
          {{ post.subject }} - {{ post.user.name }}
        </v-card-title>
        <v-card-text>
          {{ post.body }}
        </v-card-text>
      </v-card>
    </v-flex>
  </v-layout>
</template>

<script>
export default {
  async fetch ({ store }) {
    const posts = await store.dispatch('posts/fetchPosts')
    store.commit('posts/setPosts', posts.posts)
  },
  computed: {
    posts () {
      return this.$store.getters['posts/posts']
    }
  }
}
</script>

storeディレクトリ以下に置いたファイルは、{ファイル名}/{関数名}で名前空間が切られます。
どのように処理されているかの流れは、上記2ファイルに1〜8でコメント記載しています。

まずはconst posts = await store.dispatch('posts/fetchList') // 1によってposts/fetchListdispatch
前述の通りdispatchはactionsを呼び出すので、posts.jsactionsにあるfetchListが呼ばれるわけですね。

一度見方が分かれば、そこまで読み解くのは難しくないはずです。

Vuexはルールを破って書くことができてその場合エラーを投げたりしないのですが、結局そうなるとコードの保守性は下がります。ですので上記ルールに従って、storeの直接呼び出しや書き換えをせずに、actionsやmutationsで制御していきましょう。

続き

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #3 個別記事ページの作成
連載目次へ

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

Vueでv-forを使いfont awosomeを繰り返し表示させる方法

タイトル通りvueでfont awosomeのアイコンを繰り返し表示させようとしたら、一部困ったことになったので解決策を記しておきます。
vueでfont awosomeの導入するまではこの記事を参考にしました。

目的

よくプロフィールサイトで見かけるこんな感じのレイアウトを構築したいとします。
スクリーンショット 2020-09-26 0.51.23.png

結論

以下のように記述して表示させることができました。

<v-layout justify-space-around wrap class="mb-10">
  <v-flex
    v-for="language in languages"
    :key="language.id"
  >
  <font-awesome-icon
  :icon="{ prefix: language.prefix, iconName: language.iconName }"
  /><br />
  <span>{{ language.name }}</span>
  </v-flex>
</v-layout>
<script>
export default {
  data() {
    return {
      languages: [
        {
          id: 1,
          prefix: "fas",
          iconName: "code",
          name: "HTML5/CSS3/Sass",
        },
        {
          id: 2,
          prefix: "fab",
          iconName: "js-square",
          name: "JavaScript",
        },
        {
          id: 3,
          prefix: "far",
          iconName: "gem",
          name: "Ruby",
        },
      ],
    };
  },
};
</script>

注意点

何が問題だったかというと、vueでfont awosomeを表示させようとすると、prefixがデフォルトの状態でfarになっており、それ以外のfasやfabは指定しないと表示されないのです。(こちらの記事を参考にさせていただきました。)

したがって下のように記述してしまうと、デフォルトのfar以外は表示されなくなってしますのです。

<v-layout justify-space-around wrap class="mb-10">
  <v-flex
    v-for="language in languages"
    :key="language.id"
  >
  <font-awesome-icon
  :iconName="language.iconName" //prefixの指定をしていない
  /><br />
  <span>{{ language.name }}</span>
  </v-flex>
</v-layout>
<script>
//省略
         {
          id: 2,
          iconName: "js-square", //farではないので表示されない
          name: "JavaScript",
        },
        {
          id: 3,
          iconName: "gem", //farなので表示される
          name: "Ruby",
       },
      ],
    };
  },
};
</script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む