この記事は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のナビゲーションガードを使ってみるです!