豆包ai的输入框。在输入框中有其他输入框
使用vue简单实现了下。
<template>
<div class="page-container">
<div class="input" contenteditable="true" id="inner">
<template v-for="item in conArr" :key="item.id">
<span v-if="item.type === 'text'">{{ item.con }}</span>
<span
class="input-con"
contenteditable="false"
v-if="item.type === 'input'"
>
<span
:ref="(el) => { if (el) inputref.push(el as HTMLElement) }"
contenteditable="true"
class="my-input"
:data-id="item.id"
:style="{ position: item.isShowPla ? 'absolute' : 'relative' }"
>
{{ item.con }}
</span>
<span v-if="item.isShowPla" class="my-inputpla">{{
item.placeholder
}}</span>
</span>
</template>
</div>
<button @click="printData">打印数据</button>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
// 声明为数组引用
const inputref = ref<HTMLElement[]>([]);
const conArr = ref([
{ id: "1", type: "text", con: "我是一个" },
{
id: "2",
type: "input",
isShowPla: false,
con: "博主",
placeholder: "[输入职业]",
},
{ id: "3", type: "text", con: ",帮我写一篇关于" },
{
id: "4",
type: "input",
isShowPla: true,
con: "",
placeholder: "[输入主题]",
},
{ id: "5", type: "text", con: "的" },
{
id: "6",
type: "input",
isShowPla: true,
con: "",
placeholder: "[输入平台:如公众号、知乎、头条等]",
},
{ id: "7", type: "text", con: "文章,需要符合该平台写作风格。" },
]);
//添加监听事件
const handleObserver = (ele: HTMLElement) => {
const observer = new MutationObserver(function (mutations) {
mutations.forEach((mutation) => {
if (mutation.type === "childList" || mutation.type === "characterData") {
const id = ele.dataset.id;
const findItem = conArr.value.find((item) => item.id === id);
if (findItem) {
findItem.con = ele.textContent ?? "";
if (!findItem.con) {
findItem.isShowPla = true;
} else {
findItem.isShowPla = false;
}
}
}
});
});
// 开始观察内层元素及其子树的变化
observer.observe(ele, {
childList: true,
subtree: true,
characterData: true,
});
};
const printData = () => {
let str = "";
conArr.value.forEach((item) => {
str += item.con;
});
console.log(str);
};
onMounted(() => {
inputref.value.forEach((ele) => {
handleObserver(ele);
});
});
</script>
<style scoped>
.page-container {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
.input {
width: 500px;
height: 100px;
border: 1px solid #ccc;
border-radius: 5px;
margin: 0;
padding: 5px;
.input-con {
position: relative;
white-space: nowrap;
.my-input {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
border-radius: 5px;
padding: 0 5px;
background-color: rgba(0, 87, 255, 0.06);
color: rgb(0, 87, 255);
z-index: 1;
}
.my-inputpla {
color: rgba(0, 87, 255, 0.5);
background-color: rgba(0, 87, 255, 0.06);
border-radius: 5px;
padding: 0 5px;
z-index: -1;
}
}
}
}
</style>