20210101のvue.jsに関する記事は7件です。

Vue.jsで非同期処理関数を作る方法

皆さんこんにちは!!!

今回はVue.jsで非同期処理関数を作る方法をご紹介します!

めちゃめちゃ簡単なので、ぜひ学習の参考にしてください。

それでは説明していきます。

Promiseを用いて関数を作成

今回はTimeoutの関数を非同期処理で行います。

Vue.jsで非同期処理関数を作成する際は、宣言時にPromiseを利用するのではなく、返り値として利用します。

App.vue
<script>
  export default{
    methods: {
        sleep(mesc) {
          return new Promise((resolve) => {
            setTimeout(resolve, mesc)
        })
      } 
    },
  }
</script>

エラー対処

Vue2.x系を使っている方は下記のようなエラーが出ると思います。(出ない方はスルーして結構です)

error: npm i core-js/fn/promise

このエラーの対処の仕方は、僕が書いた記事core-jsの依存関係エラー(core-js/~/~)対処法を参考にして頂くと、恐らく解決できます。解決できない場合はコメント欄にてご報告をお願いします。

以上、「Vue.jsで非同期処理関数を作る方法」でした!

めちゃめちゃ簡単♪

良ければ、LGTM、コメントお願いします。

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!

Thank you for reading

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

vueで親コンポーネントで非同期通信が完了してから子コンポーネントでの通信を行いたい

vue3で親コンポーネントで非同期処理が終わってから子コンポーネントの処理を行いたい時のメモ

結論

親コンポーネントの処理が終わったらv-ifで子コンポーネントを有効にする。

親.vue
<template>
  <子コンポーネント v-if="mount"/>
</template>

<script lang="ts">
export default {
  setup() {
    const mount = ref<boolean>(false)
    親コンポーネントの非同期処理().then(() => mount.value = true)
    return { mount }
  }
}
</script>

その他

・v-showは表示されていないだけでコンポーネントは生成されるため、非同期処理の完了を待たずに実行される。
・Vue3の新機能suspenseを使うとv-showと同じような動作となる。
・setup関数をasyncにして非同期処理をawaitにすると表示されない(親コンポーネントでsuspenseを使う必要がある?)

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

とりあえずMacでVueの環境を整えてみた

スタンドアロン版のVue.js devtoolsをmacに入れていくメモ。
なおNode.JSのインストールまでは
MacにNode.jsをインストール
を参考にさせていただいています。

必要なこと

1.Homebrewのインストール(済)
2.nodebrewのインストール
3.Node.jsのインストール
4.Vue.js devtoolsのインストール

Homebrew

HomebrewはMacでのソフトウェアや拡張機能の管理を行うパッケージマネージャです。便利です。

Homebrewのインストールについては
Homebrewのインストール
を参照してます。

環境

開始段階の環境として
・mac OS Catalina 10.15.7
・Homebrew 2.7.1
はインストール済みです。

nodebrewのインストール

・インストール

ターミナルを開いてnodebrewをインストールしていきます。

ターミナル コマンド
brew install nodebrew

・確認

インストールできたか確認してみます。

ターミナル コマンド
nodebrew -v
ターミナル 結果
nodebrew 1.0.1

Usage:
    nodebrew help                         Show this message
    nodebrew install <version>            Download and install <version> (from binary)
    nodebrew compile <version>            Download and install <version> (from source)
    nodebrew install-binary <version>     Alias of `install` (For backward compatibility)
    nodebrew uninstall <version>          Uninstall <version>
    nodebrew use <version>                Use <version>
    nodebrew list                         List installed versions
    nodebrew ls                           Alias for `list`
    nodebrew ls-remote                    List remote versions
    nodebrew ls-all                       List remote and installed versions
    nodebrew alias <key> <value>          Set alias
    nodebrew unalias <key>                Remove alias
    nodebrew clean <version> | all        Remove source file
    nodebrew selfupdate                   Update nodebrew
    nodebrew migrate-package <version>    Install global NPM packages contained in <version> to current version
    nodebrew exec <version> -- <command>  Execute <command> using specified <version>

Example:
    # install
    nodebrew install v8.9.4

    # use a specific version number
    nodebrew use v8.9.4

こんな感じでツラツラと出てきたらOKです。

Node.jsのインストール

・インストール

今回はとりあえず最新版をインストールしようと思います。

ターミナル コマンド
nodebrew install-binary latest
ターミナル 結果
Fetching: https://nodejs.org/dist/v15.5.0/node-v15.5.0-darwin-x64.tar.gz
######################################################################## 100.0%
Installed successfully

・有効化

最新版をそのまま有効化していきます。

ターミナル コマンド
nodebrew use latest
ターミナル 結果
use v15.5.0

今回はインストールされている最新版がv15.5.0だったので、これでOKです。

・パスを通す

ターミナルから起動できるようにパスを通します。

ターミナル コマンド
echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile

確認のためターミナルで以下のコマンドを実行します。

ターミナル コマンド
node -v
ターミナル 結果
v15.5.0

先程有効化したv15.5.0が表示されました。
これでNode.jsのインストールは完了です。

Vue.js devtoolsのインストール

・インストール

最後に本命のVue.js devtoolsをインストールしていきます。
引き続きターミナルで以下のコマンドを実行します。

ターミナル コマンド
npm install -g @vue/devtools

なんやかんや出てきます。

ターミナル 結果
added 201 packages, and audited 202 packages in 21s

6 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

・起動

インストールできたようなので、動作確認していきます。

ターミナル コマンド
vue-devtools

・結果

別ウインドウが開いて以下の画面が出れば起動成功です。
お疲れ様でした!
スクリーンショット 2021-01-01 16.50.48.png

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

Laravel + Inertia + Vueで簡単にAPI実装する

はじめに

2021年明けましておめでとうございます!
2020年は色々あり、コロナに翻弄された年でした。
この逆境に立ち向かい、社会に貢献されているすべての皆様に敬意を表させて頂きます。
恐らく2021年も、変わらずな環境下であると思われますが…皆様同様に私も負けじと頑張ります。

さて…PHPerの皆様、Laravel8をガンガンお使いでしょうか?
Laravel8では、Laravel JetstreamというUIライブラリが用意されており、簡単にアプリケーションを作ることができるようになりましたね。
このJetstreamは、以前から似たようなものがありましたが、より簡単に作ることができるようになりました。
CSSをBootstarpからTailwind CSS に変更しており、より柔軟にCSSを使いUIを作ることができます。
さらに、実装においては、Livewireを用いてBladeを利用するか、Inertia.jsを用いてVueを利用するかを選択することができます。
Laravel8を触ってから、Inertiaを初めて知ったのですが、非常に理にかなった思想で便利だったので、そのInertiaについて書こうと思います。

Inertiaとは?

Inertiaは、「Modern Monolith(モダン モノリス)」という事を謳っています。
マイクロサービスが広まる中、モノリシックは時代錯誤な気がしますよね。
フロントエンド + バックエンドの構成では、APIを設計し実装し、フロントではそれを呼び出して描写する…これを書くAPI毎に毎回書くわけで、よく考えればこれは冗長ではないでしょうか?
Inertiaはその「毎回書くこと」をライブラリで吸収して、実装を簡単にするためのライブラリです。
API設計は必要ありません、APIの呼び出しも必要ありません。
変数やルーティングは、バックエンドの実装をもとにフロントエンドの変数のアサインやルーティングを作成してくれます。
フロントエンド + バックエンドの構成でありながら、サーバーサイドテンプレートを扱うように(モノリシックであるかのように)、 実装が可能です。
なので、ModernでありながらMonolithなもの、というわけです。

inertia_1.png

inertia_2.png

実装サンプル

routes/web.php

<?php

use Illuminate\Support\Facades\Route;

// 通常のroutingです。
Route::resource('/user','App\Http\Controllers\UserController');

UserController.php

<?php

namespace App\Http\Controllers;

use App\Models\User;
use Inertia\Inertia;

class UserController extends Controller
{
    public function index()
    {
        // Inertia::renderを呼び出す事で、どのコンポーネントに対して
        // どの変数をセットするかをここできめ、vueにも反映させることができます。
        return Inertia::render(
            'User/Index',
            ['users' => User::all()]
        );
    }

    // show
    // create
    // store
    // edit
    // update
    // destroy
}

resources/js/Pages/User/index.vue

<template>
  <layout title="Users">
    <div v-for="user in users" :key="user.id">
      <inertia-link :href="`/users/${user.id}`">
        {{ user.name }}
      </inertia-link>
      <div>{{ user.email }}</div>
    </div>
  </layout>
</template>

<script>
import Layout from '../Shared/Layout'

export default {
  components: {
    Layout,
  },
  /* Controllerで指定した変数をpropsで受け取るため、同じ変数名を指定します。
    IFはInertiaにおまかせです。
  */
  props: {
    users: Array,
  },
}
</script>

vue側でのルーティングは、Vue Routerを使わずに、Inertia側で受け持ちます。
その為、this.$route.params等は使えず、laravel側からパラメータは受け渡すことになります。
* vueを触っていると使えるのが当たり前だと思っており、使えず若干ハマりました…。

まとめ

実装サンプルのように、APIのレスポンス時も、フロントで受け取る側もいつもの記述は必要がないことがわかります。
実はコンポーネントの設計もある程度もInertiaの設計に引っ張られる為、構成が整っていいかもしれません。
デメリットとしては、ブラックボックス化してしまう事くらいでしょうか。
ただフレームワーク自体もある程度ブラックボックス化しているわけで、それと同じようなものだと考えれば、気にならないくらいのレベルです。
メリットとしては、「バックエンドテンプレートと似たような感じでVueを使える」「APIやりとりのコードが極端に減る」等です。

是非、モダンモノリスなライブラリ「Inertia」を使って見てください。

それでは今年も頑張りましょう!

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

【Vue.js】Vuexで双方向バインディング(v-modelを使いたい!)

はじめに

Vuexでv-modelを使いたいなぁ、ブラウザバックしたときに入力値が保持されるといいなぁ、と思ったときに実装した内容を残しておきます。

ここでは検索フォームを例に取り上げますが、フォーム入力全般に応用できると思います。

環境

vue @2.6.12
vue-router @3.4.9
vuex @3.6.0

双方向算出プロパティを使う

store.js に関連の処理を書く

まずは、store.js(またはそれに準ずる処理が書かれている場所)に以下のような処理を用意します。ここでは、keyword というstateを例に取り上げます。

store.js
export default new Vuex.Store({
  state: { // 1
    keyword: ''
  },
  getters: { // 2
    keyword: state => state.keyword
  },
  mutations: { // 3
    setKeyword: function(state, keyword) {
      state.keyword = keyword
    },
  },
  actions: { // 4
    getKeyword: function({ commit }, keyword) {
      commit('setKeyword', keyword)
    },
  }
})

それぞれの役割

1) Vuexのstoreにv-modelで扱いたいstateを用意する。
2. gettersでstate.keywordの値を取得できるようにする。
3. mutationsでstateの値を書き換えられるようにする。
4. actionsでmutationsを呼び出せるようにする。

2)gettersはもとの値を書き換えることがありません。ここでは読み取り専用であることを明示するために、あえてgettersを介しthis.$store.getters.keyword で値を参照できるようにしています。もちろん this.$store.state.keyword としてstateから値を参照することもできます。

3)stateの値を変更する処理です。stateの値を変えるときはmutationsを介して変更するようにします。stateを変更する処理が他のコンポーネントに書かれていると管理が煩雑になるためです。

4)さらに3のmutationsをcommitするための処理を書いています。他のコンポーネントからは、このactionsをdispatchすることで処理を行います。もちろんmutationsを直接commitしても問題ありません。

書き方はさまざまありますので、プロジェクト全体のルールに従うのが良いでしょう。

computedをgetとsetに分ける

次に実際に使用したいコンポーネントに移ります。
ここでは、inputタグのv-modelに keyword を用意しました。

search.vue
<input type="text" v-model="keyword">

次にcomputedに記述していきます。getとsetに分けて次のように書くことで、読み取りと書き込みの両方を実現できます。

  computed: {
    keyword: {
      get() {
        return this.$store.getters.keyword
      },
      set(value) {
        this.$store.dispatch("getKeyword", value);
      }
    }
  }

getはstoreから値を読み取る処理、setは値が変更されたときに実行する処理です。setの引数に、イベントが起こったときの値が入ります。
さきほど、actionsに設定した getKeyword を呼び出して、引数にvalueを渡すことでstateの値を書き換える処理を行っています。

以上で、Vuexでも、v-modelを扱えるようになります。

さいごに

本稿で取り上げたのは、Vuex公式でフォームの扱いの項目で説明されている内容に基づきます。公式で丁寧に説明がなされているものの該当箇所のみでは全体像がわからないため、関連するコードを記事としてまるっとまとめておきたいと思いました。

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

Vue.jsでちょっとハマったtips

下記構成でハマったこと。

  • vue-cliで初期化
  • vue-router導入
  • axios導入

vue.jsはvue3

ハマったこと

  • 別コンポーネントのmethodsを呼び出す方法
# BlogContents.vue
<script>
import MicroCms from '@/components/MicroCms.vue'

export default {
  name: 'Blog',
  mounted () {
    MicroCms.methods.getBlog() # この記法じゃないと呼び出せない
  }
}
</script>

# MicroCms.vue
<script>
import axios from 'axios'

export default {
  name: 'MicroCms',
  methods: {
    getBlog: function () {
      axios.get(
        // 処理
      )
    }
  }
}

BlogContents.vueからMicroCms.vuegetBlog()を呼ぶ際に下記の記法だと取得できなかった。

MicroCms.getBlog()

この記法だとgetBlog()はfunctionじゃないから見つからない的なエラーが出力される。

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

vue.js コンポーネントでDialogを作ってみる

Vue.js コンポーネントでDialogを作ってみる

vueでDialog(MessageBox的な?)コンポーネントを作ってみました。

まずは公式のマナーをおさらい

コンポーネントへデータを渡す際には
Untitled Diagram.png
プロパティ経由でデータを渡す必要があり、

逆に子コンポーネント側から親コンポーネントにデータを伝える場合、
Untitled Diagram (1).png
カスタムイベント経由で伝える必要があります。

でもDialog的な部品って

たとえばC#だと

DialogResult result = MessageBox.Show("メッセージ","タイトル",MessageBoxButtons.YesNoCancel);
if(result== DialogResult.Yes){
 //Yesを押したとき・・・
}

たとえばjavascriptだと

if( window.confirm( "メッセージ" )){
 //Yesを押したとき・・・
}

って使いたいですよね?

vue3で作ってみた

まずはダイアログ本体のコンポーネント

vue-dialog.vue
<script lang="ts">
import { defineComponent, PropType} from "vue";
import { DialogData } from "@/component/vue-dialog/vue-dialog.ts";
export default defineComponent({
    props: {
        data: {
            type: Object as PropType < DialogData > ,
            default: () => new Object()
        },
    },
    setup(props, { emit }) {
        const cancel = () => {
            if (props.data.dialogOption.cancel.isShow) {
                props.data.cancelClick();
            }
        };
        return {
            props,
            cancel 
        }
    },
});
</script>
<template>
<div class="dialogContainer" :class="{'closed':!props.data.isShow,'isShowCancel':props.data.dialogOption.cancel.isShow}" :style="{'z-index': props.data.zindex}">
    <div class="dialogBackGround" v-show="props.data.isShow">
    </div>
    <div class="dialogCardContainer" @click.stop="cancel ">
        <div class="dialogCard">
            <div class="dialogCard--header">
                <div class="title">{{props.data.title}}</div>
                <button type="button" class="closeBtn" @click.stop="cancel" v-if="props.data.dialogOption.cancel.isShow">
                    <i class="fas fa-times"></i> {{props.data.dialogOption.cancel.label}}
                </button>
            </div>
            <div class="dialogCard--body">
                <div class="message">{{props.data.message}}</div>
                <div class="btnContainer">
                    <button class="resultBtn" :style="{'order':props.data.dialogOption.isRightBottonYes==true?0:1}"
                     v-if="props.data.dialogOption.no.isShow" @click.stop="props.data.noClick()">
                        {{props.data.dialogOption.no.label}}</button>
                    <button class="resultBtn" :style="{'order':props.data.dialogOption.isRightBottonYes==true?1:0}"
                     v-if="props.data.dialogOption.yes.isShow" @click.stop="props.data.yesClick()">{{props.data.dialogOption.yes.label}}</button>
                </div>
            </div>
        </div>
    </div>
</div>
</template>

※cssはダイアログっぽいモーダルを用意します(省略)

要点は

  • プロパティで受け渡す[DialogData]
  • ダイアログ表示後のユーザー操作時の処理方法
    • プロパティにある関数を実行

プロパティについて

DialogData はダイアログに関するデータを受け渡すプロパティ

vue-dialog.ts
export class DialogData {
    public zindex: number;//ダイアログを出す時のz-index
    public isShow: Boolean;//ダイアログ用コンポーネントの表示非表示
    public title: string;//ダイアログのタイトル
    public message: string;//ダイアログのメッセージ
    public dialogOption: IDialogOption;//ダイアログに関する設定
    constructor(zindex: number = 2000) {
        this.isShow = false;
        this.title = "";
        this.message = "";
        this.zindex = zindex;
        this.dialogOption = InitDialogOption();
    }
    public yesClick: any;// ダイアログモーダルでユーザーがYesボタンを押下した時に実行する関数
    public noClick: any;// ダイアログモーダルでユーザーがNoボタンを押下した時に実行する関数
    public cancelClick: any;// ダイアログモーダルでユーザーがNoボタンを押下した時に実行する関数
}
//dialogOption はDialog使用時に表示設定に使用する要素で使用します。
export interface IDialogOption {
    yes: {
        isShow: boolean;//Yesボタンを表示するかどうか
        label: string;//Yesボタンのラベル
    };
    no: {
        isShow: boolean;//Noボタンを表示するかどうか
        label: string;//Noボタンのラベル
    };
    cancel: {
        isShow: boolean;//Cancelボタンを表示するかどうか
        label: string;//Cancelボタンのラベル
    }
    isRightBottonYes: boolean;//Yesボタンを右側に表示するかどうか
}
//dialogOption の初期値
export const InitDialogOption = (): IDialogOption => {
    return {
        yes: {
            isShow: true,
            label: "Yes",
        },
        no: {
            isShow: true,
            label: "No",
        },
        cancel: {
            isShow: true,
            label: "キャンセル",
        },
        isRightBottonYes: true,
    }
}

呼び出し元のコンポーネント

home.vue
<script lang="ts">

import { defineComponent, reactive } from "vue";
import VcDialog from "@/component/vue-dialog/vue-dialog.vue"
import { DialogData, Dialog, DialogResult, IDialogOption, InitDialogOption } from "@/component/vue-dialog/vue-dialog.ts"

export default defineComponent({
    components: {
        "vc-dialog": VcDialog,
    },
    setup() {
        const state = reactive  ({
            dialogData: new DialogData(2000),
        });
        ///...略
        return {
            state,
            ///...略
        }
    },
});
</script>
<template>
<vc-dialog :data="state.dialogData"></vc-dialog>
</template>

これに追加して同期的に呼び出してユーザー操作の結果を受け取る為に.....

vue-dialog.ts
export class Dialog {
    private DialogData: DialogData;
    constructor(dialogData: DialogData) {
        this.DialogData = dialogData;
    }

    public Show = (message: string, title: string, dialogOption: IDialogOption = InitDialogOption()) => {
        return new Promise<DialogResult>(async (resolve, reject) => {
            this.DialogData.title = title;
            this.DialogData.message = message;
            this.DialogData.dialogOption = dialogOption;
            if (this.DialogData.dialogOption.yes.isShow == false &&
                this.DialogData.dialogOption.no.isShow == false &&
                this.DialogData.dialogOption.cancel.isShow == false) {
                    this.DialogData.isShow = false;
                reject("必ず「Yes」「No」「Cancel」のうち最低一つは表示設定にしてください");
                return;
            }
            this.DialogData.yesClick = () => {
                this.DialogData.isShow = false;
                resolve(DialogResult.Yes);
            };
            this.DialogData.noClick = () => {
                this.DialogData.isShow = false;
                resolve(DialogResult.No);
            };
            this.DialogData.cancelClick = () => {
                this.DialogData.isShow = false;
                resolve(DialogResult.Cancel);
            };
            this.DialogData.isShow = true;
        });
    }
}

プロパティ用のデータにダイアログを表示しつつPromiseを返却する表示用の関数を含んだオブジェクトを用意
※ dialog.Show() 的な書き方がしたいから

使用する時は、初期化の時にダイアログのプロパティ用オブジェクトを指定しておいて

home.vue
    const dialog: Dialog = new Dialog(state.dialogData);

こんな感じで使う

home.vue
       const ret: DialogResult = await dialog.Show("たいとる", "めっせーじ");
            if (ret == DialogResult.Yes) {
                console.log("Yesが押されました")
            } else if (ret == DialogResult.No) {
                console.log("Noが押されました")
            } else if (ret == DialogResult.Cancel) {
                console.log("Cancelが押されました")
            }

という事で「vue.js コンポーネントでDialogを作ってみる」でした。(おしまい)


一応公式でもプロパティの型に「Function」と入っているので公式的にもOKなのかもしれません(自信ないけど)

興味がありましたらサンプルはこちら
https://github.com/zeronooekaki/vue3-dialog

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