最近工作中遇到这样一个需求对富文本内容进行翻译成英语,放到另一个富文本中。然而,当富文本中的内容非常多时,翻译速度会变得很慢,甚至接口可能报错。为了解决这个问题,我们可以遍历富文本中的所有节点,将每个节点的内容提取为字符串数组,翻译完成后再替换回去。
模拟两个富文本编辑器的翻译效果:
下面是对应源代码:
<body>
<div id="chinese">
<div class="document">
<div class="section">
<p>
窗前明月光,疑是<strong>地上</strong>霜;<br />举头望<span
style="color: rgb(45, 194, 107)"
data-mce-style="color: #2dc26b;"
>明月</span
>,<span
style="
text-decoration: underline;
background-color: rgb(224, 62, 45);
"
data-mce-style="text-decoration: underline; background-color: #e03e2d;"
>低头</span
>思故乡;
</p>
<p>
<img
src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBwgHBgkIBwgKCgkLDRYPDQwMDRsUFRAWIB0iIiAdHx8kKDQsJCYxJx8fLT0tMTU3Ojo6Iys/RD84QzQ5OjcBCgoKDQwNGg8PGjclHyU3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3N//AABEIAMAAzAMBIgACEQEDEQH/xAAcAAACAwEBAQEAAAAAAAAAAAADBAIFBgEHAAj/xABBEAABAwMDAgQCBgcHAwUAAAABAAIDBBEhBRIxQVEGEyJxYYEUIzJSobEHFTNCkdHhJFNicoLw8ZKywUNEY3OD/8QAGAEAAwEBAAAAAAAAAAAAAAAAAAECAwT/xAAfEQEBAQADAQACAwAAAAAAAAAAARECEiExA2ETQVH/2gAMAwEAAhEDEQA/AM7O3ZLI37riP4FCKsNbj8nV6xn/AMzvzukCuN1YgVG9l1yGTlA1GsP1N1UGe17Xx0V9HSy1jhHCwuceAth4T/R8x8Zm1KNwd783RIVrzPT2PfFJII3bN+Mcozt8Z2va4EdwfkvfYfDWnUsbWtp2EBu3jn3S9d4Y0yqZtkpmkZHHAOVRPz7qINREwNDvtHgdlXiJ33l7jXfo8oZoyyN2wBpDbcAnqe/VYfxP4KqqBzTTsBiaDuePwuqhMXAJI5Q5pHCeY+pnIZCNzjjAKCad8Uwie3a/qvSvA3hAzGOpqMt5SNk9O8E6pqj27gLW5c24Wt0z9E0ZgIrpLPvgs7L1alpYaWIBjbYsiE/wRqY8vg/RjBB50QkuHD0vI9QFxj8Fl/GvhAaXE2ShiOwYc4OIXuTuVS6zQCrgkjLb3aUaePzwIJmGxbKD23lEAmGAZh/rK0niPRnabVEEDbzvv/vqqcEnNkzLNdUf3lR/1ognqv72oTAKkHJAt9Lq+ksw92KX0+saMzO+caYDlIH4IAX6yqsfXN+cS7+t6gY3wn/SUYKW0HkA+6DA/XNQ3kQn5kKbdbmtlkP/AFFE8th/cahviivmNh/ggY1vi+PZr1Rb94Nd+CpVovHDNuqtkAw9gys4VBhuQzckAWz3U38KdFGJauNhzc8WvdOQno/gLw+Im/SZw17TYgWvZb8BrGWGAqnQIRTUELGcbVYPfmx4Twn0rgG8pXzBe10GrcXzsj3EAnNlySgp3EFu9hHZ5U/GnHho+5vJQJoWzN2vaHNPIIBUjC6IWF3NPW67csFxkKpU8uFjz3xJ4IdV6m2emDWwg5G29/8AnhegaLQtotPghjv6G2IRWhpIdbB5BRS/YC1vX8E9RUaupbG31H5KsbqU0z/7PTSvaMlzRhQrLz1EUIdl547j4qyh2R7Y4wGtGAO6mt/x8JnrsEpkALgWn7pGQg1EjTcHj4JkvZ5jdw5Nrj2Kr6lgjuQDcolTzkjC+O6WIw/SC0Egbb2vb42XndwvYq1jZLeeN9zhtrhB/Venn/2NPf8A+sKmbyUKd16sNG0xx9VBTm/+AKOsfo/0+viEunO+hz2vt5YT7dPkjA8sBF7XUgrHWdB1HRZNlfTOY0n0yNyx/sVXhuOEYb4KQIXwsF0e1kB9dRA7hSIXQEG3XjyMWppPdpWPPXPC9D8U6fNqFFE2ANuHg3cbABVNHpdLQgPH10/SRw9Lf8o/8qAoqPRaipaJJvqIjkF49Th3A7fFXFHp9Lp7g6BhdJ1kfz/RKy6zKPEbNNkjuyaEyNkLsl3X8lZO5T+E2eg6g2eBrbncOisy+5N1g9JqjTTixIBK2ULyYg5xT0Y7Ui+2QfaCL5m8bgoGzrBfOjc07o+OCO6mtvx8p8E80jHK47LUIHdxyjxRuPISXzzAWPIOeF89xPCYEN8r7yGkKvXMqKdxdqj3Y2tZjGf95T0PJJOEdtGxpLgPUQu+QBcBDafk44BCTLUk9G/y/qUGvcWgkYHdWETGxRuDeb8qt1SGpnbsiwD1RIz58pyqjlf5kzT2RgFJtDJAPUCT3K+d6bFxAVITjF3NHxV7Cfq2/BUVPJG6ZrQ9t/dX1OLsFkwK6nhqYjDUxMmifhzHi4Kwfif9G4u+q0B1jyaZ7v8AtK9BZ6V0vTJ+d6mlqaWd8FTC+KZn2mPFiPkhjcOV7zrmh6frcAjroQXt+xK3DmH4FeWeJPB9fo152A1NH/esGW/5h090lM1crocu4vZfWCQenVM8lQbzG4HAGAEm8AYTBQJFmbJ+Jh9G1vRtQGGicxPcOx4WidyVyrpoalgZPE2RocHAOF8jhTsFVuwSegklpBGD0Kt9P1h0TRHM4lqqnlBs4vAYCXHiynTb2jnEoBDr34VrA097hZjwvT1pLS8kROzxythHCGAd00WoCFgNwMlTtbhEXxCBeWoOA7KJblSJXDhVEuKDwF857QOUB0ot80BIuXC/0m5QXPBF7oRlNiAQmEpHNcLFI1MUTgbsBB6oj3Ek5QHONje1igeqt+lQGp37Sc3GbfkrqhqpKUNZPd8JwJTks9/5pISEEjoOFZ0m17OMdkKWQdcXHBGCuKrmnn0992sdNS82HLPZPUtXDVxCSneHjqOCPcdEwNfIvbnqs1oXiGbVfEeuac6OM09FK2Jkg5d6RuBHHN1peMnA+PC8+/RKH1TNb1NzQG1WoSPaerrkk3/iE88L+zPifwFDVh9XomynqOsDv2b/AG+6fw9l5pWU9RRVD6esjdFMzDmPFiF+hW9uijLR0s7t9RTQyvAtufGCbJGwpQJBlMkDul5CCcLG1pgD8IZOESX7JS7nWQHDl4AF7rVeHNBD9s8+4HmxCq/DdIKqtG4jDr2I6L0SCEMaABYdFUiOVShiZDGBG3bYdl84oxw2xQH8KkuNcOqjJIAhveGJKqqNjL4UjDDpiAb2S7qsN65VRUag0Hm3uVV1OtxtJHJ/JM8aJ9Xe5OEB9ULYssY/XZ62by4GEeqzTa101NJWthBYwOeel0aOrTSVQvYOugCoGQT+Kzolr32e8NG0XIQ/ptQwAlvrJ47+yejq1Alxj8VF5JZkqppNQ3svIAD3umzKZCC0/JEosSkJb8U7pdUWu2OCULbgWBUYSWTNN8plGlweQEq+hYZvNgvDL95mP+URj7gX7IocCLINGOV+4sqmMBONw+y7+RQ9F0ij0WhbRadF5cAcXWHcpgW22sCOxXI3+TYG/l8WP7qYNNCldcFrKLjlBPPyVAopCG/hc7YCTgpMnB/mmpeCknkb8pwmz8ERXZJIWNDvvdVsQ7AWd8HhjdJBZyT6vdXjXZWs+Mr9Gc64QJn7RdTe+zUhUS2DiiiBVNSLO9lmtX1LY21yX9ACua9qjowYoWF0pwB2SOn6U+Ytnqy7eM36fmo1pOJSopJpnRulkkNz6gFYUmlMhaNou05JOSVblkLY8Fp9lKaSJsDXXthK08ZuWgFNUsc21rg2HJF7FWscI8y2CGt5Qq+Zpt6btIJuoCuja8PaeRwkY9FSOma+Rxu0nr0+H4JeWgyS1hLz+CsaadkUVjgHKSrdfporsbI1zuzBlWnSroC1uwhosbm5tZSppZGuzYjv3UYdRbWNd5EbB8XD+qOwEEEOv3FkoKaZI45wuuGQVyMAn0WupvarRnqwp5SYxclMseqiOfabJ6CW6YWLDcKfI7oETsJhqAEar6IQ2f8AZcB9vsnsfgjh28BwIIPBCi+NsrS1wuDyLJdunMbcQTzRNOdjH4CAyRQJeCjXQJSsGhaQ8pCU+pOzHlV059SqG9F8HucdHYHNDQDjN7q+abLN+DZGu0sBpbcHNloN2FbJKV3pVXWuDWudc3ATsj+yrNQkIY87b2FkqcZh9fR09Q+Wpcd9/wB42+SyXibx3UzSGm0ktjYMGQtufYLQVWktq9RaKj7Ls2JWL8ReHH0VZPCyIg798QtbcPh39korlchafX9Xo6k/R9YNUWWO4NIjfgEixF/gvTfDlY3xNobKkAMl4kjHDXD/AMLyKkoZqipZCI5AQRf0leveCtOn0wPkMWyOQ5aRb5p7/qZfRJaGV0LRILOafUoU+n7pAZCLdLhaWTy5GPbMQwclxxdUOo1FJTuYyKqje0uts3C9/glJ60y2bjF+K4/EWp647TtDY76OxoDnCQMG7tcpGn/Rjrs5H6zr6enjJ3G0rpHfG2LL1rTaWGNvmmMBzzuJHKbqQ1+SAO1zwtLcnjP6xlNpkGk0ENBQtc5jR6nkZv8AwTjIyANzLfNXTo2AG/5paVoP7oys9WQZLscRjnFuSmg4uZnCW3B1QGYCdmaGsFkamkZXWkT1HLewVdVECVHpX5CtK+hdxdORm4VZC+9k/E7CYMLt7KIOF9dAYQlCeiFBesGpWfqq2o+181YzKtquqcDV+AqpgEkNwCT/ABW0v0XkfhmsFJrcRIBDrj1HA+K9ajO5rXXxbBVs6FM48dEnJEZBZxNr3TcpFylnvLeOEHFHqWnPnnAaPY9kf9WOlgbDUNjna03Albe3sVY+aOS6xHRQNU2+29h1UL8Q07S6OmkLmUsYeD9rJP4lX7Y2GENIGeR8FSU7/NPpc4Rt7Z3JmSvY21n2bxjP4q5+2d/Sr8SaHV1Za7T6yOMt/dcwuuO3Ky+meH3atqm6sqJY4acndEx23cb9TytVXaqPJkDCG9N3ZZOk1NzdQkeC7y3O5HIKrxtx53rY3YfBTQNjjDWNaLDPRLOmklzG5jx90OFyq2TVY7BsZjvbm1yVxknmm72MdjjbY/IhFrHDDppHP2uJYfulClkEQ3P3/C2br6WdoaNz5A1vQ5sq93mzSXjI29wMqKqDwOc+W5YYwerhlO7i/wDe9KWhjP3ijTOEcJJwEoKrqt488hGpn5Cr3Sb5C7umIHWstIhfU78BWMLsBUNPPawyrWB97ZTC0acLqDEbhdc+xQGHOEJ5RHFCdlc7YtLwSq2qGCrOThV1SMFMKaSR0czXMsCDfK9e8P14rdNjduu7aCbCy8hmY0zNv95bjQat1EIxf6s9lcRY2jiHdUrU+j4rvnB7d7T6fyS88oe5vYIIpMZQ/cDa3DW8lKGqmdNtdG1jRy48fPuroNbIw2t7pWSnaXOI4b+aVPUBWNjhLHn6tgyBgvPYnsq2oq3yC+STye3wATtRTWjDbX5N/ilHxEewRoiv+hPmJdI92w9AeU3BRRRbfQBjiyIDYi7RYIzpmEXPKc5GG+CIXAYB8kLcY8A3A6HsuVNYA36sXcUtFHNOQ54KVoGMspcCPUCfT7J6mhDxfh3UBRpqXbyP6KwYwMFwgnGRbRkKp1ma48tp225VrUTbIrXyVn9QjJjdK0lxByf5pygqwpuJ3CRjcLA8X6JmIhaJWUR+Ks6N+LcqmicrGkfZyCXsT7C66Tc3SrJLkN6IwQGOcEIorkIrnbgyJCqFwbJ+TqkKkXCAqYhvrGjsVq6KMyBgOPdUGmROdUucCAPZaahcze0WJNupwrTjQxtPkDb6gBkBAuH3DfknqVwdCLFpxxZAqKMu9UZsR0S0YGwvaA3jupsnaIy05A/E9Es4vhYQ8ZPXsoslY0AE5GSjSwzK4PeAOBwoviDmlLNla5wIcp+cLn1I2HgMkNil5I8FNukaeDlCc4FSMI0tG+araOgyVoIqRrG8JGhcW1HoGSFcSkMbY82VQAFjWoEsoYOVGaW92jHxSpa7qbpaMclJc7fyDmyXqhthe5gzt/imQCBZRey8L29bJT6eeM+xzJOBsfbI5BRY7t6pN9xIQeb5R4n45W0ZLCIqwpnAHKq4XXsmWSgSNaE6F9TOu4JvcAkaQ8XTLiScINlHobsIjyhE4WDUF5SVQfSbJuTlK1gBYQeoQCmlzsMm0HdnJC0mnta6Rp29P98rO6QwMNmgXutJpxaJWm1z3uqlKtZp1gwXTMjGWsMJGgf0L+T2TpFs3uiwQF9HG8erN+6RqNKBJMasZJNouhNkL4i4dThLDUz9PkhNhlCdTSNNloXsc2JxPqeRgoEVKRHaTkm6MJS/R3taTZdZA94CuXU7Cdp4XRC2N4F7DujBqtpWOin46WRqmZ0o9OLYwmZYBgsN3bkIwvAJLboykSv3GVzcF117m4so2vlI4+K679m8r62EKpd5dM93+FOHWZqCDM5wBFyusKC83cXDgnp3RIzhaSssOMfsZdTpHF8oJN/dIl+5P6aLvajRjSUvA9lb08F4ge6rdNiMkjGjvcq4fJZxDPsq4Kwj43Dlrh8kq42cb491oxrNez/19/wkaCvnaxNJ+1pqR3vCFHResy5KVQ+rd8eq1pq4X/tNPo3f/nb8kN/6tkBEulQ/6HuCn+Ojsx1FYCzchX0EmwMITzKXRRf+wSs/yTlTbFowP7Krb/rBT6UdobppSNrhn4K6hkEjQeAqKCXS43XLqo9gbJpmo6a3PnVA+BYEXjRKcqHGS7WfZBsT8UyzayNrGi22yrZNU0xzR/aXjqAYuFGTWtLYwD6WRc2xEeUutHaLR77HK4+aN9m8fEqnj17SZJLNrX3/AMcJsnGV+myDGo0/zJCMo2DuDTcXxbohkG7fUS0L68MgPk1dKe1pQvhDMWgB0LvaVv8ANFlBc1Jhky27SVOSoMnFgCpyUlQ9pBgefiBf8kq6nqIvtQyAdy0hT6PEJRbkoQCKQXcr7Z0CDCsqXX6vywIGOIvyeVdzSNhjLn2+axGp1H0qtfI27T27pyYLXWut6hypF2MdUu0m3wRWFUkWMXwrrS2WLVUwAlw91odPiAaD3TgXmmHZud2CvIIQIxuGUjpFICwPeMc2+KtCc4VxD//Z"
width="69"
height="89"
/>
</p>
</div>
</div>
</div>
<div id="translateButton"><button>Translate</button></div>
<div id="english"></div>
</body>
<style>
#chinese {
width: 500px;
height: 300px;
background: pink;
margin: 0 auto;
}
#english {
width: 500px;
height: 300px;
background: yellow;
margin: 0 auto;
}
#translateButton {
margin: 0 auto;
width: 200px;
text-align: center;
}
</style>
以看到,粉色的富文本中包含一张体积较大的base64图片。如果直接将其与其他内容一同发送给后端,传输的数据量会大幅增加,从而导致接口响应变慢,甚至可能报错。
function extractText(node, textArray = []) {
if (node.nodeType === Node.TEXT_NODE) {
const trimmedText = node.textContent.trim()
if (trimmedText) {
textArray.push({ node, text: trimmedText })
}
} else if (node.nodeType === Node.ELEMENT_NODE) {
node.childNodes.forEach((child) => {
extractText(child, textArray)
})
}
console.log(textArray)
return textArray
}
因此,我们可以传入富文本中的整个 DOM 节点,然后通过判断 node.nodeType
是否为 Node.TEXT_NODE
或 Node.ELEMENT_NODE
来确定每个节点是文本节点还是元素节点。对于文本节点,可以通过 node.textContent
提取其中的文本内容。
Node.ELEMENT_NODE
(值为1
): 表示元素节点,例如<div>
、<p>
等。Node.TEXT_NODE
(值为3
): 表示文本节点,即元素或属性中的文本内容。如果节点是文本节点
这样就将文本节点提取到一个数组中:
接下来我模拟一个翻译好的对应数组
// 模拟翻译内容数组
const translations = [
'The bright moonlight before my bed, I suspect',
'on the ground',
'is frost;',
'I raise my head to gaze at',
'the bright moon',
',',
'Lower your head',
'thinking of hometown;'
]
拿到翻译好的内容后,再写一个替换函数,按顺序替换掉将提取出来的文本节点
function replaceText(textArray, translations) {
textArray.forEach((item, index) => {
item.node.textContent = translations[index] || item.text
})
}
document.getElementById('translateButton').addEventListener('click', () => {
const documentDiv = document.querySelector('.document')
const clonedDiv = documentDiv.cloneNode(true)
const allTextArray = extractText(clonedDiv)
replaceText(allTextArray, translations)
const englishDiv = document.getElementById('english')
englishDiv.innerHTML = ''
englishDiv.appendChild(clonedDiv)
})
- 点击翻译按钮时,获取
.document
类对应的元素,假设这是第一个富文本编辑器。 - 克隆该元素及其子节点(深度克隆),以便在不修改原始内容的情况下操作。
- 使用
extractText
函数提取克隆元素中的文本节点。 - 调用
replaceText
函数,用翻译后的文本替换克隆元素中的文本节点。 - 清空
#english
元素的内容,然后将翻译后的克隆内容添加到该元素中。