本章主要详细介绍实现特定文本内容高亮和滚动同步的功能。
废物不多说,先直接上效果
实现思路
1. 布局和样式
- 使用 Ant Design Vue 的
<a-row>和<a-col>组件来创建响应式布局。 <div class="container">是主容器,设置了固定的宽度和高度。<div class="text-div">用于显示处理后的文本(高亮显示的文本)。<div class="text-wrap">包含一个<a-textarea>,用于用户输入文本。
2. 文本处理
-
用户在
<a-textarea>中输入文本,这部分文本通过 Vue 的v-model双向绑定到inputText变量。 -
当用户输入文本时,触发
handleChange方法。这个方法将inputText中的文本按行分割,并检查每一行是否包含数字“8”。- 如果一行包含“8”,则该行被包裹在一个带有
vin-matching-error类的<span>标签中,这个类定义了高亮样式(红色字体)。 - 如果一行不包含“8”,则保持原样。
- 空行被替换为包含空格的
<span>,以保持格式。
- 如果一行包含“8”,则该行被包裹在一个带有
-
处理后的文本(可能包含高亮的行)被赋值给
inputText2,并通过v-html在<div class="text-div">中显示。
3. 滚动同步
- 当用户在
<a-textarea>中滚动时,触发handleScroll方法。 handleScroll方法获取<a-textarea>的滚动位置,并将这个滚动位置应用到<div id="myText">上,从而实现两个区域的滚动同步。
4. Vue 生命周期和 DOM 引用
- 使用
onMounted钩子函数来获取对myText(显示处理后文本的<div>)的引用。这是通过document.getElementById实现的。 - 这个引用在
handleScroll方法中用于同步滚动位置。
5. CSS 样式
.container和其他类用于设置布局和基本样式。:deep(.vin-matching-error)用于定义高亮样式。:deep()是一个 Vue 特有的选择器,用于穿透scoped样式的边界,使得定义在组件内部的样式可以应用到动态生成的 HTML 内容上。
Let's show you the code!
<template>
<div style="padding: 50px">
<a-row>
<a-col :span="8">
<div class="container">
<div id="myText" class="text-div" v-html="inputText2"></div>
<div class="text-wrap">
<a-textarea
v-model:value="inputText"
placeholder="请输入批量车架号"
class="textarea"
@scroll="handleScroll"
@input="handleChange"
@change="handleChange"
/>
</div>
</div>
</a-col>
</a-row>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
const inputText = ref("");
const inputText2 = ref("");
const myText = ref(null);
const handleChange = () => {
inputText2.value = inputText.value
.split("\n")
.map((item) =>
item.includes("8")
? `<span class="vin-matching-error">${item}</span>`
: item || "<span> </span>"
)
.join("\n");
};
onMounted(() => {
myText.value = document.getElementById("myText");
});
const handleScroll = (event) => {
if (myText.value) {
myText.value.scrollTop = event.target.scrollTop;
}
};
</script>
<style scoped>
.container {
width: 400px;
height: 500px;
position: relative;
:deep(.vin-matching-error) {
color: #ff4d4f;
position: relative;
z-index: 10000;
word-break: break-all;
font-size: 14px;
line-height: 1.5715;
}
}
.text-div {
width: 100%;
height: 100%;
margin: 0;
padding: 4px 11px;
white-space: pre-wrap;
color: rgba(0, 0, 0, 0.85);
font-size: 14px;
line-height: 1.5715;
vertical-align: bottom;
transition: all 0.3s, height 0s;
border: 1px solid #fff;
border-radius: 2px;
overflow: auto;
text-align: left;
}
.text-wrap {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
position: absolute;
z-index: 1;
top: 0;
left: 0;
}
.textarea {
height: 500px;
resize: none;
}
.error {
color: #ff4d4f;
position: relative;
z-index: 10000;
}
</style>