はじめに
これはVue.jsに触り始めて間もない私が、自分で書いたコードを公式ドキュメントを参考に修正するといった内容になります。
そのため、私と同じようにVue.jsに触り始めた方の参考になれば幸いです。
具体的な内容
先日Vue.js+firebaseでSPAを作成したのですが、Vueを学び始めて数日だったので、ボタン制御の部分で誤った実装をしてしまっていました。
その時はこれでいいやで済ませたのですが、公式ガイドを読んでいる際に正しい実装方法が載っていたので、これをもとにコードを修正しようと思います。
動作のイメージ
今回の対象は入力フォームに何も入力されていなかった場合にボタンが非活性になるという単純なものです。
元のコード
<template>
<div class="create">
<div style="margin-right: 50px;text-align: right;">
<header>NumG</header>
<router-link to="/">Home</router-link>
</div>
<h1>Create</h1>
<div>
<p>
<br />伝えたい言葉を入力してください。
<br />※個人情報などは入力しないでください。
</p>
</div>
<div>
<form @submit="checkForm">
<textarea cols="30" rows="5" :value="message" @input="doUpdate">いつもありがとう!
これからもよろしくね!</textarea>
</form>
</div>
<div>
<router-link
id="confirmBtn"
to="/Confirm"
tag="button"
class="btn btn-outline-primary"
>Confirm</router-link>
</div>
</div>
</template>
<script>
export default {
name: "Create",
computed: {
message() {
return this.$store.getters.message;
}
},
watch: {
message: function() {
let el = document.getElementById("confirmBtn");
if (this.message.length) {
el.removeAttribute("disabled", "disabled");
} else {
el.setAttribute("disabled", "disabled");
}
}
},
methods: {
doUpdate(event) {
this.$store.dispatch("doUpdate", event.target.value);
},
checkForm() {
if (this.message) {
return true;
}
this.error = null;
if (!this.message) {
this.error = "伝えたい言葉を入力してください";
}
event.preventDefault();
}
}
};
</script>
元のコードではrouter-link
(送信ボタン)に属性disabled
をつけるためにwatch
を使い、message
(入力値)が変更になるたびに直接DOMの操作を行っていました。あまりVueっぽくない書き方だなぁと思いつつも他に書き方が分からず、時間もないためスルーしてしまいました。
ちなみにmethodsのcheckForm
は消し忘れた不要なコードです。。。
上記のwatchのおかげで入力値がない時はそもそもボタンが非活性となるため、ボタンが押せずイベントが発火しません。
ドキュメントの該当箇所
ドキュメントの該当箇所はテンプレート構文#属性の部分です。
<button v-bind:disabled="isButtonDisabled">Button</button>
isButtonDisabled
がnull
、undefined
、またはfalse
の値を持つ場合、disabled
属性は描画された<button>
要素に含められません。
つまり、v-bind
を使えばisButtonDisabled
の属性を自動で制御(付けたり外したり)できるということです。
修正したコード
<template>
<div class="create">
<div style="margin-right: 50px;text-align: right;">
<header>NumG</header>
<router-link to="/">Home</router-link>
</div>
<h1>Create</h1>
<div>
<p>
<br />伝えたい言葉を入力してください。
<br />※個人情報などは入力しないでください。
</p>
</div>
<div>
<form>
<textarea cols="30" rows="5" :value="message" @input="doUpdate"></textarea>
</form>
</div>
<div>
<router-link
to="/Confirm"
tag="button"
class="btn btn-outline-primary"
:disabled="isButtonDisabled"
>Confirm</router-link>
</div>
</div>
</template>
<script>
export default {
name: "Create",
computed: {
message() {
return this.$store.getters.message;
},
isButtonDisabled() {
return this.$store.getters.message.length <= 0;
}
},
methods: {
doUpdate(event) {
this.$store.dispatch("doUpdate", event.target.value);
}
}
};
</script>
以下のように修正しました。
①computed
にボタンの押下可否を判定するための算出プロパティisButtonDisabled()
を追加
※入力値の文字数が0以下の場合にtrue(押下不可)を返すようになっています。
②router-link
に:disabled="isButtonDisabled"
を追加
※念のため補足ですが:
はv-bind:
を省略した記法です。
②不要になったwatch
の削除
④その他の不要庵部分の削除(form
の@submit="checkForm"
、textareaの無駄な例
、router-link
の使わなくなったid
、methods
のcheckForm()
)
修正前と比較すると**`script`タグの中がかなりすっきりしたてVueっぽくなったと思います!** 特にDOMの要素を直接操作する処理が消えたのが大きいかなと思います。 ※動作自体は修正前と変わらないので割愛します。
まとめ
公式のドキュメントはちゃんと目を通した方がいいことが分かったので、時間を作って一通り目を通したいと思います。
もっといい書き方があればコメントいただければ幸いです。