How to
Vueで文字数制限するdirectiveを実装する方法と注意点
vueでinputの文字数を制限する機能を実装する機会がありました。
directiveにして共通化しようと実装してみると、Vueの仕組みをちゃんと考慮しておかないとハマってしまう現象に出会ってしまいました。
ちゃんと実装できてからは考えてみれば当然と思えても、実装している最中は時間をとられてしまいました・・。
それではまず最初に実装したコードから紹介します。
最初書いていたコード
シンプルにdirectiveで設定された数値の文字数で切り取って、値をセットしています。
一見これでうまく動きそうですが、特定の条件化では想定しない挙動になってしまいます。
1 2 3 4 5 6 7 8 9 10
Vue.directive('sample', { bind: function(el: Element, binding: any, vnode: any) { el.addEventListener('input', (e: any) => { e.target.value = e.target.value.substr(0, binding.value); }); } }); // HTML <input type="text" v-sample="10" />
v-modelが設定済みかつコピー&ペーストした時
上記のコードはv-modelが設定されていなかったり、コピー&ペーストに対応する必要がなければ問題なく動作します。
ですがv-modelを設定してコピー&ペーストに対応した時に限り上記のコードではうまく動きません。
コピー&ペーストで上限以上の文字を入力した時に瞬間的には正常に動いているように見えますが、他の要素の値が変更されるなど再描画が起こったときに問題が生じます。
再描画で制限文字数を超えて値が入力される
再描画時に入力制限したはずのinputに、文字数を超えて最後にコピー&ペーストした内容が値に設定されてしまいます。
この現象が起こる原因は、v-modelには下記の加工した値が設定されていないからです。