この記事はVue.js #1 Advent Calendar 2017の16日目の記事です。
もともとは「Vuetifyを使って爆速でマテリアルデザインのコンポーネントをつくる」という記事をあげる予定でしたが、間に合わなかったので過去に社内Qiitaに載せたものを紹介します。(Vuetifyに関する記事はいずれ書きます)
はじめに
基本的にHTMLのテキストフィールドは固定長で作られますが、
現在取り組んでいるプロジェクトで可変長のテキストフィールドが必要になり、探してみても意外となかったのでつくってみました。
設計方針
設計というほど大げさなものではないですが、基本的なアイディアはこんな感じ。
-
visibility: hiddenにしたspanを用意 - 可変のテキストフィールドと同じスタイルを適用
- テキストフィールドの文字を
spanのテキストと同期させて長さを得る - 長さをテキストフィールドに反映
はじめは入力されているテキストの文字数をカウントして長さを変えようかと思いましたが、
全角半角がまざると面倒なので却下しました。
実装
Vue.jsを使った実装の上でのポイントはこんな感じ。
-
v-modelを使ってもinput文字のバインドはできるが、全角入力中の文字がとれないので@inputを使って入力イベントをフックする -
spanはposition: absolute (or fixed)にしないとclientWidthが0になる -
spanにwhite-space: nowrapをつけないとspanが改行してしまい、正常な幅がとれない -
vm.$nextTickを使わないとdomの更新前に幅の計算が走ってしまう - 入力しやすいように少し幅を大きく取る(今回は
+10px)
コード
pugとsassを使っています。
# flexible-input
input(
type="text"
v-bind:value="text"
v-bind:style="style"
@input="input"
)
span(ref="hidden") {{text}}
new Vue({
el: '#flexible-input',
data() {
return {
text: "初期値",
style: "",
}
},
mounted() {
this.updateStyle()
},
methods: {
updateStyle() {
this.style = `width: ${this.$refs.hidden.clientWidth + 10}px;`
},
input(e) {
this.text = e.target.value
this.$nextTick(() => this.updateStyle())
}
}
})
input
border: 1px solid lightgrey
min-width: 100px
span
visibility: hidden
position: fixed
white-space: nowrap
デモ
GIF
テキストの変化が分かるようにspanを表示させています。
Codepen
See the Pen Flexible Input by totto357 (@totto357) on CodePen.
まとめ
今回はVue.jsで可変長のテキストフィールドを作成しました。
必要な機能を追加してこのコンポーネントをnpmパッケージとして公開できるようにしたいですね。
17日目は @SatohJohn さんのVue-Routerのナビゲーションガードを使ってみるです!
