99 lines
2.0 KiB
Vue
99 lines
2.0 KiB
Vue
<template>
|
|
<!-- 文字节点 -->
|
|
<div class="text" @mousedown="onMouseDown">
|
|
<div
|
|
tabindex="0"
|
|
class="input"
|
|
ref="inputRef"
|
|
:contenteditable="active"
|
|
@input="onInput"
|
|
@blur="onBlur"
|
|
@paste.prevent
|
|
@keydown.stop
|
|
></div>
|
|
<span class="delete" @mousedown.stop @click="emit('delete-node')" v-show="active">
|
|
<svg-icon name="close" size="7" size-unit="px" />
|
|
</span>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { reactive, ref, onMounted, nextTick, watch } from 'vue'
|
|
const props = defineProps({
|
|
active: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
data: {
|
|
type: Object,
|
|
default: () => ({})
|
|
}
|
|
})
|
|
const emit = defineEmits(['update-data', 'delete-node'])
|
|
const data = reactive({
|
|
text: props.data?.text || '点击编辑文本'
|
|
})
|
|
const time = ref(null)
|
|
const inputRef = ref<any>()
|
|
const onInput = () => {
|
|
const text = inputRef.value.innerHTML
|
|
data.text = text
|
|
}
|
|
// watch(
|
|
// () => props.active,
|
|
// (newVal) => {
|
|
// if (!newVal) return
|
|
// nextTick(() => {
|
|
// // 光标定位到文本末尾
|
|
// const range = document.createRange()
|
|
// const selection = window.getSelection()
|
|
// range.selectNodeContents(inputRef.value)
|
|
// range.collapse(false)
|
|
// selection.removeAllRanges()
|
|
// selection.addRange(range)
|
|
// })
|
|
// }
|
|
// )
|
|
const onMouseDown = (e: MouseEvent) => {
|
|
if (props.active) e.stopPropagation()
|
|
}
|
|
const onBlur = () => {
|
|
// emit('update-data', data)
|
|
}
|
|
onMounted(() => {
|
|
inputRef.value.innerHTML = data.text
|
|
emit('update-data', data)
|
|
})
|
|
defineExpose({ data })
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.text {
|
|
user-select: none;
|
|
border: 1px solid transparent;
|
|
padding: 2px;
|
|
position: relative;
|
|
&.active {
|
|
border-color: #000;
|
|
> .input {
|
|
cursor: text;
|
|
}
|
|
}
|
|
> .input {
|
|
outline: none;
|
|
min-width: 2px;
|
|
font-size: 16px;
|
|
}
|
|
> .delete {
|
|
position: absolute;
|
|
top: 4px;
|
|
right: 4px;
|
|
transform: translate(100%, -100%);
|
|
background-color: #fff;
|
|
padding: 2px;
|
|
border-radius: 50%;
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
</style>
|