20200112のvue.jsに関する記事は12件です。

【Jest】Vueのテストを書こう!

Vueのテストを書こう!

Vue.jsのコンポーネントのテストについてナレッジを貯めていきます。(随時追加)

  1. テキスト表示についてのテスト
  2. DOM要素についてのテスト
  3. 子コンポーネントをスタブにしてテスト
  4. コンポーネントのfactory関数を定義する

テキスト表示についてのテスト

import { mount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'

describe('HelloWorld.vue', () => {
  it('renders a HelloWorld', () => {
    const wrapper = mount(HelloWorld)

    expect(wrapper.text()).toMatch("HelloWorld!!")
  })
})

DOM要素についてのテスト

import { mount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'

describe('HelloWorld.vue', () => {
  it('renders a HelloWorld', () => {
    const wrapper = mount(HelloWorld)
    expect(wrapper.html()).toMatch("<div><p>HelloWorld!!</p></div>")
  })
})

子コンポーネントをスタブにしてテスト

shallowMountメソッドで子コンポーネントをスタブ(代替えの偽物)としてマウントします。
mountだと子コンポーネントまですべてマウントされます。

const shallowWrapper = shallowMount(Parent)
console.log(shallowWrapper.html())
  • ログの結果

子コンポーネントが<vuecomponent-stub />とスタブとなって出力されています。

<div><vuecomponent-stub></vuecomponent-stub></div>

コンポーネントのfactory関数を定義する

一番上にvaluesオブジェクトをまとめてdataにして、新しいwrapperインスタンスを返すファクトリ関数を宣言します。

このようにすると、すべてのテストでconst wrapper = shallowMount(Foo)を複製する必要がありません

import { shallowMount } from '@vue/test-utils'
import Foo from './Foo'

const factory = (values = {}) => {
  return shallowMount(Foo, {
    data () {
      return {
        ...values
      }
    }
  })
}

describe('Foo', () => {
  it('welcome メッセージを描画する', () => {
    const wrapper = factory()

    expect(wrapper.find('.message').text()).toEqual("Welcome to the Vue.js cookbook")
  })

  it('usernameが7未満のときエラーを描画する', () => {
    const wrapper = factory({ username: ''  })

    expect(wrapper.find('.error').exists()).toBeTruthy()
  })

  it('usernameが空白のときエラーを描画する', () => {
    const wrapper = factory({ username: ' '.repeat(7) })

    expect(wrapper.find('.error').exists()).toBeTruthy()
  })

  it('usernameが7文字かそれ以上のとき、エラーが描画されない', () => {
    const wrapper = factory({ username: 'Lachlan' })

    expect(wrapper.find('.error').exists()).toBeFalsy()
  })
})

参考URL

Vue.js 公式サイト

vue-test-utils 公式サイト

vue-testing-handbook
➡︎より実践的な使い方がわかる

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

MonacaのアプリをCircleCIとDeployGateで自動デプロイした話

背景

Monacaで作成中のアプリの試験的配布を自動化したかった

そんな中CircleCIとDeployGateでアプリのリリース自動化という記事を色々見つけた

そこに検索ワードとしてMonacaやCordovaを足したらそれっぽい記事が見つからなかった....

ので頑張った
(作った後にMonaca CIの存在に気付いた...)

目的

Vue.jsにて開発しているMonacaアプリについて
ローカルで作成して
GitHubにpushして
CircleCIでビルドして
DeployGateでデバッガに配布したい

......とりあえずAndroid版だけ

内容

端的に言えば
CircleCIとDeployGateのアカウントを無料のでいいので取得し、GitHubと連携
後はリリースしたいリポジトリに下記ファイルを置けば動く
最後の行の[トークン]と[ユーザー名]は自分のDeployGateの情報にて書き換える

.circleci/config,yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/android:api-28-alpha

    working_directory: ~/repo # 作業フォルダ

    steps:
      # ビルド環境構築
      - run:
          name: apt-get upgrade
          command: |
            sudo apt-get update
            sudo apt-get upgrade -y

      - run:
          name: Setup Node.js via nvm
          command: |
            curl --silent -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash
            echo 'export NVM_DIR="$HOME/.nvm"' >> $BASH_ENV
            echo 'source "$NVM_DIR/nvm.sh" --no-use' >> $BASH_ENV 
            source $BASH_ENV
            nvm install v10.15.3 --no-progress
            nvm alias default v10.15.3
            sed -i -e 's/ --no-use//' $BASH_ENV

      - run:
          name: Install Cordova
          command: |
            npm install -g cordova
            sudo apt-get install gradle -y
            gradle -v

      - checkout

      # キャッシュがある場合はキャッシュから依存関係を復元
      - restore_cache:
          # 復元するキャッシュのkey
          keys:
            - v2-dependencies-{{ checksum "package-lock.json" }}
            - v2-dependencies-

      # Cordovaのビルド設定
      # この作業はチェックアウトしてCordovaのプロジェクトが出来てから行う必要がある
      - run:
          name: Setup Cordova to build as Android app
          command: |
            cordova platform add android@8.0.0
            gradle dependencies

      # 依存関係のインストール
      - run:
          name: Install dependencies
          command: npm install

      # ビルド
      - run:
          name: PreBuild
          command: npm run build

      # ビルドの確認
      - run:
          name: Check dist
          command: ls -la www

      # キャッシュの保存
      - save_cache:
          paths:
            - node_modules
          key: v2-dependencies-{{ checksum "package-lock.json" }}

      # ビルド
      - run:
          name: Cordova Build
          command: cordova build --debug --device

      # デプロイ
      - run:
          name: Upload to DeployGate
          command: |
            APK_PATH=platforms/android/app/build/outputs/apk/debug/app-debug.apk
            COMMIT_HASH=$(git log --format="%H" -n 1 | cut -c 1-8)
            curl -F "file=@${APK_PATH}" -F "token=[トークン]" -F "message=Test Build by CircleCI <${COMMIT_HASH}>" https://deploygate.com/api/users/[ユーザー名]/apps

まとめ・所感

これで手元のVSCodeからPushするだけでDeployGateからアプリ配布の通知が来てインストールできるので超便利になった

ビルドしたアプリがVue製のためタグにVueがとりあえず入っているけれど、ビルド環境の内容としてはReactでもAngularでも変わらないかと

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

【勉強会ポエム】パンダ本:第8章 Vue.js入門&実践活用?

React-Angular-Vue-ReactNative_png.png
(出典:https://gihyo.jp/book/2018/978-4-7741-9706-7)

記事の概要?‍♀️

  • 勉強会に参加した感想と備忘録
  • 通称パンダ本 p138〜
  • 第8章 Vue.js入門&実践活用を読みながら、学んだことを残します

誰向けか?

  • あんまり勉強会に参加したことがない人
  • Vueの概要を知りたい人
  • Vueの環境構築をしてみたい人

Vue.jsの概要

Vueとは

  • UIを構築するためのプログレッシブフレームワーク
  • 中国出身のEvanYou氏が開発

Evan You 氏

evanyou.jpeg

  • Googleのフロントエンドエンジニア
  • AngularJSとか
  • JavaScriptフレームワークの開発元Metor経た
  • Vue.jsに注力するため独立

 

Vue.jsの4つの特徴

1.テンプレートとCSS

  • テンプレート言語はHTML

    • 新たなDSLやプリプロセッサ(PugやHaml)を学ぶ必要がない
    • 既存のWEBアプリケーションの移行コストが低い
  • HTMLとCSS共通して、プリプロセッサを選択できるという特徴がある

 

2.リアクティブシステム

  • あるデータを変更した際に、変化がデータのフローに沿って伝播して関連するデータや表示なども書き換わる
  • モデルはプレーンなJavaScriptオブジェクト
  • モデルを変更するときにビューを更新する

 

3.コンポーネント

  • 独立した小さな部品に分割して再利用可能にする
  • 開発や管理、更新が行いやすい

 

4.段階的な機能の取捨選択

  • Vue.jsそのものは、コンポーネントを作成して描画するためのビューレンダリング用のライブラリ
  • Vue RouterやVuexなどのさまざまな機能を使うことができる
  • 上記を使うことで小さくコンパクトに、大規模に開発したいときなどスケールを合わせることができる

 

Vueをはじめるには

主に3つの方法がある

  • CDN
  • ダウンロード(ソースコードをプロジェクト内部に埋め込む)
  • Vue CLI (npmでインストールしていく)

Vue CLIを推奨(公式)

  • 必要な環境が簡単に整う
  • 便利機能が使用できる

この記事では、Vue CLIを使って環境を構築していきます!

Vue CLIをインストール(npm)
$ npm i -g vue-cli

無事にインストールできたか確認
$ vue --version
  #=>2.9.6

プロジェクトを作成する

vue init webpack vueChat
  • ↓エラーになる場合  
Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
  • 参考にした記事
  • 記事を確認すると、nodeのバージョンを6以上にあげればOKとのこと(ちゃんと調べてなくてすみません。)  
# 現在のNodeのバージョンを確認
nodebrew ls
v5.3.0
v9.10.1
v10.1.0
v12.12.0

current: v5.3.0

残念ながら、5.3.0でした

# とりあえず5よりもあげるようにする
nodebrew use v9.10.1
  • これでエラー出なくなりました!

引き続き開発環境を作ります(初期化)

// vueChatというプロジェクト名にしました
$ vue init webpack vueChat

# ここから作成するプロジェクトについて色々入力していく

? Project name vuechat
? Project description A sample chat of Vue.js
? Author azumax
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? No
? Set up unit tests No
? Setup e2e tests with Nightwatch? No
? Should we run `npm install` for you after the project has been created? (recommended) npm

   vue-cli · Generated "vueChat".

  • インストールが完了したら作ったディレクトリに移動して、npm実行する
# To get started:

 $ cd vueChat
 $ npm run dev

 

  • ブラウザにアクセスしてみる
(http://localhost:8080)

vuechat.png

  • 上図のような画面が表示されれば、ひとまず開発環境構築は成功です!

 

ディレクトリ構成の確認

  • 開発環境のディレクトリ構成を確認してみましょう
     

  • index.html

    • プロジェクトの起点になる
    • 表示用HTML
  • src

    • 作成したアプリケーションのソースコード格納
    • 作業用ディレクトリ
  • src配下のディレクトリ

    • main.js
      • アプリケーションの起点。エントリーポイントとなるファイル
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.

## ライブラリやコンポーネントをインポートする
## この3つは大事そう!
import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
  • 以下のコードでインスタンスを作成するとVueアプリケーションが実行される
new Vue({
  el: '#app',  #=> 出力・描画されるHTMLの要素を指定する。index.html
  router,      #=> routerの設定
  components: { App }, #=> 使用するコンポーネントの定義
  template: '<App/>'   #=> 描画
})
  • インスタンスの引数のオブジェクトの各属性で各設定を行う
  • componentsには、使用したいコンポーネント {key: コンポーネント}
    で登録する

  • 定義されたkeyが、templateで使用するコンポーネントの要素名になる

  components: { Hoge: App }, #=> keyを指定する
  template: '<Hoge/>'   #=> 要素名も合わせる
  • build
    • webpackなどトランスパイルに必要な設定ファイルが格納される

npmコマンドについて

  • npm run dev

    • ファイル更新すると表示されているページも更新されるホットリロード機能を持ったローカルホスト立ち上げコマンド
  • npm run build

    • 実行すると「distディレクトリ」がプロジェクト直下に作成される
    • distディレクトリには、minifyされたindex.htmlとかトランスパイルされたJSとCSSが格納されたstaticディレクトリが作成される
  • 基本的には、

    • ローカルホスト立ち上げなら run dev
    • トランスパイル実行もしたければ run build

単一ファイルコンポーネント

  • Vue.jsの醍醐味です
  • 勉強会の時間内で全て終わらなかったので、途中で終わってしまいます
  • 時間を見つけて続きを書いていこうかと思います?

 

  • 1つのファイル内で3つのブロックに切り分けて記述を行う、Vue専用の仕組み

    • JavaScriptのロジック
    • テンプレート
    • スタイル
  • 拡張子は「*.vue」

  • コンポーネントを複数に分けると、色々煩雑

    • すべてのコンポーネントに一意な名前を強制する
    • エディタでのシンタックスハイライト使えない
    • 複数行HTMLでバックスラッシュ、プラス記号が強要され、可読性さがる
    • ビルド処理がないことでHTMLの制限をうける
  • これらの問題を解決するのが、単一ファイルコンポーネントのしくみ

 

最後にポエムさせてください?‍♂️

  • 以前にVueの開発環境構築をしたときは、codesandboxを使ったのですが、今回はVueCLIで構築をしました
  • 参考:【勉強会ポエム】Vue.js×Firebaseで簡単なTwitter風アプリケーションを作ろう
  • 勉強会というタイトルではありましたが、内容はもくもく会でした
  • 勉強会だと思い(ハンズオンやセミナー形式と勘違い)来場した方も複数いらっしゃり、もくもく会とわかったタイミングで帰宅する姿が見られました。
  • 私自身は、もくもくやりながら、何か質問ができればいいなーくらいに考えていたので?‍♂️
  • 主催者の方は何かつまずいていないか常に気にしてくれて、いい人でした!
  • コミュニティ作りに力をいれているような印象を受けました!

参考記事

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

本当のimport Vue from 'vue'を研究して、分かってきたもの

import Vue from 'vue'はなぜ使えるか?

Vuejsの開発の際、よく最初に出てくるこれ

import Vue from 'vue';

下のような相対パスなどはまだわかりやすいけど、

import Example from './Example.vue';

vueはなずimportできるのか、みんな様こんな疑問はないのか。
もしかして俺一人の疑問かも?

少し研究してきたことをまとめてみた。

importとは

Javascriptのモジュールシステムです。他のファイルを使いたい時、require functionで他のファイルの内容を引用する。
es6を使っている時、importrequireにコンパイルする。
だから、実際に実行するコードは以下。

import Vue from 'vue';
⬇️
const Vue = require('vue')

nodejs引用ルール

実は、nodejsの中に、requireを使う時に、require.reslove functionを使ってファイルのパスを探している。このfunctionは優先順位は以下になる。
require(X) from module at path Y
1.もしXはコアのパッケージかどうか、普段のpathなどみたいは直接引用される。ではなければ、次へ。
2.もしX/から始めれば、YのパスはOSのrootと設定。ではなければ、次へ。
3.もしX./,/,../から始めれば、(Y + X)ファイルかディレクトリ引用。ではなければ、次へ。
4.node_modulesフォルダの中に、見つかる!

node_modulesにあるvue

node_modulesに確かにvueというフォルダは存在しているが、new Vue()などの操作の時は、JsのObjectとして使っている。では、なぜか!
真の犯人まではもう少し?❗️
npmのパッケージとして、内部の出力はまたルールがある!
まずは、node_modules/vueのディレクトリツリーを見てみる。

├── LICENSE
├── README.md
├── dist
├── package.json
├── src
└── types

ルールは以下になる。
1.package.jsonmainが定義されたら、mainに入り口を探す。
2.package.jsonがなければ、index.jsindex.nodeを読む。
3.どちらもなければ、Error: Cannot find module 'some-library'を投げる。

では、node_modules/vue/packeage.jsonこう書いてある❗️

  ...
  "main": "dist/vue.runtime.common.js",
  ...

ではでは、だんだん明らかになってきた❗️

本当にいつもimportしたものは...

import vue from 'vue';

// 実は、これに変換する
const vue = require('./node_modules/vue/dist/vue.runtime.common.js');

その内容は

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./vue.runtime.common.prod.js')
} else {
  module.exports = require('./vue.runtime.common.dev.js')
}

これは普段npmのスクリプトにあるNODE_ENV=developmentを読んで、実行環境に応じて違うvueインスタンスのexportができるようになった?

今回のimportルールや他にも今回出てなかったルールの詳細はnodejsのドキュメントに?

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

import Vue from 'vue'の意味を研究して、分かってきたもの

import Vue from 'vue'はなぜ使えるか?

Vuejsの開発の際、よく最初に出てくるこれ

import Vue from 'vue';

下のような相対パスなどはまだわかりやすいけど、

import Example from './Example.vue';

vueはなずimportできるのか、みんな様こんな疑問はないのか。
もしかして俺一人の疑問かも?

少し研究してきたことをまとめてみた。

importとは

Javascriptのモジュールシステムです。他のファイルを使いたい時、require functionで他のファイルの内容を引用する。
es6を使っている時、importrequireにコンパイルする。
だから、実際に実行するコードは以下。

import Vue from 'vue';
⬇️
const Vue = require('vue')

nodejs引用ルール

実は、nodejsの中に、requireを使う時に、require.reslove functionを使ってファイルのパスを探している。このfunctionは優先順位は以下になる。
require(X) from module at path Y
1.もしXはコアのパッケージかどうか、普段のpathなどみたいは直接引用される。ではなければ、次へ。
2.もしX/から始めれば、YのパスはOSのrootと設定。ではなければ、次へ。
3.もしX./,/,../から始めれば、(Y + X)ファイルかディレクトリ引用。ではなければ、次へ。
4.node_modulesフォルダの中に、見つかる!

node_modulesにあるvue

node_modulesに確かにvueというフォルダは存在しているが、new Vue()などの操作の時は、JsのObjectとして使っている。では、なぜか!
真の犯人まではもう少し?❗️
npmのパッケージとして、内部の出力はまたルールがある!
まずは、node_modules/vueのディレクトリツリーを見てみる。

├── LICENSE
├── README.md
├── dist
├── package.json
├── src
└── types

ルールは以下になる。
1.package.jsonmainが定義されたら、mainに入り口を探す。
2.package.jsonがなければ、index.jsindex.nodeを読む。
3.どちらもなければ、Error: Cannot find module 'some-library'を投げる。

では、node_modules/vue/packeage.jsonこう書いてある❗️

  ...
  "main": "dist/vue.runtime.common.js",
  ...

ではでは、だんだん明らかになってきた❗️

本当にいつもimportしたものは...

import vue from 'vue';

// 実は、これに変換する
const vue = require('./node_modules/vue/dist/vue.runtime.common.js');

その内容は

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./vue.runtime.common.prod.js')
} else {
  module.exports = require('./vue.runtime.common.dev.js')
}

これは普段npmのスクリプトにあるNODE_ENV=developmentを読んで、実行環境に応じて違うvueインスタンスのexportができるようになった?

今回のimportルールや他にも今回出てなかったルールの詳細はnodejsのドキュメントに?

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

Indexed Database APIを使ってスタンドアロンな付箋アプリを作ってみる

記事の趣旨

せっかくIndexed Database APIについて勉強したので,それを使ってブラウザアプリを作ってみた.

1. 作ったアプリと技術要素

ブラウザにスティッキー(付箋紙)っぽいメモを残していけるツール.本当はカンバン方式の管理ツールを作りたかったんだけれど,力尽きたのでいったん保留.画面キャプチャは以下のとおり.

kanban01.png

使用した技術要素は以下のとおり.Vue.jsは初めて触るので,書籍と睨めっこしながらの対応.

  • HTML
  • CSS
  • Vue.js
  • Indexed Database API(敢えてライブラリ未使用)

ソースコードはGithubのリポジトリに置いているのでご自由にどうぞ.動作は「Chrome 79.0.3945.117」で確認.Edgeでも動作するがレイアウトが若干崩れる.

2. 操作方法

直感で扱えるレベルだと思うけれど,とりあえず以下のとおり.

  1. cloneなりzip downloadなりでローカルに落としてきたらkanban.htmlを開く.
  2. 付箋紙を新たに作りたいときは左下のプラスマークをクリック.
  3. 付箋紙はドラッグ&ドロップで自由に移動可能.
  4. 付箋紙をダブルクリックすると編集ウィンドウ(後述)が開く.
  5. 編集ウィンドウでURLを登録しておけば,付箋紙左下の「URL」ボタンクリックでその画面に新タブで遷移可能.

kanban02.png

3. 苦戦したポイント

スキル低いので,初歩的だったり,間抜けなものばかりだが,恥を忍んで書いていく.

3.1 Promise

以下の処理は,「DBへのコネクションを確立する」->「チケットを全件取得する」->「グローバル変数にチケット情報を詰め込む」という意図のコードになる.このうち,createConnection()およびgetAllTickets()は,Promiseオブジェクトを返却する関数である.先日の記事でも述べたとおり,Indexed Database APIは非同期処理であるため,Promiseを活用することで同期を図っている.

    created: function() {
        createConnection().then(
            getAllTickets()
        ).then(
            (allTickets) => {
                allTickets.forEach(
                    ticket =>
                    {
                        tickets.push({
                            id: ticket.id,
                            text: ticket.text,
                            url: ticket.url,
                            categoryId: ticket.categoryId,
                            left: ticket.left,
                            top: ticket.top,
                            zIndex: ticket.zIndex,
                            deleted: false
                        })
                    }
                )
            }
        ).catch(
            (reason) => alert(reason)
        )
    }

さて,上記コードは一部が不正で,これだと同期処理にならない.どこかわかるだろうか.

答えは3行目.getAllTicket()と書いているが,ここはgetAllTicketと,関数オブジェクトを指定しないといけない.

promise.prototype.then()は,あくまでメソッドであり,その引数指定するのはコールバック関数.ものすごく間抜けなミスだが,うっかりif/elseの構文と同じような感覚で記述してしまい,上記のミスに至ってしまった.

3.2 Bubbling

今回の付箋紙オブジェクトは,複数のレイヤで構成されているので,Bubblingを意識してイベントをハンドリングしないといけない.が,そもそもその辺りを全然理解しておらず,序盤はかなり意図しない挙動に苛まれた.たぶん今も多少バグは残っていると思われる.

Bubblingについては,こちらのページの説明がとてもわかりやすいと思う.定義を引用させていただくと以下のとおり.

要素上でイベントが起きると、最初にその上のハンドラが実行され、次にその親のハンドラが実行され、他の祖先に到達するまでそれらが行われます。

今回でいうと,例えば「URL」ボタンをクリックすると,続けて付箋紙自体にセットされたマウスダウンイベントが処理されることになる.後者は付箋紙の移動に関わる処理なので,付箋紙がワープするなどの謎挙動が頻発していた.

Bubblingを防ぎたい場合は,event.stopPropagation()を呼び出すことで,それ以降の親オブジェクトへの伝播を抑制することができる.

4. ペンディングしている事項

  • 付箋紙の色の変更機能
    • categoryIdという死にパラメータがその名残
  • ファイルサーバやローカルへのショートカットボタン
    • エクスプローラの直接操作は無理そうなので,パスをクリップボードにコピーする処理を想定
  • ゴミ箱アイコンへのドロップによる付箋紙削除処理
    • 面倒臭くなって今は削除ボタンで代替
  • カンバンボード化と,付箋紙へのステータス(ToDo,WIP,Done)導入
    • そもそもそれを目指したアプリだったので
  • 複数タブ対応
    • 現在は複数タブでこのアプリを開いたら何が起きるか不明
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Vuejs(Nuxtjs)] 僕のVee-validateカスタムルール

TL;DR

  • 自分が業務で使用しているvee-validate 3.xのカスタムルールをまとめました。

概要

  • 自分はメディア運営会社のエンジニアとして働いているもので、メディアのコンテンツを入稿するツールをnuxtjsで開発や運用しています。入稿されるデータに不整合が起きないように、データ作成/更新前のバリデーションには気を使っています。バリデーションライブラリでは、vee-validateを使用しています。
  • 属性が多いモデルに関しては、様々な条件に柔軟に対応しないといけないのですが、デフォルトで提供されているvee-validateのルールだけだと対応できないな...と思い、色々と自分でカスタムで実装しました。が、そもそもそんなにカスタムルールの作り方が見つからなかったと思ったので、作り方などまとめました。

対象者

  • vee-validateは使ったことあり、これからカスタムルールをどう実装していく方。

技術スタック

  • nuxtjs 2.x
  • vuetify 2.x
  • vee-validate 3.x

カスタムルールの作り方

ここでは、vee-validate3.xをどうやってnuxtjsで使えるようにすればいいのかは詳細には書きません。

まずは、vee-validatenuxtjsで使えるようにするためのプラグインを用意します。
nuxt.config.jspluginsプロパティで読み込みます。

plugin/vee-validate.js
// vee-validateからルールを拡張できる関数をインポート
import { extend } from 'vee-validate'

// vee-validateがデフォルトで用意してくれているルールをインポート
import * as Rules from 'vee-validate/dist/rules' 

// 自分が実装したvee-validateのカスタムルールをインポート
import * as CustomRules from '~/utils/validation-custom-rules.js'

for (const rule in Rules) {
  extend(rule, Rules[rule])
}

for (const rule in CustomRules) {
  extend(rule, CustomRules[rule])
}

そしてカスタムルールを下のように定義します。下のページを参考しました。
https://logaretm.github.io/vee-validate/advanced/rules-object-expression.html#cross-field-validation

utils/validation-custom-rules.js
const custom_rule = {
  // ルールを書くときに使う引数。
  params: ['compare'],

  // バリデーションロジック
  validate(field, { compare }) {
    return true // or false true: バリデーションエラーなし, false: バリデーションエラーあり
  },

  // バリデーションエラーメッセージ
  message(field, { compare }){
    return `validation error. ${field}` 
  },
}

export { custom_rule }

プロジェクトで実装したカスタムルールの一部を記載。

utils/validation-custom-rules.js
/**
 * 数字が指定した桁数以下か検証する
 * @param max 最大桁数
 */
const max_digits = {
  params: ['max'],

  validate(value, { max }) {
    return value ? String(value).length <= max : true
  },

  message(field, { max }) {
    return `${field}${max}桁以下でなければなりません`
  },
}

/**
 * コレクションの要素数が指定していた数以下かを検証する
 * @param maxLength 最大要素数
 */
const collection_max_length = {
  params: ['maxLength'],

  validate(value, { maxLength }) {
    if (!Array.isArray(value)) {
      return false
    }

    return value.length <= maxLength
  },

  message(field, { maxLength }) {
    return `${field}${maxLength}つまでしか選択することができません。`
  },
}

export { max_digits, collection_max_length }

実際にどう使うか

実際にコンポーネントでどうカスタムルールを使うかを記載します。

<template>
  <v-row justify="center">
    <v-col cols="12">
      <!-- rulesを文字列で渡す場合 -->
      <validation-provider v-slot="{ errors }" name="記事ID" rules="numeric|max_digits:7">
        <v-text-field v-model="articleId" :error-messages="errors" label="記事ID" counter="7" type="number" />
      </validation-provider>
    </v-col>

    <v-col cols="12">
      <!-- オブジェクトを渡すこともできます。 -->
      <validation-provider v-slot="{ errors }" name="色" :rules="{ collection_max_length: { maxLength: 3 } }">
        <v-select v-model="selectedColors" multiple chips :items="colors" :error-messages="errors" />
      </validation-provider>
    </v-col>
  </v-row>
</template>

<script>
export default {
  data() {
    return {
      articleId: 0,

      selectedColors: [],
      colors: ['red', 'blue', 'yellow', 'green', 'purple'].map((color) => ({ value: color, text: color })),
    }
  },
}
</script>

自分が指定したバリデーションエラーメッセージが表示されたことを確認。
スクリーンショット 2019-12-30 21.34.29.png

まとめ

  • メディアのコンテンツを入稿するツールを作っていく以上、不適切なデータが入稿され、メディアのブランドや信用性が損なわれるのを防ぐ必要があると思っています。こうやって、カスタムでバリデーションルールを実装できるので、コンテンツを作るユーザーが安心して、良いコンテンツを入稿できるように、日々起こりうるデータの不整合をなくしていければと思います。最後まで読んでいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue ナビゲーション

○ <router-link :to="{ path: '/product' }">

○ <router-link :to="{ path: '/product', query: { page: 1 } }">

x <router-link :to="{ path: '/product', param: { id: 1 } }">

○ <router-link :to="{ name: 'product', param: { id: 1 } }">
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue URLにハッシュをつけない

Vue Router
ハッシュ
ヒストリー

ハッシュモードはハッシュ値の変更によって現在のルートを検知するため、
ブラウザのHistory Apiのサポートやサーバ側の設定を必要としないが、

自動的にURLに「#」が付与されページ内リンクが使用できない

export default new Router({
+ mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Home,
},

あと.htaccessかserver.confにmode_rewrite的な設定必要

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

npm run serveできない

Windowsで開発していたvue.jsファイルをmacで動かそうとしたら以下のようなエラーが出た。

$ npm run serve

> my-project@0.1.0 serve /Users/hoge/hoge
> vue-cli-service serve

 INFO  Starting development server...
10% building 2/2 modules 0 activeevents.js:180
      throw er; // Unhandled 'error' event
      ^

Error: getaddrinfo ENOTFOUND x86_64-apple-darwin13.4.0
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26)
Emitted 'error' event at:
    at GetAddrInfoReqWrap.doListen [as callback] (net.js:1412:12)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:17) {
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'x86_64-apple-darwin13.4.0'
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! my-project@0.1.0 serve: `vue-cli-service serve`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the my-project@0.1.0 serve script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/.npm/_logs/2020-01-11T15_34_59_526Z-debug.log

解決策

モジュールを再インストールする。

rm -rf node_modules/
npm install

sudoをつけて実行する。
https://stackoverflow.com/questions/49008498/npm-run-serve-error

sudo npm run serve

試したこと

https://akamist.com/blog/archives/2827
上記の記事を参考に

rm -rf node_modules
rm package-lock.json
npm cache clear --force
npm install

を実施。改善しない...。

なんならnpm installでpythonのエラーが出てきた...。

gyp ERR! find Python 
gyp ERR! find Python Python is not set from command line or npm configuration
gyp ERR! find Python Python is not set from environment variable PYTHON

pythonエラーはcondaの仮想環境を停止させたら消えたが、依然として解決できず...

vueのバージョン確認

~/documents/vue $ vue --version
@vue/cli 4.1.2

原因はなんだったのか

調査中

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

Vue AtomicDesignでフォルダ構成する

AtomicDesign

今回はAtomicDesignの考えのもと、フォルダ構成していきたいと思います。

AtomicDesignとは
一言で言うと5段階に区切って定義するUIデザイン手法。
5段階とは、
Atoms(原子),
Molecules(分子),
Organisms(有機体),
Templates(テンプレート),
Pages(ページ)です。

化学用語が分からなくても実は簡単。

5段階詳しく

Atoms(原子)
ボタンやテキスト入力などの分けられない単位。

Molecules(分子)
ボタンやテキスト入力を組み合わせたフォーム(検索フォーム)。

Organisms(有機体)
フォームだったりボタンなど組み合わせたヘッダー。

Templates(テンプレート)
ヘッダーとかフッターを組み合わせたページの枠組みです。

Pages(ページ)
テンプレートの枠組みに内容を入れた状態がページ。

VueでAtomicDesign

AtomicDesignの考えをもとにVueでフォルダ構成しました。
それがこちら

.
├── node_modeuls/
├── src/
│     ├── assets/
│     ├── components/
│         ├── atoms/
│         │    └──buttons/
│         ├── molecules/
│         └── organisms/
│              └── footer.vue
│ 
├── pages/
├── main.js
├── router/
│   └── index.js
├── store/
└── App.vue

AtomicDesignをカスタマイズして構成しました。

カスタマイズ点
1.Templateは必要がないので削除
2.organismsとpagesのみstoreとやりとりするのはOK。
3.pagesはrouterとやりとりするのでcomponents外
4.atomsの中にもボタンや入力欄を分けるためにフォルダを作成


人それぞれの好みとプロジェクト規模により異なる点もあるかと思うので参考にしてもらえればと思います。

以上!

はてなブログもやってます

はてなブログのVue系⬇︎
https://taitoajiki.hatenablog.com/archive/category/Vue

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

Vue 環境構築

前提

Node.jsのインストールでnpmコマンドが使えること。

インストール

@vue/cliをインストール

npm install --global @vue/cli

プロジェクト作成

vue create [project naeme]

その後にいくつかの質問に答えて設定します。

今回はbabel,Typescript,Vuex,Router,es-lintをチェック。

cd [project naeme]
npm run serve

終了

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