出于友好性交互的考虑,在某些特定业务场景下,在table单元格上直接进行编辑,会有更好的用户体验感:
封装一个focusInput组件,支持input和textarea;
使用元组件component的原因是可继续扩展支持select组件,这里暂时先去掉了select;
<template>
<div class="focus-input" @click="onDivClick">
<template v-if="getStatus()">
<span v-if="!computedModelValue" class="focus-input__placeholder">
{{ placeholder }}
</span>
<template v-else>
<slot name="default" v-bind="currentOption">
<span v-html="computedModelValue"></span>
</slot>
</template>
</template>
<component
:is="inputType"
v-if="!getStatus()"
ref="inputRef"
v-bind="$attrs"
:type="isTextarea"
:disabled="disabled"
:autosize="isTextarea === 'textarea' ? true : false"
:model-value="modelValue"
:placeholder="placeholder"
@blur="onBlur"
>
</component>
</div>
</template>
根据点击事件,由focusing值来控制显隐,显示input及主动触发focus();
根据具体应用场景,通过disabled控制禁止编辑等;
<script setup>
import { computed, nextTick, ref } from 'vue'
const props = defineProps({
disabled: {
type: Boolean,
default: false
},
modelValue: {
type: [String, Number],
default: null
},
inputType: {
type: String,
default: 'el-input'
},
placeholder: {
type: String,
default: null
},
scoreInput: {
type: Boolean,
default: false
},
isTextarea: {
type: String,
default: null
}
})
const isInput = computed(() => props.inputType == 'el-input')
const computedModelValue = computed(() => {
if (isInput.value) {
if (props.isTextarea) {
return props.modelValue?.split('\n')?.join('<br/>')
}
return props.modelValue
}
return null
})
const inputRef = ref(null)
const focusing = ref(false)
const onDivClick = (event) => {
if (props.disabled) {
return
}
if (focusing.value) {
return
}
focusing.value = true
if (isInput.value) {
nextTick(() => {
inputRef.value.focus()
inputRef.value.handleFocus && inputRef.value.handleFocus(event)
})
}
}
const onBlur = () => {
if (isInput.value) {
focusing.value = false
return
}
}
const getStatus = () => {
if (props.scoreInput) {
return props.disabled
} else {
return !focusing.value
}
}
</script>
在table-column中使用:
<el-table-column
header-align="center"
align="center"
prop="indexScore"
label="分值"
width="150px"
class-name="content-full"
>
<template #default="{ row, $index }">
<el-form-item :prop="`indexDetail.${$index}.indexScore`">
<FocusInput
v-model="row.indexScore"
placeholder="分值"
:disabled="bzType === 'score' ? true : disabled"
>
</FocusInput>
</el-form-item>
</template>
</el-table-column>