- 普段はテキストだけどダブルクリックするとテキストボックスになるよ
- Enterかフォーカスアウトで確定されるよ
- 渡した値はリアクティブに変更されるよ
- 大丈夫!リバートもできるよ
- 値が変更された時は一応通知が行くよ
- 値が空になった時はプレースホルダが表示されるよ
- リバートボタンとプレースホルダは
<tamplate>でカスタマイズできるよ
そのうちnpm化してちゃんとドキュメント書きます
<template>
<span>
<!-- bootstrap-vue 使ってたからこれになってるけど普通のinputに差し替えてもいいよ -->
<b-form-input
v-if="isEditable"
ref="content-input"
:value="value"
size="sm"
class="box"
type="text"
:style="inputWidth"
@keypress.enter.native="editableOff"
@blur="editableOff"
@input="$emit('input', $event)"
/>
<span
v-else
ref="plain-text"
class="box"
@dblclick="editableOn()"
>
<span
v-if="value"
>
{{ value }}
</span>
<slot
v-else
name="placeholder"
>
:none:
</slot>
</span>
<span
v-if="isEdited()"
@dblclick="revertValue()"
>
<slot
name="revert"
>
:rev:
</slot>
</span>
</span>
</template>
<script>
export default {
props: {
value: {
type: String,
require: true,
default: ''
},
identify: {
type: Object,
require: false,
default: () => {}
}
},
data () {
return {
isEditable: false,
originText: '',
textWidth: null,
inputWidth: {
'min-width': ''
}
}
},
mounted () {
this.originText = this.value
},
methods: {
editableOn () {
this.textWidth = this.$refs['plain-text'].clientWidth
this.isEditable = true
this.$nextTick(() => {
// table の中とかにあると input になった時に縮んじゃう事があるから元のテキストのサイズに合わせるようにしている
this.inputWidth['min-width'] = (this.textWidth * 1.1) + 'px'
this.$refs['content-input'].select()
})
},
editableOff () {
// Enterした時にフォーカスアウトで2回ここに来るからガードつけておく
if (!this.isEditable) {
return
}
this.isEditable = false
if (this.isEdited()) {
this.$emit('editedValue', this.identify, this.value, this.originText)
}
},
isEdited () {
return this.value !== this.originText
},
revertValue () {
this.$emit('input', this.originText)
this.$emit('revert')
this.isEditable = false
}
}
}
</script>
<style>
</style>