Vue.jsでinput/textarea要素といえばv-model。
v-modelで指定されたデータは双方向バインディングされ,ユーザーが入力した文字がデータへ即反映され,逆に,データが変更されたらinput/textarea要素の表示に即反映される。
contenteditable属性をtrueに設定したHTML要素でもこれと同じ動きをするものが作れる。
以下,つくってみたものを紹介する。
contenteditableな要素でつくったinput要素っぽいコンポーネント
<template>
<div
contenteditable="true"
v-text="text"
v-on:input="OnUpdate"
v-on:focus="OnFocus"
v-on:blur="OnBlur"
></div>
</template>
<script>
export default {
name: "Editable",
props: {
value: {
type: String,
required: true
},
},
data() {
return {
focusIn: false,
text: ""
};
},
mounted() {
this.text = this.value;
},
methods: {
input(str) {
this.$emit("input", str);
},
OnUpdate(event) {
const target = event.target;
this.input(target.innerText);
},
OnFocus() {
this.focusIn = true;
},
OnBlur() {
this.focusIn = false;
}
},
watch: {
value() {
if (this.focusIn) return;
this.text = this.value;
}
}
};
</script>
つくったコンポーネントの使い方
<template>
<editable
v-bind:value="editableData"
v-on:input="OnStringUpdated"
></editable>
</template>
<script>
import Editable from "./Editable.vue";
export default {
name: "MyComponent",
data() {
return {
editableData: ""
};
},
methods: {
OnStringUpdated(newString) {
this.editableData = newString;
}
},
components: {
Editable
}
};
</script>