経緯
Vue.jsの「v-model」では日本語入力中(未確定状態)ではdataを書き換えてくれない。
日本語入力途中でのサジェスト表示実装などで必要となりましたので、カスタムディレクティブ化しました。
v-modelだとどうなる?
<div id="app1">
<h2>v-model使用</h2>
<p>{{ text }}</p>
<input type="text" v-model="text">
<p>日本語入力が確定するまでdataに反映されない。</p>
</div>
// v-modelで実装
const app1 = new Vue({
el: '#app1',
data: {
text: ''
}
});
See the Pen Vue.js 日本語入力 v-model by Rikuto Yamaguchi (@RikutoYamaguchi) on CodePen.
eventListenerで実装
keyup
とcompositionend
で更新することで、候補選択時などもdataを書き換えることができます。
<div id="app2">
<h2>eventListenerで実装</h2>
<p>{{ text }}</p>
<input type="text" ref="input" :value="text">
<p>日本語入力中でもdataへ反映されるがVueへmethodsなど結構記述増える</p>
</div>
// eventListenerで実装
const app2 = new Vue({
el: '#app2',
data: {
text: ''
},
methods: {
update (e) {
this.text = e.target.value;
}
},
mounted () {
this.$nextTick(() => {
const $input = this.$refs.input;
$input.addEventListener('keyup', this.update);
$input.addEventListener('compositionend', this.update);
});
}
});
See the Pen Vue.js 日本語入力 eventListener by Rikuto Yamaguchi (@RikutoYamaguchi) on CodePen.
これをカスタムディレクティブにすると。
カスタムディレクティブで実装
<div id="app3">
<h2>カスタムディレクティブで実装</h2>
<p>{{ text }}</p>
<input type="text" v-composition-model="text">
</div>
function vCompositionModelUpdate (el, { value, expression }, vnode) {
// data書き換え
vnode.context[expression] = el.value
}
Vue.directive('composition-model', {
bind: function (el, binding, vnode) {
el.value = binding.value
el.addEventListener('keyup', () => vCompositionModelUpdate(el, binding, vnode))
el.addEventListener('compositionend', () => vCompositionModelUpdate(el, binding, vnode))
},
// dataが直接書き換わったときの対応
update: function (el, { value }) {
el.value = value
}
})
const app3 = new Vue({
el: '#app3',
data: {
text: ''
}
});
See the Pen Vue.js 日本語入力 カスタムディレクティブ by Rikuto Yamaguchi (@RikutoYamaguchi) on CodePen.