代码拉取完成,页面将自动刷新
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./assets/global.css">
<style>
.parks .park {
display: flex;
margin-bottom: 5px;
}
.parks .words {
display: flex;
flex-wrap: wrap;
}
.book>.name,
.park>.name {
padding: 4px 8px;
}
.parks .word {
padding: 4px 8px;
margin-right: 6px;
cursor: pointer;
box-sizing: border-box;
border: 1px solid transparent;
}
.parks .word.selected {
border: 1px dashed red;
}
.control-bar {
display: flex;
}
.control-bar .form-item {
display: flex;
align-items: center;
padding-left: 8px;
}
.control-bar .form-item-input {
margin: 0 12px;
display: flex;
align-items: center;
}
.control-bar .form-item-text {
margin-right: 12px;
}
.read-word-text {
padding: 8px;
}
.read-word-text textarea {
height: 120px;
width: 360px;
resize: none;
}
.input-image {
margin-left: 10px;
}
</style>
</head>
<body>
<div class="read-word-text">
<textarea></textarea>
</div>
<div class="control-bar">
<div class="form-item">
<div class="form-item-label">
间隔
</div>
<div class="form-item-input">
<input class="read-interval" type="range" min="0" max="5" value="2">
</div>
<div class="form-item-text">
2s
</div>
</div>
<div class="form-item">
<button class="read-words">朗读</button>
<button class="input-image">图片识别</button>
</div>
</div>
<script type="module">
import Tesseract from "https://gcore.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.esm.min.js";
const worker = await Tesseract.createWorker("chi_sim", 1, {
corePath:
"https://gcore.jsdelivr.net/npm/tesseract.js-core@5/tesseract-core-simd-lstm.wasm.js",
workerPath:
"https://gcore.jsdelivr.net/npm/tesseract.js@5/dist/worker.min.js",
langPath:
"https://gcore.jsdelivr.net/npm/@tesseract.js-data/chi_sim/4.0.0",
});
const inputImageDOM = document.querySelector('.input-image')
inputImageDOM.addEventListener("click", () => {
const fileInput = document.createElement('input');
fileInput.setAttribute('type', 'file');
fileInput.setAttribute('accept', '*');
fileInput.addEventListener('change', async () => {
const files = fileInput.files;
let text = '';
for (let i = 0; i < files.length; i++) {
const ret = await worker.recognize(files[i]);
text += ret.data.text.replace(/[^a-zA-Z\u4e00-\u9fa5 ]/g, '')
console.log(ret.data.text);
}
readWordTextDOM.value = text;
});
fileInput.click();
})
const bookWords = [
{
name: '义务教育(六三学制)三年级上册',
parts: [
{
name: '1',
words: [
'穿戴',
'鲜艳',
'服装',
'打扮',
'敬爱',
'早晨',
'国旗',
'树枝',
'好奇',
'孔雀',
'招引',
'安静',
'敬礼',
'粗壮',
'枝干',
'影子'
]
},
{
name: '2',
words: [
"阵雨",
"荒野",
"跳舞",
"狂欢",
"功课",
"放假",
"互相",
"狂风",
"急急忙忙",
"自然",
"能够",
"双臂"
]
},
{
name: '5',
words: ['水泥', '放晴', '明朗', '亮晶晶', '金黄', '雨珠', '院墙', '落叶', '闪闪发光', '尽头', '平展', '排列', '规则', '歌唱', '迟到']
},
{
name: '6',
words: '清凉 留意 颜料 枫叶 邮票 果树 菊花 仙子 气味 香甜 香味 加紧 过冬 丰收'.split(' ')
},
{
name: '8',
words: '火柴 围裙 可怜 哪怕 暖和 简直 蜡烛 亮光 地板 烛光 温和 赶紧 痛苦 清晨'.split(' ')
},
{
name: '10',
words: '旅行 要好 咱们 草堆 作声 偷偷 答应 做梦 来得及 救命 拼命 大吃一惊 消化 当然 几乎 知觉 眼泪'.split(' ')
},
{
name: '12',
words: '变成 门板 准备 暴风雨 安心 睡觉 主人 墙壁 母鸡 注意 蜘蛛 漂亮 因此'.split(' ')
},
{
name: '15',
words: '雨点 船夫 用力 船头 羽毛 母亲 外祖父 翠绿 静悄悄 翠鸟 捕鱼'.split(' ')
},
{
name: '16',
words: '窗前 蒲公英 盛开 玩耍 一本正经 绒毛 合拢 手掌 有趣 假装 哈欠 钓鱼 观察 喜爱'.split(' ')
}
]
}
]
const readWordTextDOM = document.querySelector('.read-word-text > textarea')
/**
* 创建📕元素
* @author linyisonger
* @date 2025-04-10
*/
function createBookDOM() {
let bookWordsDOM = document.createElement('div')
bookWordsDOM.className = 'book-words'
for (const book of bookWords) {
let bookDOM = document.createElement('div')
let bookNameDOM = document.createElement('div')
let bookPartsDOM = document.createElement('div')
bookDOM.className = 'book'
bookNameDOM.className = 'name'
bookPartsDOM.className = 'parks'
bookNameDOM.textContent = book.name
for (const part of book.parts) {
let partDOM = document.createElement('div')
let partNameDOM = document.createElement('div')
let partWordsDOM = document.createElement('div')
partDOM.className = 'park'
partNameDOM.className = 'name'
partWordsDOM.className = 'words'
partNameDOM.textContent = part.name;
for (const words of part.words) {
let workDOM = document.createElement('div')
workDOM.className = 'word'
workDOM.textContent = words
partWordsDOM.appendChild(workDOM)
workDOM.addEventListener('click', (e) => {
e.target.classList.toggle('selected')
let wordsSelectedDOMList = document.querySelectorAll('.book-words .word.selected')
let wordsSelected = []
wordsSelectedDOMList.forEach(item => {
wordsSelected.push(item.textContent)
})
readWordTextDOM.value = wordsSelected.join(' ');
})
}
partDOM.appendChild(partNameDOM)
partDOM.appendChild(partWordsDOM)
bookPartsDOM.appendChild(partDOM)
}
bookDOM.appendChild(bookNameDOM)
bookDOM.appendChild(bookPartsDOM)
bookWordsDOM.appendChild(bookDOM)
}
document.body.prepend(bookWordsDOM);
}
createBookDOM();
const synth = window.speechSynthesis;
let voices;
function loadVoices() {
voices = synth.getVoices();
}
// in Google Chrome the voices are not ready on page load
if ("onvoiceschanged" in synth) {
synth.onvoiceschanged = loadVoices;
} else {
loadVoices();
}
let readWordsDOM = document.querySelector('.read-words')
let readIntervalDOM = document.querySelector('.read-interval')
readWordsDOM.addEventListener('click', readWord)
readIntervalDOM.addEventListener('change', (e) => {
let textDOM = e.target.parentElement.parentElement.querySelector('.form-item-text')
textDOM.textContent = e.target.value + 's';
})
async function readWord() {
if (+readIntervalDOM.value == 0) {
const utterThis = new SpeechSynthesisUtterance(readWordTextDOM.value);
utterThis.voice = voices[0];
synth.speak(utterThis);
}
else {
let wordsSelected = readWordTextDOM.value.split(' ').filter(w => w)
for (let i = 0; i < wordsSelected.length; i++) {
const words = wordsSelected[i];
const utterThis = new SpeechSynthesisUtterance(words);
utterThis.voice = voices[0];
synth.speak(utterThis);
await new Promise(r => setTimeout(r, +readIntervalDOM.value * 1000))
}
}
}
</script>
</body>
</html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。