【ES6】Latex总结笔记生成器(网页版)

发布于:2025-07-10 ⋅ 阅读:(21) ⋅ 点赞:(0)

概述

之前写了Godot版本的ETD2Latex,也就是将Tab缩进格式的层级文本转化成Latex的cases环境嵌套,一直想写个JS版本的,之前基于AI转化代码修改,越改越乱,放弃了。

今天终于沉下心来,从零开始写了一个JS版本。也算把这个坑填了。

用处嘛,就是学习时写各种总结笔记,亲测有效,用来过了一场考试。

界面

实现基础功能,界面都是原生的HTML和JS,所以暂时有点丑。

在这里插入图片描述
目前版本:

  • 可以使用空格作为缩进,可以是1个或多个空格,只要低一级的缩进数大于高一级的就行
  • 实时转化为Latex公式的cases环境嵌套形式(Latex总结笔记)
  • 使用KaTex渲染,直接在底部实时生成预览

代码

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS版ETD2Latex</title>
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js"></script>
    <script src="ETD2Latex.js"></script>
	<style>
		h1{
			text-align: center;
			margin-bottom: 10px;
		}
		.author{
			text-align: center;
			margin-bottom: 10px;
		}
		textarea{
			width:calc(100% - 8px);
			height: 200px;
		}
		.colums2{
			display: grid;
			gap: 10pt;
			grid-template-columns: 1fr 1fr;
		}
		.col{
			background-color: #ccc;
			border:1px solid #444;
			/* padding: 10pt; */
			text-align: right;
		}
		.col h2{
			margin: 0pt;
			padding: 5px;
			background-color: #444;
			text-align: center;
			color:white;
		}
		.col .col_body{
			padding: 10pt;
		}
		button{
			min-width: 100px;
			min-height: 30px;
		}
		/* latex公式预览区域 */
		#latex_div{
			min-height: 100px;
			background-color: #ccc;
			padding: 10px;
		}
		span.info{
			color:red;
			margin-right: 5px;
		}
	</style>
</head>
<body>
	<h1>Latex总结笔记生成器(网页版)</h1>
	<div class="author">巽星石</div>
	<!-- 分栏 -->
	<div class="colums2">
		<!-- 左侧列 -->
		<div class="col">
			<h2>ETD字符串</h2>
			<div class="col_body">
				<textarea id="etd_txt"></textarea><br>
				<button id="cls_btn">清空</button>
			</div>
		</div>
		<!-- 右侧列 -->
		<div class="col">
			<h2>Latex公式字符串</h2>
			<div class="col_body">
				<textarea id="latex_txt"></textarea><br>
				<span class="info" id="info1"></span><button id="copy_btn">复制</button>
			</div>
		</div>
	</div>
	<h2>Latex预览</h2>
	<div id="latex_div"></div>

</body>
<script>

// 解析ETD字符串
let etd_txt = document.getElementById("etd_txt")
let latex_txt = document.getElementById("latex_txt")
let latex_div = document.getElementById("latex_div")
let cls_btn = document.getElementById("cls_btn")
let copy_btn = document.getElementById("copy_btn")
let info_span = document.getElementById("info1")


// 清空
cls_btn.onclick = function(){
	etd_txt.value = ""
	etd_txt.onkeyup()
}

// 实时输入和生成
etd_txt.onkeyup = function(){
	let tree = ETDTree.with_etd_str(etd_txt.value);
	latex_txt.value = tree.to_latex();
	katex.render(latex_txt.value,latex_div); // 渲染
}

// 复制
copy_btn.onclick = function(){
	latex_txt.select();
	navigator.clipboard.writeText(latex_txt.value);
	info_span.innerText = "已完成拷贝";
}

</script>

</html>

ETD2Latex.js

// 节点
class ETDNode{
	children = []
	constructor(id,deep,text,p_node){
		this.id = id
		this.deep = deep
		this.text = text
		this.p_node = p_node
	}
	// 转化为字符串
	to_string(is_last = false){
        let sttr = ""
        if(is_last){
            sttr = "\t".repeat(this.deep) + this.text;
        }else{
            sttr = "\t".repeat(this.deep) + this.text + "\n";
        }
        let idx = 0;
        if(this.children.length > 0){
            sttr += "\n"
        }
		this.children.forEach(chd => {
			sttr += chd.to_string(idx == this.children.length - 1);
            idx += 1;
		});
		return sttr;
	}
    // 转换为Latex
    to_latex(is_last = false){
        let ltx = ""
        if(this.children.length == 0){
            if(is_last){
                ltx = this.text + "\n";
            }else{
                ltx = this.text + "\\".repeat(2) + "\n";
            }
        }else{
            ltx = this.text + "\n";
            ltx += "\\begin{cases}\n"
            let idx = 0;
            this.children.forEach(chd => {
                ltx += chd.to_latex(idx == this.children.length - 1);
                idx += 1;
            });
            ltx += "\\end{cases}" + "\\".repeat(2) + "\n";
        }
        return ltx;
    }
}

// 解析后的树
class ETDTree{
	tree = null;
	constructor(tree){
		this.tree = tree;
	}
	// 以ETD字符串创建实例
	static with_etd_str(etd_str){
		let p_node = null  // 父节点
		let c_node = null  // 当前节点
		let line_idx = 0   // 行号
		let tree = null    // 树的根节点
		for(let line of etd_str.split("\n")) {
			let deep = line.length - line.trimStart().length  // 当前深度
			let text = line.trim() // 当前节点文本
			if(p_node == null){
				c_node = new ETDNode(line_idx,deep,text,p_node);
				tree = c_node;
				p_node = c_node;
			}else{
				if(p_node.deep < deep){
					c_node = new ETDNode(line_idx,deep,text,p_node);
					p_node.children.push(c_node);
					p_node = c_node;
				}else if(p_node.deep == deep){
					p_node = p_node.p_node
					c_node = new ETDNode(line_idx,deep,text,p_node);
					p_node.children.push(c_node);
					p_node = c_node;
				}else{
                    p_node = p_node.p_node.p_node
					c_node = new ETDNode(line_idx,deep,text,p_node);
					p_node.children.push(c_node);
					p_node = c_node;
                }
			}
			line_idx += 1;
		}
		return new ETDTree(tree);
	}
	// 转化为字符串
	to_string(){
		return this.tree.to_string();
	}
    // 转换为Latex
    to_latex(){
        return this.tree.to_latex();
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到