- 投稿日:2021-06-20T23:13:47+09:00
Vue2+Composition APIでVue Test Utilsのtrigger,emittedが機能しない時の対処方法
概要 今後はVue3を使うことが多くなると思いますが、Vue2 + Composition APIを使う環境で、 triggerを行った結果イベントがemitされることを wrapper.emitted で検証しようとしても、 戻り値がundefinedしか取れずうまく行かない事象が起きてハマっていました。 const expectedId = 'test-id' const wrapper = mount(SideMenuItem, { propsData: { id: expectedId, title: 'テスト', }, }) await wrapper.find('[data-test="menu-item"]').trigger('click') expect(wrapper.emitted('click')[0][0]).toBe(expectedId) // wrapper.emitted('click') の戻り値がundefinedでうまく行かない。 // もう少し調べると emitted() の戻り値が空のオブジェクトになっている。 TL;DR jest用に以下の設定ファイルを作成し、jest.config.js で指定する必要がありました。 Vue2ではComposition APIはプラグイン扱いなので、当然と言えば当然でした。 setup.js import Vue from 'vue' import CompositionApi from '@vue/composition-api' Vue.use(CompositionApi) jest.config.js module.exports = { //中略 setupFiles: ['./setup.js'], } 詳細 コンポーネント <template> <div> <div @click="handleClick" data-test="menu-item" > {{ title }} </div> </div> </template> <script> import { defineComponent } from '@vue/composition-api' export default defineComponent({ props: { id: { type: String, required: true, }, title: { type: String, required: true, }, }, setup(props, context) { const handleClick = () => { context.emit('click', props.id) } return { handleClick, } }, }) </script> テスト it('クリック時にイベントがemitされること', async () => { const expectedId = 'test-id' const wrapper = mount(SideMenuItem, { propsData: { id: expectedId, title: 'テスト', }, }) await wrapper.find('[data-test="menu-item"]').trigger('click') expect(wrapper.emitted('click')[0][0]).toBe(expectedId) })
- 投稿日:2021-06-20T23:03:52+09:00
Vue.jsでカスタムページネーションを作る
Vue.jsにはVue Pagination 2というpagination用のライブラリがありますが、仕組みを理解したいと思い自作しました。今回はそのカスタムページネーションについて記事にします。ソースコードはGitHubにて公開しています。 手っ取り早く実装したい方は上記ライブラリを使うことをお勧めします。時間があり、仕組みから理解したい人は読んでくれたら嬉しいです。 完成図 手の込んだことはしておらず、ページボタンを押すと表示するアイテム一覧が変わるだけの簡単な実装にしています。 対象読者 普段pagination実装はライブラリで済ませているけど、今こそ中身を理解したいと言う人 既存ライブラリのpaginationに満足しておらず、自作paginationを作りたいと思っている人 内容 方針 やっていることは決して難しいことではなく、表示したい部分のインデックスを取得して、それに対応する配列の一部分を取ってくるだけです。ページの変更は、表示したいインデックスを変更するだけで大丈夫です。 それでは実装に移りましょう。 実装 紙面の都合上、重要な部分のみ取り上げます。詳細に関してはGitHubより確認して頂ければと思います。 Vue.jsの基本はすでに理解している前提で話を進めますが、難しいことはしていないので基本を押さえている方であれば大丈夫だと思います。 ページネーションコンポーネントには次の2つを渡します。 1. アイテムを格納した配列 (items) 2. 1ページに表示したいアイテム数 (itemNumPerPage) App.vue <template> <div class="home"> <pagination :items="items" :itemNumPerPage="10" /> </div> </template> 今回はデモなので渡すアイテム配列は要素に文字列を持つ配列にしています。 続いて、ページネーションコンポーネントについて見ていきます。 Paginaiton.vue <template> <div class="pagination"> <div class="item-list"> <item v-for="(item, idx) in displayItems" :key="idx" :title="item" /> </div> <div class="page-btns"> <page-button @changePage="changePage" v-for="n in pageNum" :key="n" :pageNumber="n" :curPage="curPage" /> </div> </div> </template> <script> import Item from '@/components/Item.vue'; import PageButton from '@/components/PageButton.vue'; export default { components: { Item, PageButton }, props: { items: Array, itemNumPerPage: Number, }, data() { return { curPage: 1, // curPage starts from 1 pageNum: 0, // number os pages } }, created() { this.calcPageNum(); }, computed: { displayItems() { const startIdx = (this.curPage - 1) * this.itemNumPerPage; const endIdx = startIdx + this.itemNumPerPage; return this.items.slice(startIdx, endIdx); }, }, methods: { changePage(value) { this.curPage = value; }, calcPageNum() { this.pageNum = Math.ceil(this.items.length / this.itemNumPerPage); } } } </script> itemコンポーネントは単に渡した数字を表示しているだけなので省きます。 実際に画面に表示したいアイテム部分列を選んでいるのは算出プロパティdisplayItemsです。 displayItems() { const startIdx = (this.curPage - 1) * this.itemNumPerPage; const endIdx = startIdx + this.itemNumPerPage; return this.items.slice(startIdx, endIdx); } 表示したい配列部分の開始、終了インデックスを計算して、スライス関数を使って部分配列を作成して返しています(現在のページ番号を保存する変数curPageは画面に表示されているページ番号と揃えるために1スタートにしている点に注意)。 ページ数の計算はcalcPageNum関数で行っています。この関数はcreatedで呼び出しています。 calcPageNum() { this.pageNum = Math.ceil(this.items.length / this.itemNumPerPage); } Math.ceil()にしているのは、最終ページの表示アイテム数がitemNumPerPageより小さい場合でも表示できるようにするためです。 続いてPageButtonコンポーネントについて見ます。 PageButton.vue <template> <div class="page-btn"> <button @click="btnPressed" :class="{active: isCurrentPage}" >{{ pageNumber }} </button> </div> </template> <script> export default { props: { pageNumber: Number, curPage: Number }, computed: { isCurrentPage() { return this.pageNumber === this.curPage; } }, methods: { btnPressed() { this.$emit('changePage', this.pageNumber); } } } </script> propsでcurPageを受け取り、同じページ番号のボタンの背景色は変えています。 ボタンが押されたときに親コンポーネントに対してcurPageを変更するように知らせています。親コンポーネントであるpagination.vueではその知らせを受け取ったら、changePage関数を呼び出して新しいページ番号にcurPageを変更しています。 pagination.vue changePage(value) { this.curPage = value; } 以上で実装に関しては終わりです。 まとめ 本記事ではVue.jsを使ったカスタムページネーションの作成について解説しました。 時間ができたときに、一つ前、先のページに進むボタンなどを付け加えたいと思っています。 「もっとこうした方が良いよ」「こういうやり方もあるよ」というアドバイスがあれば、ぜひコメントを書いてくださると助かります。 参考資料 Pagination in Vanilla Javascript
- 投稿日:2021-06-20T17:05:23+09:00
【Javascript】axiosエラーハンドリング共通化を考えてみた
Vue.jsの開発で非同期通信にaxiosを使用している。 非同期通信時のエラーハンドリングのロジック自体は同じで、各axios実装箇所で行っていた。 開発の効率や、ソースコードの可読性、後々メンテナンス、拡張などを考えた時のために共通化を考えてみた。 axios実装のビフォーアフター Before 【既存のaxios実装】 axiosの各呼び出し箇所で下記のようなエラーハンドリングしており、同じロジックコードが散在している。 axios.post(url, params) .then(response => { // 成功時の処理 }).catch(error => { // 失敗時の処理 switch (error.response?.status) { case 401: // HTTPステータスに応じて処理 case 403: default: // 例外処理 } }); After 【エラーハンドリングの共通化後のaxios実装】 エラーハンドリングを共通化したことでaxiosの各呼び出し箇所では成功時の処理のみを実装する。 ソースコードがスッキリした!! const response = axios.post(url, params); if(response) { // 成功時の処理(エラー時は共通コードでハンドリングされるため、responseが返らない) } axiosのエラーハンドリング共通化 axiosAPIのInterceptorsを活用する。 Interceptorsについてはこちら参照:Interceptors | axios公式 Interceptorsを使って、axiosのエラーハンドリングを共通化 axiosErrorHandler.js axios.interceptors.response.use(function (response) { // 成功時の処理 return response; }, function (error) { // 失敗時の処理 switch (error.response?.status) { case 401: // HTTPステータスに応じて処理 case 403: default: // 例外処理 } }); ちなみにInterceptorsはaxiosのrequest前処理も共通化することができる Nuxt.jsを使っていたらpluginが用意されているのでそちらを使用するのが良さそうです →nuxt/axios Vue.jsでのエラーハンドリングについて、ご意見や事例があればぜひお聞かせください
- 投稿日:2021-06-20T15:58:34+09:00
npm package をアップデートしたい時の便利なコマンド
npm package をアップデートしたい時のコマンド npm packageをアップデートしたい時によく使用するコマンドについてまとめます。 今回packageを見ていくのは vue-hackernews-2.0 をです。 $ git clonse https://github.com/vuejs/vue-hackernews-2.0.git $ cd vue-hackernews-2.0 npm outdated outdatedコマンドは、レジストリをチェックして、インストールされている(または特定の)パッケージが現在古くなっているかどうかを確認する。 デフォルトでは、ルートプロジェクトの直接の依存関係と構成されたワークスペースの直接の依存関係のみが表示する。 --allすべての古いメタ依存関係も検索するために使用する。 実行 $ npm outdated Package Current Wanted Latest Location autoprefixer 7.2.6 7.2.6 10.2.6 vue-hackernews-2.0 babel-loader 7.1.5 7.1.5 8.2.2 vue-hackernews-2.0 chokidar 1.7.0 1.7.0 3.5.2 vue-hackernews-2.0 cross-env 5.2.1 5.2.1 7.0.3 vue-hackernews-2.0 css-loader 0.28.11 0.28.11 5.2.6 vue-hackernews-2.0 file-loader 1.1.11 1.1.11 6.2.0 vue-hackernews-2.0 firebase 4.6.2 4.6.2 8.6.8 vue-hackernews-2.0 lru-cache 4.1.5 4.1.5 6.0.0 vue-hackernews-2.0 rimraf 2.7.1 2.7.1 3.0.2 vue-hackernews-2.0 route-cache 0.4.3 0.4.3 0.4.5 vue-hackernews-2.0 stylus-loader 3.0.2 3.0.2 6.1.0 vue-hackernews-2.0 sw-precache-webpack-plugin 0.11.5 0.11.5 1.0.0 vue-hackernews-2.0 url-loader 0.6.2 0.6.2 4.1.1 vue-hackernews-2.0 vue 2.6.12 2.6.14 2.6.14 vue-hackernews-2.0 vue-server-renderer 2.6.12 2.6.14 2.6.14 vue-hackernews-2.0 vue-template-compiler 2.6.12 2.6.14 2.6.14 vue-hackernews-2.0 webpack 3.12.0 3.12.0 5.39.1 vue-hackernews-2.0 webpack-dev-middleware 1.12.2 1.12.2 5.0.0 vue-hackernews-2.0 webpack-merge 4.2.2 4.2.2 5.8.0 vue-hackernews-2.0 webpack-node-externals 1.7.2 1.7.2 3.0.0 vue-hackernews-2.0p current: 現在インストールされているバージョン wanted: 存在するバージョンのうち、 package.json に記載された semver 条件を満たす最新のバージョン。 Latest: レジストリで最新としてタグ付けされているパッケージのバージョン Location: 物理ツリーのどこにパッケージが配置されているか ※ semverとは? Semantic Versioning の略 3.14.1 一番左側の数字をメジャーバージョン、真ん中の数字をマイナーバージョン、一番右側の数字をパッチバージョン パッチバージョン:後方互換性のあるバグ修正やドキュメントの変更などをした場合、パッチバージョンの値をひとつ大きくする。 マイナーバージョン:後方互換性のある機能追加とドキュメントの追記をした場合、マイナーバージョンの値をひとつ大きくする。 メジャーバージョン:後方互換性のない変更がある場合、メジャーバージョンの値をひとつ大きくする。 npm update このコマンドはtag、semverを尊重して、リストされているすべてのパッケージを最新バージョン(構成で指定)に更新する。 また、不足しているパッケージもインストールする。 マイナーバージョンまで最新化される。 実行 $ npm update npm WARN ajv-keywords@3.5.2 requires a peer of ajv@^6.9.1 but none is installed. You must install peer dependencies yourself. + vue-template-compiler@2.6.14 + vue@2.6.14 + vue-server-renderer@2.6.14 updated 3 packages and audited 1001 packages in 4.595s 12 packages are looking for funding run `npm fund` for details found 15 vulnerabilities (4 low, 8 moderate, 3 high) run `npm audit fix` to fix them, or `npm audit` for details vue-template-compiler@2.6.14 vue@2.6.14 vue-server-renderer@2.6.14 の3つのパッケージがlatest(マイナーバージョンの最新バージョン)に更新されました。 npm audit auditコマンドは、プロジェクトで構成されている依存関係の説明をデフォルトのレジストリに送信し、既知の脆弱性のレポートを要求する。 脆弱性が見つかった場合は、影響と適切な修正が必要な箇所が表示される。 low(低レベル), moderate(中レベル), high(高レベル), critical(致命的) の 4種類に分かれます。(infoというのもあります。) https://docs.npmjs.com/cli/v7/commands/npm-audit#audit-level 基本的に全てに対応したいですが、BreakingChangeなどもありなかなか対応できないものもあります。しかしcriticalとhighについては絶対対応すべきです。 実行 $ npm audit ..... found 15 vulnerabilities (4 low, 8 moderate, 3 high) in 1001 scanned packages run `npm audit fix` to fix 2 of them. 12 vulnerabilities require semver-major dependency updates. 1 vulnerability requires manual review. See the full report for details.. (訳) スキャンした1001個のパッケージから15個の脆弱性(低4個、中8個、高3個)が見つかりました。 npm audit fix` を実行して、そのうちの2つを修正しました。 12個の脆弱性は準メジャーな依存関係の更新が必要です。 1つの脆弱性は手動でのレビューが必要です。詳細は報告書の全文をご覧ください。。 ┌───────────────┬──────────────────────────────────────────────────────────────┐ │ High │ Regular Expression Denial of Service │ ├───────────────┼──────────────────────────────────────────────────────────────┤ │ Package │ normalize-url │ ├───────────────┼──────────────────────────────────────────────────────────────┤ │ Dependency of │ css-loader [dev] │ ├───────────────┼──────────────────────────────────────────────────────────────┤ │ Path │ css-loader > cssnano > postcss-normalize-url > normalize-url │ ├───────────────┼──────────────────────────────────────────────────────────────┤ │ More info │ https://npmjs.com/advisories/1755 │ └───────────────┴──────────────────────────────────────────────────────────────┘ More info の URIにアクセスすると脆弱性内容の詳細を見ることができます。 今回は、 https://www.npmjs.com/advisories/1755 Overview The xmlhttprequest-ssl package before 1.6.1 for Node.js disables SSL certificate validation by default, because rejectUnauthorized (when the property exists but is undefined) is considered to be false within the https.request function of Node.js. In other words, no certificate is ever rejected. Remediation Upgrade to version 1.6.1 or later (訳) 概要 Node.jsの1.6.1以前のxmlhttprequest-sslパッケージは、デフォルトでSSL証明書の検証を無効にしています。これは、Node.jsのhttps.request関数内でrejectUnauthorized(プロパティが存在するが未定義の場合)がfalseとみなされるためです。つまり、証明書が拒否されることはない。 対応策 バージョン1.6.1以降にアップグレードする。 正規表現を使ったDoS攻撃(ReDoS)を食らう危険があるらしい。。。 自動で修正する方法 npm audit コマンドには脆弱性のある箇所を自動修正してくれるサブコマンドfixがあります $ npm audit fix found 13 vulnerabilities (3 low, 7 moderate, 3 high) in 1001 scanned packages 12 vulnerabilities require semver-major dependency updates. 1 vulnerability requires manual review. See the full report for details. npm ls lsコマンドは、インストールされているパッケージのすべてのバージョンと依存関係をツリー構造で標準出力に出力する。 実行 今回は npm audit コマンドで脆弱性 high の normalize-url について見てみます。 npm ls <package名> $ npm ls normalize-url vue-hackernews-2.0@ /Users/taimikam/workspace/vue-hackernews-2.0 └─┬ css-loader@0.28.11 └─┬ cssnano@3.10.0 └─┬ postcss-normalize-url@3.0.8 └── normalize-url@1.9.1 npm dedupe ローカルパッケージツリーを検索し、依存関係をツリーのさらに上に移動することで全体的な構造を単純化しようとする。依存関係は、複数の依存パッケージでより効果的に共有できる。 以下のような依存関係ツリーがあるとする。 a +-- b <-- depends on c@1.0.x | `-- c@1.0.3 `-- d <-- depends on c@~1.0.9 `-- c@1.0.10 npm dedupe は以下のように変換する。 a +-- b +-- d `-- c@1.0.10 その他便利packageについて npm-check-updates https://github.com/raineorshine/npm-check-updates npm-check-updatesは、指定されたバージョンを無視して、package.jsonの依存関係を最新バージョンにアップグレードします。 実行 ❯ ncu Checking /Users/hoge/workspace/vue-hackernews-2.0/package.json [====================] 35/35 100% compression ^1.7.1 → ^1.7.4 cross-env ^5.1.1 → ^7.0.3 es6-promise ^4.1.1 → ^4.2.8 express ^4.16.2 → ^4.17.1 firebase 4.6.2 → 8.6.8 lru-cache ^4.1.1 → ^6.0.0 serve-favicon ^2.4.5 → ^2.5.0 vue-router ^3.0.1 → ^3.5.1 vuex ^3.0.1 → ^3.6.2 autoprefixer ^7.1.6 → ^10.2.6 babel-core ^6.26.0 → ^6.26.3 babel-loader ^7.1.2 → ^8.2.2 babel-preset-env ^1.6.1 → ^1.7.0 chokidar ^1.7.0 → ^3.5.2 css-loader ^0.28.7 → ^5.2.6 file-loader ^1.1.5 → ^6.2.0 friendly-errors-webpack-plugin ^1.6.1 → ^1.7.0 rimraf ^2.6.2 → ^3.0.2 stylus ^0.54.5 → ^0.54.8 stylus-loader ^3.0.1 → ^6.1.0 sw-precache-webpack-plugin ^0.11.4 → ^1.0.0 url-loader ^0.6.2 → ^4.1.1 vue-loader ^15.3.0 → ^15.9.7 webpack ^3.8.1 → ^5.39.1 webpack-dev-middleware ^1.12.0 → ^5.0.0 webpack-hot-middleware ^2.20.0 → ^2.25.0 webpack-merge ^4.2.1 → ^5.8.0 webpack-node-externals ^1.7.2 → ^3.0.0 現在のバージョン → 最新バージョン を表示してくれます。 ncu -u を実行すると package.jsonを強制的に最新packageを使用するように書き換えてくれます。 最後に 今回紹介した以外にも npm package を更新するのに便利なコマンドがあると思います。 CIなどと組み合わせて自動更新スクリプトを組むのも良いかもしれませんね。
- 投稿日:2021-06-20T15:15:50+09:00
【Vue Vuex】非親子コンポーネント間の値を非同期で更新する方法
はじめに 非親子のコンポーネント間で情報を動的に変更したいと思った時に、少し困ったのですが解決方法はとても単純だったので記事として残します。 経緯 Vueで開発している際にA.vueファイルで更新した内容を、非親子のB.vueファイルに反映させるにはどのようにしたら良いかを考えていました。 具体例 ページ(Body.Vue)でVuexのactionで更新処理を実行し、 ヘッダー(Header.Vue)に表示されている情報を更新したい場合 方法 VuexのStateの値を更新して他ファイルのStateの値も更新すること Body.VueからVuexのcolorについてのstateの値が更新されることで、Header.Vueで参照しているcolorについてのstateの値も更新されます。 よって、他ファイルの値をVuexのstate経由で更新することができます。 Header.vue <template> <div :style="headerColor"> HEADER COLOR!!!!! </div> </template> <script> export default { name: 'Header', computed: { ...mapGetters(['Color']), headerColor(){ Color.mainColor }, }, mounted: {}, methods: {}, } </script> 補足 VueではDataに値を定義して使用するのではなく、できるだけcomputedに値を定義して使ったほうが良い理由が理解できました。 親子間のデータのやり取りにばかり気を取られて、全体のデータ更新について理解が及んでいませんでした。 参照
- 投稿日:2021-06-20T13:38:02+09:00
vue環境構築(npm,yarnインストールからサーバー起動まで)
npm, yarnインストール Mac OSの場合 以下に従ってhomebrewを入れる。 https://brew.sh/index_ja.html 以下でインストールを確認 $ brew -v # => 1.1.0 # Homebrew/homebrew-core (git revision bb24; last commit 2016-11-15) nodebrewを入れる。 $ brew install nodebrew # ... $ nodebrew -v # => 0.9.6# ...(いろいろ表示される) 安定版のnodeをインストールする。 $ nodebrew install-binary stable PATHを通す $ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile # bashの場合 # $ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zprofile # zshの場合 # *** ターミナル再起動 *** nodeのバージョン確認 $ node -v yarnも入れる $ npm install --global yarn # ...(いろいろ表示される) $ yarn --version Windows の場合 以下からnodeのインストーラ(LTS版)を取得して、インストールする。 https://nodejs.org/ja/ インストール確認 PS> node --version ::: v14.17.1 yarnも入れる。 PS> npm install --global yarn ::: ... PS> yarn --version ::: 1.22.10 WSLの場合 sudo apt install -y nodejs npm sudo npm install -g n sudo n lts # --- terminal reboot --- # sudo apt purge -y nodejs npm sudo apt autoremove -y node -v # -> v14.17.0 sudo apt install -y curlcurl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list sudo apt update && sudo apt install yarn yarn --version # -> 1.22.5 vue/cliインストール $ npm install -g @vue/cli # $ sudo npm install -g @vue/cli # Linux, WSLの場合 スクリプト実行権限の設定(PowerShellのみ) この項目は、自己責任で実施するか、PowerShell以外を使ってください。 PowerShellでvueコマンドを使う場合は、実行権限の変更が必要。 管理者モードでPowerShellを起動する。以下で実行権限を確認し、 PS> PowerShell Get-ExecutionPolicy Restricted 以下で変更する。 PS> PowerShell Set-ExecutionPolicy RemoteSigned PS> PowerShell Get-ExecutionPolicy RemoteSigned vue/cliでプロジェクト作成 $ vue create my-project 設定は以下の通り。 Vue CLI v4.5.13? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter, Unit, E2E ? Choose a version of Vue.js that you want to start the project with 3.x ? Use class-style component syntax? No ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass) ? Pick a linter / formatter config: Standard ? Pick additional lint features: Lint on save, Lint and fix on commit ? Pick a unit testing solution: Jes t? Pick an E2E testing solution: Cypress ? Where do you prefer placing config for Babel, ESLint, etc.?: In dedicated config files ? Pick the package manager to use when installing dependencies: (Use arrow keys): Use Yarn 以下一つずつ説明。 まず、マニュアルにする。 ? Please pick a preset: Manually select features 次で設定する項目を選ぶ。PWA以外は有効とした(PWAはスマホ対応なので要らないと考えた)。 ? Check the features needed for your project: Choose Vue version, Babel, TS, Router, Vuex, CSS Pre-processors, Linter, Unit, E2E vueのversionは新しい方を選択。 ? Choose a version of Vue.js that you want to start the project with 3.x # vueは3.xを使用 Noとする。vue3では、class-styleではなくcomposition APIという方がスタンダードらしい。 React Hooksのうな型推論の恩恵を受けれるというのが自分的には好印象だったので。 https://qiita.com/jesus_isao/items/0b305c7d90c45ad66c1b ? Use class-style component syntax? No ここはデフォルトのYes。 ? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes サーバー側で対応が必要だが、SPAで操作履歴を見るためには、historyがあった方が都合よさそうなのでYes。 ? Use history mode for router? (Requires proper server setup for index fallback in production) Yes 生CSSは辛そうなので、新しいdart-SCSSを使ってみる。 ? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass) Linterの設定。airbnbは結構厳しいみたいなので、Standardにした。 Prettierは後でインストールする。 忘れないよう保存時に強制適用にする。 ? Pick a linter / formatter config: Standard? Pick additional lint features: Lint on save, Lint and fix on commit テストフレームワークは標準になってきているJestを設定 ? Pick a unit testing solution: Jest E2EテストはCypressが良いらしい。 ? Pick an E2E testing solution: Cypress 各設定ファイルは別ファイルに合った方がいいかな。 ? Where do you prefer placing config for Babel, ESLint, etc.?: In dedicated config files yarn, npmどちらを使うか聞かれたらyarnを選択。 ? Pick the package manager to use when installing dependencies: (Use arrow keys): Use Yarn サーバー起動 $ cd my-project$ yarn serve
- 投稿日:2021-06-20T01:52:33+09:00
【Tips】Vue.jsのSPAでもGoogle Analyticsで細かい画面遷移の情報を取得する
はじめに Vue.jsでSPAを作っているとURLが変わらないので、Google Analyticsで情報が充分に取得できないのではないかという懸念があったので調べてみたが、実際には問題なく取得することができたので方法を簡単にまとめる。 なお、今回は以下のような簡易な画面遷移をするSPAで、 ページロード時は、/ のパスに遷移したことにする ボタン1を押下時は /#button1 のパスに遷移したことにする ボタン2を押下時は /#button2 のパスに遷移したことにする ボタン3を押下時は /#button3 のパスに遷移したことにする という仕様にする。 コンテンツ コンテンツは、index.htmlとapp.jsの簡易な構成とする。 index.html <html> <head> <style> [v-cloak] { display: none } </style> <meta charset="utf-8"> <title>Google Analytics SPAおためし</title> </head> <body> <div id="myapp" v-cloak> <div v-if="button_desabled">ボタンを押下してください</div> <div v-if="button1_enabled">ボタン1選択中</div> <div v-if="button2_enabled">ボタン2選択中</div> <div v-if="button3_enabled">ボタン3選択中</div> <button v-on:click="button1_clicked" v-bind:disabled="button1_enabled">ボタン1</button> <button v-on:click="button2_clicked" v-bind:disabled="button2_enabled">ボタン2</button> <button v-on:click="button3_clicked" v-bind:disabled="button3_enabled">ボタン3</button> </div> <!-- Vue.js を読み込む --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://www.googletagmanager.com/gtag/js?id=${ga_mesurement_id}"></script> <script src="app.js"></script> </body> </html> ${ga_mesurement_id} には、Google Analyticsの設定ページで払い出された「測定ID」を設定する。 app.js window.dataLayer = window.dataLayer || [] function gtag () { dataLayer.push(arguments) } gtag('js', new Date()) const app = new Vue({ el: '#myapp', data: function () { return { button_desabled: true, button1_enabled: false, button2_enabled: false, button3_enabled: false } }, created: function () { gtag('config', '${ga_mesurement_id}', { page_path: '/' }) }, methods: { button1_clicked: function () { this.button_desabled = false this.button1_enabled = true this.button2_enabled = false this.button3_enabled = false gtag('config', '${ga_mesurement_id}', { page_path: '/#button1' }) }, button2_clicked: function () { this.button_desabled = false this.button1_enabled = false this.button2_enabled = true this.button3_enabled = false gtag('config', '${ga_mesurement_id}', { page_path: '/#button2' }) }, button3_clicked: function () { this.button_desabled = false this.button1_enabled = false this.button2_enabled = false this.button3_enabled = true gtag('config', '${ga_mesurement_id}', { page_path: '/#button3' }) } } }) app.$mount('#myapp') ここも、それほど難しいことはない。 Google Analyticsを window.dataLayer = window.dataLayer || [] function gtag () { dataLayer.push(arguments) } gtag('js', new Date()) で初期化し、あとはアクセス記録をしたい箇所で gtag('config', '${ga_mesurement_id}', { page_path: '[パス]' }) とすれば良い。 実際にコンテンツにアクセスしてボタンを押してみると…… 以下のような感じで、Google Analyticsのコンソール上でpage_pathで指定した単位でアクセスが分計できている。 これで、SPAでもいろいろな分析ができるようになった!
- 投稿日:2021-06-20T01:37:49+09:00
【Vue.js】ヘッダーをVue.jsで実装する
概要 Vue.jsでヘッダーを共通化して利用できるようにする。 v-forを使用して配列に入れた要素を呼び出す。 HTML index.html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <link rel="stylesheet" href="./css/style.css" /> <title></title> </head> <body> <div id="header"> <ul class="header-menu"> <li v-for="(item, i) in menus" :key="i" class="menu-item"> <a :href="item.path">{{item.label}}</a> </li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="./script/script.js"></script> </body> </html> Vue.JS script.js // header new Vue({ el: "#header", data() { return { menus: [ { label: "TOP", path: "./index.html", }, { label: "AAA", path: "./aaa.html", }, { label: "BBB", path: "./bbb.html", }, { label: "CCC", path: "./ccc.html", }, { label: "DDD", path: "./ddd.html", }, { label: "EEE", path: "./eee.html", }, { label: "FFF", path: "./fff.html", }, ], }; }, }); CSS style.css .header-menu { display: flex; justify-content: flex-start; align-items: center; padding: 12px; margin: 0; background: #e8e8e8; } 完成図 感想 共通化できるようになり手間が減った。