20200320のvue.jsに関する記事は11件です。

Vue.jsでApexchartsを使ってグラフ描画を行う

Vue.jsでのグラフ描画ライブラリの選定について

Apexcharts, vue-apexcharts を使って、Vue.jsで各種グラフの描画をおこなってみます。
当初、vue-chartjs を使っていたものの、柔軟性に欠ける、見た目があまり良くない、コードが複雑になりがち等の理由で乗り換えました。

描画結果

今回、折れ線グラフ円グラフ棒グラフ (横型) の描画を行ってみました。結果は以下。

linechart.png
piechart.png
barchart.png

良い点

  • 色々なカスタマイズ項目があり、細かい要求に対して融通が利きやすい
  • 今回のような単純な例の他、人口ピラミッドヒートマップ地図ローソク足等色々なグラフの描画が可能
  • マウスカーソルをグラフ上にあてると特定の結果をハイライト表示できる
  • 折れ線グラフはブラウザ上で横軸のズームイン、ズームアウトができる
  • 画像としてダウンロード可能
  • トランスパイルすればIE11にも対応

参考: 公式のデモ

インストール

npm install vue-apexcharts

折れ線グラフのコードサンプル

サンプルは色々カスタマイズオプションを設定しているため少し長めですが、大部分は省略可能です。

~略~
<!-- 少し色みがかったグラフにするため今回は type="area"にした。通常は type="line" -->
<apexchart
  type="area"
  height="400"
  :options="chart.options"
  :series="chart.series"
></apexchart>
~略~
<script>
import VueApexCharts from 'vue-apexcharts'
export default {
  components: {
    apexchart: VueApexCharts,
  },

  data: () => ({
    chart: {
      options: {
        chart: {
          zoom: {
            type: 'x', // X軸のズームを可能にする
            enabled: true,
            autoScaleYaxis: true,
          },
          toolbar: {
            autoSelected: 'zoom',
          },
        },
        plotOption: {
          line: {
            curve: 'smooth', // 滑らかなラインにする
          },
        },
        xaxis: {
          type: 'datetime', // category, datetime, numericのいずれか。時系列チャートならズームに強いdatetimeがおすすめ
          title: {
            text: '日付',
            offsetY: 10,
          },
          labels: {
            format: 'yy/MM/dd',
          },
          categories: [ // X軸の値
            new Date('2020/03/01 09:00:00'),
            new Date('2020/03/02 09:00:00'),
            new Date('2020/03/03 09:00:00'),
            new Date('2020/03/04 09:00:00'),
          ],
        },
        yaxis: {
          title: {
            text: '回答数',
          },
        },
        title: {
          text: '回答数推移',
          align: 'center',
        },
        tooltip: {
          x: {
            format: 'yy/MM/dd',
          },
        },
        fill: {
          type: 'gradient', // グラデーションをつける
          gradient: {
            type: 'vertical',
            shadeIntensity: 1,
            inverseColors: false,
            opacityFrom: 0.5,
            opacityTo: 0,
            stops: [0, 90, 100],
          },
        },
      },
      series: [
        {
          name: '回答数',
          data: [10, 3, 8, 2], // Y軸の値
        },
      ],
    },
  }),
}
</script>

時差が考慮されていないのか、9時間進んだ値を入れないとうまく日本時間に合った表示をしてくれませんでした。(私の調査不足かもしれません)

円グラフのコードサンプル

~略~
<apexchart
  type="pie"
  height="400"
  :options="chart.options"
  :series="chart.series"
></apexchart>
~略~
<script>
import VueApexCharts from 'vue-apexcharts'
export default {
  components: {
    apexchart: VueApexCharts,
  },

  data: () => ({
    chart: {
      options: {
        labels: ['20代', '30代', '40代', '50代'],
        title: {
          text: 'あなたの年齢を教えてください。',
          align: 'center',
        },
      },
      series: [5, 8, 3, 2],
    },
  }),
}
</script>

棒グラフのコードサンプル

~略~
<apexchart
  type="bar"
  height="400"
  :options="chart.options"
  :series="chart.series"
></apexchart>
~略~
<script>
import VueApexCharts from 'vue-apexcharts'
export default {
  components: {
    apexchart: VueApexCharts,
  },

  data: () => ({
    chart: {
      options: {
        plotOptions: {
          bar: {
            horizontal: true, // 横型のグラフにする場合
          },
        },
        title: {
          text: '使用ブラウザー',
          align: 'center',
        },
        xaxis: {
          categories: ['Internet Explorer', 'Google Chrome', 'Firefox', 'Safari'],
        },
      },
      series: [
        {
          name: '件数',
          data: [3, 5, 2, 9],
        },
      ],
    },
  }),
}
</script>

グラフのカスタマイズ

オプション項目の一覧はAPEXCHARTS - Optionsを参照。
ただし、オプションを見ただけではイマイチ具体的な設定方法が分からなかったり、
ところどころVue.jsに合わせて勘でアレンジする必要がありました。
VUE CHARTS DEMOSにいくつか実コードが載っているケースもあり、参考になりました。

参考: 棒グラフに件数とパーセンテージを両方表示する例

options: {
  // ~~略~~
  dataLabels: {
    enabled: true,
    formatter: (val, opt) => {
      return (
        val + '件 (' + Math.round((100 * val) / total) + '%)' // total変数に総件数が入っているものとします
      )
    },
  },
  tooltip: {
    y: {
      formatter: val => {
        return (
          val + '件 (' + Math.round((100 * val) / data.total) + '%)'
        )
      },
    },
  // ~~略~~
},

IE11に対応させる

  • promise-polyfill
  • classlist.js
  • findIndex - timeline/rangebarグラフを使う場合必要
  • canvg - PNGでのダウンロードに対応させる場合必要

が必要とのこと。BabelのPolyfillで概ねいけましたが、classlistは別途Polyfillが必要でした。

npm install classlist-polyfill

src/main.js

import 'classlist-polyfill'

Babelについては他の記事をご参照ください。

CSSの微調整

Apexchartsのツールバーのz-indexがイケておらず、私の環境ではCSSの調整が必要でした。(場合によると思われます)

.apexcharts-toolbar {
  z-index: 4 !important;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【感想】Laravel(+Vue.js)でSNS風Webサービスを作ろう!を終えて

Laravel(+Vue.js)でSNS風Webサービスを作ろう!を終えて

教材のご紹介

今回、私が学習した教材はこちらです。

Laravel(+Vue.js)でSNS風Webサービスを作ろう!
https://www.techpit.jp/p/laravel-vue-sns


★参考までに今までのTechpit歴
・Techpitの学び放題会員2か月
・(残念ながら)学び放題に入っていない教材5個くらい単発購入(してやられた)

ちなみにRails、Laravel、Python、Vue.jsなど含め、Techpit教材はかなり漁ってきました。その中でもかなりおすすめの教材です。

初学者がポートフォリオ作成で躓く(私含め)であろうミドルウェア、リクエスト、認可、ポリシー、さらにはフロンドエンドフレームワーク(Vue.js)との連携まで、実際にアプリを作りながら体験できます。

(他にもLaravelに関しては、AWSを用いた教材やVue.jsのSPAまで実装できる教材もあるので、そちらもおすすめです。(回し者ではありません。))

教材通り、herokuでデプロイも完了しております。参考までに。
http://laravel-vue-sns.herokuapp.com/

学習を終えて


この教材では、Mac&Laradockを用いた開発になりますが、私はWindows&XAMPPに置き換えて挑戦しました。

※というよりも、いつもこの環境で頑張って乗り切っています。(Mac環境の教材多すぎて辛い)

最終的に、Mailhogだけどうしても実装できませんでしたが、それ以外は問題なく実装できました。

また、今回XAMPP環境にPostgreSQLを紐づける方法も理解できたので、herokuも今後は積極的に利用していこうかなと思いました。(※herokuはPostgreSQLを推奨。かつFTPでデプロイするのは時間がかかりすぎるので。。。)

⇓参考までにXAMPPでPostgreSQLを使う方法に関しては、下記でまとめています。

https://chobimusic.com/laravel_xampp_postgresql/

今後に関して


今回のMailhogの実装失敗などを踏まえ、Laradockでのアプリ制作ができたほうが良いなと痛感しました。

また、この教材を参考にしながらVue.jsまで連携させたポートフォリオ制作に挑戦していこうと思います。

引き続き頑張ります✌

P.S.

独学中の身として、Twitterで執筆者の方々や学習者の方々とやり取りできるのがとても励みになっています。ありがとうございます。

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

[Vuex/Nuxt] storeをmodule化したときに[vuex] unknown action typeが出たときの対処法およびデバッグ法

きっかけ

今までクラシックモードで書いていたstoreをモジュールモードで書くことにしました。
index.jsの中でarticle.jsというファイルをmoduleとしてimportしたあと、
componentでactionを実行しようとしたら[vuex] unknown action type
というエラーが出たので、その対処法およびデバッグ法をご紹介します。

ファイル

store/index.js
import Vuex from "vuex";
import articles from "./modules/articles"

const store = () => new Vuex.Store({
  modules: {
    articles
  }
})

export default store
store/modules/article.js
const namespaced = true

const state = () => ({
  articles: []
})

const mutations = () => ({
  SET_ARTICLES(state, articles) {
    state.articles = articles
  }
})

const actions = () => ({
  setArticles(vuexContext, articles) {
    vuexContext.commit("SET_ARTICLES", articles)
  },
})

const getters = () => ({
  getArticles(state) {
    return state.articles
  }
})

export default {
  namespaced,
  state,
  mutations,
  actions,
  getters
}
pages/index.vue
<template>
  <div>
    <Header />
    <ArticleList :articles="articles" />
  </div>
</template>

<script>
import Header from '@/components/molecules/Header.vue'
import ArticleList from '@/components/organisms/ArticleList.vue'
import { mapGetters } from 'vuex'

export default {
  name: 'TopPage',
  components: {
    Header,
    ArticleList
  },
  async fetch({store, $axios}) {
    await $axios.$get("http://localhost:3000/api/v1/articles")
      .then((data) => {
        store.dispatch("articles/setArticles", data)
      })
      .catch(e => {
        console.log(e)
      })
  },
  computed: {
    ...mapGetters({
      articles: "articles/getArticles"
    }
  }
}
</script>

この状態でサーバにアクセスしたところ、
[vuex] unknown action type 'setArticles' undefined
が出てしまいました。
pages/index.vueのfetchのthen内部のdispatchが呼び出せていないようです。
しかし、moduleの設定などは確認したところすべて合っていました。

自分がしたこと

そもそも、setArticlesが読み込めていないということは、
1. article.jsでのsetArticlesメソッドの設定がおかしく読み込めていない
2. そもそもarticle.jsをmoduleとして読み込めていない
可能性があるので、まずは2番から確認していくことにしました。

「2. そもそもarticle.jsをmoduleとして読み込めていない」について

これは、axiosでdataを取得したあとのthenで一度 contextを確認してみればいいと感じました。

pages/index.vueのthenにconsole.logをはさみます。
※このcontextはnuxtContextです

pages/index.vue
<script>
...
  async fetch(context) {
    await $axios.$get("http://localhost:3000/api/v1/articles")
      .then((data) => {
        console.log(context.store.state) // ここです
        store.dispatch("articles/setArticles", data)
      })
      .catch(e => {
        console.log(e)
      })
...
</script>

結果としては、以下のオブジェクトが返ってきました。

{ article: { articles: [] } }

なので、article.js自体はmoduleとして正しく読み込めている ことがわかりました。

1. article.jsでのsetArticlesメソッドの設定がおかしく読み込めていない」について

となれば、あとはsetArticlesメソッドの部分を確認します。

これ、もう結論を言ってしまうのですがなぜ動かなかったのかというと、
article.jsの各定数(変数)をObjectではなくfunctionとして定義していたからです。

functionとして定義(動かなかった)

store/modules/article.js
const namespaced = true

const state = () => ({
  articles: []
})

const mutations = () => ({
  SET_ARTICLES(state, articles) {
    state.articles = articles
  }
})

const actions = () => ({
  setArticles(vuexContext, articles) {
    vuexContext.commit("SET_ARTICLES", articles)
  },
})

const getters = () => ({
  getArticles(state) {
    return state.articles
  }
})

export default {
  namespaced,
  state,
  mutations,
  actions,
  getters
}

Objectとして定義(動いた)

store/modules/article.js
const namespaced = true

const state = {
  articles: []
}

const mutations = {
  SET_ARTICLES(state, articles) {
    state.articles = articles
  }
}

const actions = {
  setArticles(vuexContext, articles) {
    vuexContext.commit("SET_ARTICLES", articles)
  },
}

const getters = {
  getArticles(state) {
    return state.articles
  }
}

export default {
  namespaced,
  state,
  mutations,
  actions,
  getters
}

actions, mutationsのデバッグについて

一番最初に確認した2.のケースではstateが正常に読み込まれていたので、
stateに関してはアロー関数式で表現しても問題ないように思いました。

が、actionsとmutations、gettersに関してはアロー関数式で定義するとunknown action typeが出てしまいます。

その際に、「どのようにしてactionsとmutations, gettersが正しく読み込まれているのかを知るのか」がわかりませんでしたが、
contextを確認した際にその確認方法がわかった気がしましたので、ここに載せておきます。

先程2.を確認した際、context.storeを確認しましたが、
このstoreの中にstateがあるならactionsやmutations, gettersもあるはず。
と考え、確認してみました。以下が確認結果となります(長いので大部分省略しています)

console.log(context.store)
<ref *5> Store {
  _committing: false,
  // 3行目------
  _actions: [Object: null prototype] {},
  _actionSubscribers: [],
  _mutations: [Object: null prototype] {},
  _wrappedGetters: [Object: null prototype] {},
  // ----------
  _modules: ModuleCollection {
    root: Module {
      runtime: false,
      _children: [Object: null prototype],
      _rawModule: [Object],
      state: [Object],
      context: [Object]
    }
  },
  // 下から9行目
  _modulesNamespaceMap: [Object: null prototype] {
    'articles/': Module {
      runtime: false,
      _children: [Object: null prototype] {},
      _rawModule: [Object],`
      state: [Object],
      context: [Object]
    }
  },

下から9行目、_modulesNamespaceMapのところに'articles/': Moduleとあるので、articles.jsが正しくmoduleとして読み込まれている、ということでしょう。

そして、3行目から下4行を見ると、_actions, _mutations, _wrappedGettersがあり、いずれも[Object: null prototype] {},となっています。
これは2.で確認した失敗のケースなので、actions, mutations, gettersともに登録されておらず{}となっているのでしょう。
おそらくここがactions, mutations, wrappedGettersのstoreだろうという推測のもと、それらをfunctionからobject表記に戻して確認してみると、

console.log(context.store)
<ref *5> Store {
  _committing: false,
  _actions: [Object: null prototype] {
    'articles/setArticles': [ [Function: wrappedActionHandler] ]
  },
  _actionSubscribers: [],
  _mutations: [Object: null prototype] {
    'articles/SET_ARTICLES': [ [Function: wrappedMutationHandler] ]
  },
  _wrappedGetters: [Object: null prototype] {
    'articles/getArticles': [Function: wrappedGetter]
  }

となり、やはり_actions, _mutations, _wrappedGettersがactions, mutations, gettersのstoreであることが実際にわかると思います。

まあstoreの中に入っているので当然といえば当然ですが、これを知っているだけでもデバッグは捗るような気がしています。

まとめ

1. unknown action typeが出る場合は、state, actions, mutations, gettersの定義を確認してみよう
→ functionではなくobjectとして登録するのが正解
2. actions, mutations, gettersが読み込まれているかを確認するときは、nuxtContextのstore内部の
_actions, _mutations, _wrappedGetters`の中身を確認してみよう

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

Vue + Rails + CarrierwaveでS3へのダイレクトアップロードをする

Heroku経由でS3にファイルアップロードする際、Herokuのリクエストタイムアウトは30秒に設定されているので、大容量ファイルをアップロードするとタイムアウトになりエラーになる。
そのため、Herokuで4MB以上のファイルをアップロードする際は、Herokuを介さずブラウザから直接アップロードすることが推奨されている。
https://devcenter.heroku.com/articles/s3#direct-upload

carrierwave_directでいいのかなと思ったけど、最後のPRが2016/12で終わっているので多分メンテナンスされていない...
carrierwave_direct

Railsのファイル保存では、Active Storageを使ったやり方はたくさん記事があったが、Carrierwaveを使ったやり方は情報があまりなかったので記事にする事にした。

Version

Rails 6.0.0
Carrierwave 2.0.2
Vue.js 2.6.11

ここではRailsのWebpackerでVue.jsの基本的な設定を行っているものとする。

処理の流れ

S3へのアップロードまでの流れは下記の通りとなる。
①Vue.js → Rails : レコード生成とS3にアップロードするための署名付きリンクをリクエスト
②Rails → Vue.js : 署名付きリンクを返却
③Vue.js → S3 : 取得した署名付きリンクでファイルアップロード

S3 Bucketの設定

S3にアクセスし、対象のBucketに入り、アクセス権限 → CORSの設定をクリック
スクリーンショット 2020-03-20 17.07.04.png
下記を追加して保存。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

Rails側の設定と処理

RailsからS3を操作出来るようにするために、aws-sdkをインストールし設定を行う。

# Gemfile
gem 'aws-sdk'
# config/initializers/aws.rb
unless Rails.env.test? || Rails.env.development?
  credentials = Aws::Credentials.new(
    ENV["S3_ACCESS_KEY_ID"],
    ENV["S3_SECRET_ACCESS_KEY"]
  )

  s3_resource = Aws::S3::Resource.new(region: 'bucketのリージョン名', credentials: credentials)
  S3_BUCKET = s3_resource.bucket('S3のバケット名')
end

URL生成のメソッドはCarrierwaveのUploaderで記述し、ファイル取得はCarrierwaveで行えるようにする。

class ApplicationUploader < CarrierWave::Uploader::Base
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def presigned_url(file_name = nil)
    file_name ||= self.model.attributes[mounted_as.to_s]
    object = S3_BUCKET.object([store_dir, file_name].join('/'))
    # 署名付きリンクは10分で失効(デフォルトでは15分)
    object.presigned_url(:put, expires_in: 10.minutes.to_i, acl: 'private')
  end
end

次にAPIを作っていく。

  #
  # post: /api/v1/products/id
  #
  def create
    @product = Image.new(product_params)
    # 先に@productのオブジェクトを作成し、後からファイルカラムを更新する
    if @product.save!
      @product.update_column('image', product_params[:image])
        render json: {
          id: @product.id,
          image_url: @product.image.presigned_url
        }
    else
      render json: @product.errors, status: :unprocessable_entity
    end
  end

Vue.js側の処理

次にフロント側のフォームと処理を書いていく。
まずはフォーム

<input
  class="custom-file-input"
  type="file"
  name="products[image]"
  ref="productImage"
>

<div class="form-group">
  <input
    type="submit"
    name="commit"
    value="アップロード"
    class="btn btn-success submit"
    data-disable-with="アップロード"
    @click="postProduct"
  >
</div>

次にメソッドの処理

export default {
  data: () => ({
    presignedUrl: '',
    uploadFile: {},
    productId: '',
  }),

  // ...

  methods: {
    async postProduct (e) {
      try {
        this.uploadFile = this.$refs.productImage.files[0]
        const postingUrl = `/api/v1/products`
        const payload = {
          product: {
            image: this.uploadFile.name
          }
        }
        const res = await this.$axios.post(postingUrl, payload)
        this.presignedUrl = res.data.image_url
        this.productId = res.data.id
        this.fileUpload()
      } catch(e) {
        console.error(e)
      }
    },

    async fileUpload () {
      try {
        const config = {
          headers: {
            'content-type': 'multipart/form-data'
          }
        }
        // formDataは使わずファイルをそのままアップロードする
        await this.$axios.put(this.presignedUrl, this.uploadFile, config)
      } catch(e) {
        console.error(e)
      }
    }
  }
}

以上の処理でS3へのアップロードは完了する。
注意点としては、S3へアップロードするファイルはformDataで成形せず、添付されたファイルをそのままアップロードする事。
formDataを使うとアップロードしたファイルにファイルのヘッダー情報などが入ってしまうため。

参考: WebKitFormBoundary uploading a file to S3 using axios FormData

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

Vue-Cli UI上でビルドするとError:CssDependencyが出る

はじめに

最近、フロントエンドのお勉強を始めました。
Vue?なにそれ?から二日目です。

Qiitaの投稿もmarkdown記法も初めてなので簡潔に。

ネットで拾ったチュートリアルを終えて、 build してみるかってとこで表題のエラー。

環境

vue-cli 4.2.3

エラー内容

Vue UI上でbuild実行時の出力

$ vue-cli-service build --mode production --dest dist --target app --dashboard

- Building for production...

ERROR Error: No module factory available for dependency type: CssDependency
Error: No module factory available for dependency type: CssDependency
...
...

コンソール上でのnpm run buildは正常終了するのに、UI上でビルドするとエラーになる。何故だ。

原因

実際のパスとVue UIが認識しているパスが異なってるのが原因っぽい。
参考:Error: No module factory available for dependency type: CssDependency #5154

問題があったのは下プロジェクト。
C:\Users\...\Vue_CrashCourse\vue_realtime_chatが正しいパス。
Vue UI上でプロジェクト作成したあと、直接フォルダ名を変えたのが悪かった。

コメント 2020-03-20 160113.png

解決法

インポートし直す。

serveは動くから「なんでなんで」だったけど、シンプルなミスでした。
ネット情報だとwebpackだったり、vueRouterのmodeが原因になりえるみたい。

以上。
Vueおもしろいっすね。

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

Vue.js入門編 ~コンポーネントについて ~

コンポーネントとは?

コンポーネントは名前付きの再利用可能な Vue インスタンス。
いわゆるVue.jsでインスタンスを生成してそれをHTMLに反映させるための
新しい箱のようなイメージですね。

では実際に成功品とコードを見てみましょう。

スクリーンショット 2020-03-20 13.42.48.png
スクリーンショット 2020-03-20 13.43.47.png

①Errorメッセージの表示
②クリックされた回数を表示
以上2つを説明していきます

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<style>
</style>
<body>
    <div id="app"> <!-- こちらがerrorメッセージ -->
        <alert-box>
            入力されていません
        </alert-box>
        <!-- コンポーネント化されているため反映される -->
        <alert-box>
            入力されていません
        </alert-box>
    </div>
    <!-- クリック回数の取得 -->
    <div id="components-demo">
        <button-counter></button-counter>
    </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

</body>
</html>

Id要素にはそれぞれappcomponents-demoが与えられているのが見てわかるかと思います。
ちなみに、<alert-box><button-counter>は実際にHTMLには存在せず、
コンポーネントによって作られたインスタンスになります。

それでは実際にVue.jsでどのようにインスタンスを生成しているのか見てみましょう。

①Errorメッセージの表示

Vue.component('alert-box',{ //alert-box というコンポーネント作成
  template:
    `<div class="alert" v-on:click="caution"> //htmlを記述
       <strong>Error!</strong>
       <slot></slot>
     </div>`,
     methods:{ //メソッドを定義
       caution: function(){ 
         alert('クリックされました') //アラートメッセージの表示
       }
     }
   });

var app = new Vue({ //id要素の取得
  el: "#app"
});

②クリックされた回数を表示

Vue.component('button-counter',{ //button-counter というコンポーネント作成
  data: function(){
    return{ //初期値
       count:0
          }
  },
  template: 
    `<button v-on:click="count++"><p>クリックされた回数は {{ count }} です</p></button>`
  });

 var button = new Vu({ //id要素の取得
   el: '#components-demo'
 });

以上の記述でこちらが完成します。

<参考文献>
https://jp.vuejs.org/v2/guide/components.html
https://www.youtube.com/watch?v=vD7fZY2F_Kc&list=PLh6V6_7fbbo-SZYHHBVFstU2tp0dDZMAW&index=8

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

永遠に続くクソ計算クイズ3 vue vuexで

成果物

https://amazing-minsky-06ffdf.netlify.com/

リポジトリ

https://github.com/yuzuru2/yuzuru2.github.io/tree/master/neta2

環境

  • node.js 12.14.0
  • parcel 1.12.4
  • typescript 3.8.3
  • vue 2.6.11
  • vuex 3.1.3

UI

無題.png

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

Cloud9でvue serveを実行する

はじめに

Cloud9にて「vue serve」が実行できなかったので、実行する手順をまとめました。

情報元

情報元は以下の記事です。

AWS Cloud9でVue.js開発、devServerを自動的に設定する。

本記事では上記の記事の一部を初心者向けの手順にまとめました。

フォルダ・ファイル構成

最終的には以下のようなフォルダ・ファイル構成となります。

image.png

まずは教科書通りにやる!

Cloud9にアクセスします。
Terminalが表示されていなければ、ツールバーの「Window」→「New Terminal」をクリックし、Terminalを表示する。

image.png

Terminalにて以下の2個のコマンドを実行して、Vue CLIをインストールする。

npm install -g @vue/cli
npm install -g @vue/cli-service-global

Terminalにて以下のようなコマンドを実行し、プログラムを配置するフォルダを作成し、配置するフォルダに移動する。

mkdir -p ~/environment/vue/my-first-vue
cd ~/environment/vue/my-first-vue/

Vueのソースを新規作成するために、左側のツリーにて以下のように「my-first-vue」を右クリックし、「New File」をクリックする。

image.png

「Untitled」となっているファイル名を「app.vue」に変更する。

image.png

作成した「app.vue」をダブルクリックしエディタで開く。

image.png

エディタにて以下のように入力し、Macならば「command+s」、Windowsならば「Ctrl+s」で保存する。

<template>
  <div id="app">
    <h1>こんにちはVue.js</h1>
  </div>
</template>

image.png

Terminalにて以下のコマンドを実行する。

vue serve

Terminalで以下のような表示になるまで待つ。

image.png

ツールバーの「Preview」→「Preview Running Application」をクリックする。

image.png

以下のような表示となる。

image.png

本来は「こんにちはVue.js」と表示されるべきなのに、上記のように表示されるのは、「vue serve」で起動したVueのdevServerが、Cloud9経由のアクセス(Cloud9が自動で割り振ってくれたホスト名でのアクセス)を許可していないためである。

Cloud9で動かすための追加手順

devServerにてCloud9経由でのアクセスを許可するために以下のような手順を実施する。

Vue CLI(Vue.jsのコマンドラインツール)の設定ファイルを追加するために、左側のツリーにて以下のように「my-first-vue」を右クリックし、「New File」をクリックする。

「Untitled」となっているファイル名を「vue.config.js」に変更する。

image.png

作成した「vue.config.js」をダブルクリックしエディタで開く。

エディタにて以下のように入力し、Macならば「command+s」、Windowsならば「Ctrl+s」で保存する。

module.exports = {
  devServer: {
    disableHostCheck: true
  }
}

Terminalを選択状態にして、Macならば「control+c」、Windowsならば「Ctrl+c」でdevServeを終了させる。
Terminalが以下の表示になれば良い。

image.png

Terminalにて以下のコマンドを実行する。

vue serve

Terminalで以下のような表示になるまで待つ。

image.png

ツールバーの「Preview」→「Preview Running Application」をクリックする。

image.png

以下のような表示となる。

image.png

これでCloud9でVue.jsが実行できた!

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

laravel 外部からのPOSTを許可

suicreditのクレジット決済を導入したい。

決済完了後、
先方から当サイトへの戻りとしてPOST送信でリンク移動する。

つまり、普通のリンク移動でないので、POST送信を許可しないと以下のエラーが出る。

Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException
No message

同一サイト内のPOSTならフォーム内に
{{ csrf_field() }}
と書くだけなのだが・・・。

ということで、外部から指定URLへのPOST送信を許可する方法。

指定URLへ、外部からのPOST送信を許可

Http/Middleware/VerifyCsrfToken.php
    protected $except = [
        '/mypage',
        //
    ];

vue.js で get でも post でも全て受け付けるように

web.php
Route::match(['get', 'post'] ,'/{app}', function () {
    //本番になったら削除する
    \File::cleanDirectory(storage_path()."/framework/views/");
    return view('vue');
})->where('app', '.*');

これで外部からのPOSTも受けることができる。

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

Laravel+Mysql+Vue.jsの開発環境をDockerで構築

はじめに

Laravel+Mysql+Vue.jsでSPAのWebアプリケーション作成の勉強をしたくて、Dockerで開発環境構築をしました。
開発の常で、開発環境構築に苦戦したので備忘録を兼ねて構築手順を記述します。
記載内容に誤り等ございましたら、ご指摘をよろしくお願いいたします。

開発環境

$ docker --version
Docker version 19.03.8, build afacb8b

$ docker-compose --version
docker-compose version 1.25.4, build 8d51620a

$ php artisan --version
Laravel Framework 7.2.0

$ mysql --version
mysql  Ver 14.14 Distrib 5.7.29, for Linux (x86_64) using  EditLine wrapper

$ npm list vue
`-- vue@2.6.11 

参考

ディレクトリ構成

project
├ docker-compose.yml
├ docker
│  ├ php
│  │  ├ php.ini
│  │  └ Dockerfile
│  └ nginx
│    └ default.conf
└ server

手順

1. ファイルを準備

以下のファイルを作成します。

  • Dockerfile
  • docker-compose.yml
  • php.ini
  • default.conf
project/docker/php/Dockerfile
FROM php:7.4.1-fpm
COPY php.ini /usr/local/etc/php/

RUN apt-get update \
  && apt-get install -y zlib1g-dev libzip-dev zip mariadb-client-10.3 libpng-dev libjpeg-dev curl wget \
  && docker-php-ext-install zip pdo_mysql

# nodejs install
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash -
RUN apt-get install -y nodejs

# Composer install
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('SHA384', 'composer-setup.php') === '$(wget -q -O - https://composer.github.io/installer.sig)') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME /composer
ENV PATH $PATH:/composer/vendor/bin
WORKDIR /var/www
RUN composer global require "laravel/installer"

mysql-clientのパッケージは削除されているので注意。

project/dockerfile-compose.yml
version: '3'
services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
      - ./server:/var/www
    depends_on:
      - db
  nginx:
    image: nginx
    container_name: nginx
    ports:
      - 80:80
    volumes:
      - ./server:/var/www
      - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - php
  db:
    image: mysql:5.7
    restart: always
    container_name: db-host
    environment:
      MYSQL_ROOT_PASSWORD: yourpassword
      MYSQL_DATABASE: phpapp_db
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    volumes:
      - ./docker/db/data:/var/lib/mysql
      - ./docker/db/my.conf:/etc/mysql/conf.d/my.cnf
      - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
      - 3306:3306
project/docker/php/php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
project/docker/nginx/default.conf
server {
  listen 80;
    index index.php index.html;
    root /var/www/public;

  location / {
    root /var/www/public;
    index  index.html index.php;
    }

  location ~ \.php$ {

    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
 }

2. dockerコンテナを立ち上げる

$ docker-compose build
$ docker-compose up -d

3. phpコンテナに入ってlaravelプロジェクトを作成する

$ docker-compose exec php bash
$ laravel new

4. dockerコンテナを一旦停止する

$ docker-compose down

5. .envファイルを編集する

以下のように無いパラメーターは追加し、すでに記述されているパラメーターは修正する。

project/server/.env
DB_CONNECTION=mysql
DB_HOST=db-host
DB_PORT=3306
DB_DATABASE=phpapp_db
DB_USERNAME=root
DB_PASSWORD=yourpassword

6. コンテナを立ち上げる

$ docker-compose up -d

7. ローカルホストにつながることを確認する

ブラウザから以下のURLにアクセスして正常に接続できることを確認する。

正常に接続できれば以下のような画面が表示される。

Built_laravel_environment_1

8. migrateが実行できることを確認する

phpコンテナに入ってmigrateを実行する。

$ docker-compose exec php bash
$ php artisan migrate

migrateが失敗する場合は以下の記事等を参考にして頂くと良いと思います。

9. Vue.jsの導入

npmでvueのパッケージをインストール。

$ npm install
$ npm install -D vue

vueのパッケージがインストールできていることを確認。

$ docker-compose exec php bash
$ npm list vue

開発環境構築は以上です。

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

CakePHP4 + Vue.js 開発での .editorconfig の設定内容

新しいプロジェクトを始めるたびに .editorconfig を変更していてるので、備忘録として残します。
新しい設定が必要なったら編集して記載内容を更新する予定です。

この記事でわかること

.editorconfig

CakePHP4 で Vue.js ( Laravel-Mix ) を使えるようにして docker-compose で動くようにする で作ったソースを元に始めます。

CakePHP4 のプロジェクトを作った時点で .editorconfig が用意されるのですが、足りない点があるので追記します。

.editorconfig
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.bat]
end_of_line = crlf

[*.{yml,json,scss,html,js,vue}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[*.twig]
insert_final_newline = false

[Makefile]
indent_style = tab

追記した点を補足します。

[*] > charset = utf-8
文字コードの指定です。
[*.{yml,json,scss,html,js,vue}] > indent_size = 2
インデント2のファイルは yml のみになっていたので、json, scss, html, js, vue とフロント開発に必要な拡張子を追加します。
[*.md] > trim_trailing_whitespace = false
markdown は後方スペースで改行を示す場合がある(使いたくない機能だけど)ので false とします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む