Markdown、Latex编辑小工具

Markdown、Latex编辑小工具

    • 文章说明
    • 主要代码
    • 效果展示
    • 源码下载

文章说明

本文主要为了书写Latex的书写风格,以及了解自己实现一个markdown类型的编辑器的过程;目前实现了当前的效果;书写文章进行记录,方便后续查阅

目前还未添加好markdown的代码高亮效果,等待后续自己实现一个高亮组件,然后添加到该demo中

文本相对复杂的几个小点为:
1、marked库的使用
2、katex库的使用
3、textarea元素的光标处插入内容的实现(本效果参考了文章:利用selection对象在textarea光标处插入指定文本)
4、滚动同步效果(目前实现的效果感觉不是很好,会有一些抖动的效果,感觉有点头晕,没有CSDN自带的编辑功能的这个同步效果的实现精细,不过我目前也没整明白它这里的实现原理是什么样的,如果有好的想法的同学欢迎提出在评论区中,如对demo有帮助,冰冰一号会进行采纳,同时添加到项目贡献者中)
Latex相关公式的查找(参考文章为:[markdown语法]公式篇–整理总结了常用的公式语法全)

实际关于markdown相关组件的使用,可以直接使用封装好的库,如v-md-editor,这种封装好的库使用相对简单,而且功能更加完善,参考链接:v-md-editor

主要代码

文件结构
在这里插入图片描述

markdown组件

<template><div class="container"><textarea class="left" v-model="data.text" @scroll="scrollLeftSync"></textarea><div class="right" v-html="renderedMarkdown" @scroll="scrollRightSync"></div></div>
</template><script setup>
import {marked} from 'marked';
import {computed, onMounted, reactive} from "vue";const data = reactive({text: "",
});const renderedMarkdown = computed(() => {return marked.parse(data.text);
});let left;
let right;onMounted(() => {left = document.getElementsByClassName("left")[0];right = document.getElementsByClassName("right")[0];left.focus();
});let leftScroll = true;
let rightScroll = true;function scrollLeftSync() {if (!leftScroll) {return;}const percent = (left.scrollTop / (left.scrollHeight - left.clientHeight)).toFixed(2);rightScroll = false;right.scrollTo({top: (right.scrollHeight - right.clientHeight) * percent,});rightScroll = true;
}function scrollRightSync() {if (!rightScroll) {return;}const percent = (right.scrollTop / (right.scrollHeight - right.clientHeight)).toFixed(2);leftScroll = false;left.scrollTo({top: (left.scrollHeight - left.clientHeight) * percent,});leftScroll = true;
}
</script><style lang="scss" scoped>
.container {width: 100%;height: 100%;.left {width: 50%;height: 100%;resize: none;border: none;outline: none;background: transparent;font-size: 1.4rem;padding: 1rem;display: block;overflow: auto;float: left;&::-webkit-scrollbar {width: 0.5rem;background-color: transparent;border-radius: 0.5rem;cursor: pointer;}&::-webkit-scrollbar-thumb {background-color: #bbbbbb;border-radius: 0.5rem;cursor: pointer;}}.right {width: 50%;height: 100%;background-color: #ffffff;font-size: 1.4rem;padding: 1rem;overflow: auto;float: left;&::-webkit-scrollbar {width: 0.5rem;height: 0.5rem;background-color: transparent;border-radius: 0.5rem;}&::-webkit-scrollbar-thumb {background-color: #bbbbbb;border-radius: 0.5rem;}}
}
</style>

Latex组件

<template><div class="container"><div class="tool"><ul><li @click="appendLine">换行</li><li @click="superscript">上标</li><li @click="subscript">下标</li><li @click="vector">向量</li><li @click="average">平均值</li><li @click="fraction">分式</li><li @click="dots">省略号</li><li @click="sqrt">根式</li><li @click="mul"></li><li @click="div"></li><li @click="ge">大于等于</li><li @click="le">小于等于</li><li @click="ne">不等于</li><li @click="dx">导数</li><li @click="infinity">无穷</li><li @click="leftarrow">左箭头</li><li @click="rightarrow">右箭头</li><li @click="In">属于</li><li @click="notIn">不属于</li><li @click="overbrace">上大括号</li><li @click="underbrace">下大括号</li><li @click="sin">sin</li><li @click="cos">cos</li><li @click="tan">tan</li><li @click="log">log</li><li @click="lg">lg</li><li @click="ln">ln</li><li @click="equationSet">方程组</li><li @click="calculationProcess">计算过程</li></ul></div><div class="content"><textarea class="left" v-model="data.text" @scroll="scrollLeftSync"></textarea><div class="right" v-html="data.parseText" @scroll="scrollRightSync"></div></div></div>
</template><script setup>
import {onMounted, reactive, watch} from "vue";
import katex from 'katex'const data = reactive({text: "",parseText: "",
});const renderOption = {delimiters: [{left: '$$', right: '$$', display: true},{left: '$', right: '$', display: false},{left: '\\(', right: '\\)', display: false},{left: '\\[', right: '\\]', display: true}],throwOnError: false
}watch(() => data.text, () => {data.parseText = katex.renderToString(data.text, renderOption);
});let left;
let right;onMounted(() => {left = document.getElementsByClassName("left")[0];right = document.getElementsByClassName("right")[0];left.focus();
});let leftScroll = true;
let rightScroll = true;function scrollLeftSync() {if (!leftScroll) {return;}const percent = (left.scrollTop / (left.scrollHeight - left.clientHeight)).toFixed(2);rightScroll = false;right.scrollTo({top: (right.scrollHeight - right.clientHeight) * percent,});rightScroll = true;
}function scrollRightSync() {if (!rightScroll) {return;}const percent = (right.scrollTop / (right.scrollHeight - right.clientHeight)).toFixed(2);leftScroll = false;left.scrollTo({top: (left.scrollHeight - left.clientHeight) * percent,});leftScroll = true;
}function insertAtCursor(f, value, callback) {let field = flet newValueif (field.selectionStart || field.selectionStart === 0) {const startPos = field.selectionStartconst endPos = field.selectionEndconst restoreTop = field.scrollTopnewValue = field.value.substring(0, startPos) + value + field.value.substring(endPos, field.value.length)if (restoreTop > 0) {field.scrollTop = restoreTop}field.focus()setTimeout(() => {field.selectionStart = startPos + value.lengthfield.selectionEnd = startPos + value.length}, 0)} else {newValue = field.value + valuefield.focus()}callback(newValue)
}function addContent(text) {insertAtCursor(left, text, (newValue) => {data.text = newValue;});
}function appendLine() {addContent("\n\\\\\\\n");
}function superscript() {addContent(" x^y ");
}function subscript() {addContent(" x_y ");
}function vector() {addContent(" \\vec{a} ");
}function average() {addContent(" \\overline{a} ");
}function fraction() {addContent(" \\frac{1}{2} ");
}function dots() {addContent(" \\cdots ");
}function sqrt() {addContent(" \\sqrt[2]{x+y} ");
}function mul() {addContent(" \\times ");
}function div() {addContent(" \\div ");
}function ge() {addContent(" \\ge ");
}function le() {addContent(" \\le ");
}function ne() {addContent(" \\ne ");
}function dx() {addContent(" x{\\prime} ");
}function infinity() {addContent(" \\infty ");
}function leftarrow() {addContent(" \\leftarrow ");
}function rightarrow() {addContent(" \\rightarrow ");
}function In() {addContent(" \\in ");
}function notIn() {addContent(" \\notin ");
}function overbrace() {addContent(" \\overbrace{1+2+\\cdots+100} ");
}function underbrace() {addContent(" \\underbrace{1+2+\\cdots+100} ");
}function sin() {addContent(" \\sin 30^\\circ ");
}function cos() {addContent(" \\cos 30^\\circ ");
}function tan() {addContent(" \\tan 30^\\circ ");
}function log() {addContent(" \\log_2 8 ");
}function lg() {addContent(" \\lg 10 ");
}function ln() {addContent(" \\ln 2 ");
}function equationSet() {addContent("\nf(n)= \\begin{cases}\n" +"n/2, & \\text {if $n$ is even} \\\\\n" +"3n+1, & \\text{if $n$ is odd}\n" +"\\end{cases}\n");
}function calculationProcess() {addContent("\n\\begin{aligned}\n" +"    f(x)\n" +"    &=x^3+3x^2+3x+1\\\\\n" +"    &=(x+1)^3\\\\\n" +"\\end{aligned}\n");
}
</script><style lang="scss" scoped>
.container {width: 100%;height: 100%;.tool {width: 100%;height: 6rem;border-bottom: 0.1rem solid #e0e1e2;background-color: #ffffff;ul {list-style: none;height: 3rem;line-height: 3rem;user-select: none;li {float: left;padding: 0 0.5rem;height: 3rem;text-align: center;color: #409eff;&:hover {cursor: pointer;color: #79bbff;}}}}.content {width: 100%;height: calc(100% - 6rem);.left {width: 50%;height: 100%;resize: none;border: none;outline: none;background: transparent;font-size: 1.4rem;padding: 1rem;display: block;float: left;&::-webkit-scrollbar {width: 0.5rem;background-color: transparent;border-radius: 0.5rem;}&::-webkit-scrollbar-thumb {background-color: #bbbbbb;border-radius: 0.5rem;}}.right {width: 50%;height: 100%;background-color: #ffffff;font-size: 1.4rem;padding: 1rem;overflow: auto;float: left;&::-webkit-scrollbar {width: 0.5rem;height: 0.5rem;background-color: transparent;border-radius: 0.5rem;}&::-webkit-scrollbar-thumb {background-color: #bbbbbb;border-radius: 0.5rem;}}}
}
</style>

效果展示

markdown编辑展示
在这里插入图片描述

Latex编辑展示
在这里插入图片描述

源码下载

冰冰markdown小工具

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/365135.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux实用命令练习

目录 一、常用命令 二、系统命令 三、用户和组 四、权限 五、文件相关命令 六、查找 七、正则表达式 八、输入输出重定向 九、进程控制 十、其他命令 1、远程文件复制&#xff1a;scp 2、locate查找 3、which命令 4、设置或显示环境变量&#xff1a;export 5、修…

【.NET全栈】第16章 Web开发

文章目录 前言16.1 HTML概述16.1.1 HTML的基本概念16.1.2 HTML语言的基本元素16.1.3 格式设置16.1.4 超级链接16.1.5 图像16.1.6 表格16.1.7 框架16.1.8 表单 16.2 ASP.NET Web Forms的组织16.2.1 认识ASP.NET16.2.2 Web Forms的组织 16.3 Web服务器组件16.3.1 使用Label和Text…

[AIGC] 深入了解标准与异常重定向输出

在操作系统和编程环境下&#xff0c;有时我们需要更加精细地控制程序的输入或输出过程&#xff0c;这就涉及到了标准输入输出流&#xff0c;以及重定向的概念。接下来&#xff0c;我们将详细介绍标准输出、标准错误输出&#xff0c;以及如何进行输出重定向。 文章目录 1. 标准输…

网线直连电脑可以上网,网线连tplink路由器上不了网

家里wifi网络连不上好几天了&#xff0c;用网线直连电脑可以上网&#xff0c;但网线连tplink路由器wan口上不了网&#xff0c;无Internet连接&#xff0c;网线连lan口可以电脑上网&#xff0c;手机上不了。 后来发现网线的主路由用的192.168.0.1&#xff0c;我的路由器wan口自…

将某列缺失分隔符的文字读入 Excel

有个逗号分隔的 txt&#xff0c;共 10 列&#xff0c;第 3 列有时候缺少分隔符&#xff0c;导致该列缺失&#xff0c;数据不齐只剩 9 列。比如最后两行&#xff1a; 01-0104-0133,MAYO, RONIE #2,202403,2024-03-21 22:51:43.000,1449.49,0.00,0.00,08,6CC6BDAC7E45 17-1782-02…

百强韧劲,进击新局 2023年度中国医药工业百强系列榜单发布

2024年&#xff0c;经济工作坚持稳中求进、以进促稳、先立后破等工作要求。医药健康行业以不懈进取的“韧劲”&#xff0c;立身破局&#xff0c;迎变启新。通过创新和迭代应对不确定性&#xff0c;进化韧性力量&#xff0c;坚持高质量发展&#xff0c;把握新时代经济和社会给予…

ubuntu 编译交叉环境arm 版本的openssl库

一&#xff0c;下载源码 [ Old Releases ] - /source/old/index.html 二&#xff0c;设置交叉编译环境 我的交叉环境是RV1126开发板&#xff0c;/home/rpdzkj/development/cross-compile-tools/rv1126/ 对应的是我电脑里的RV1126开发板的交叉环境下的gc g等路径存放 设置环境…

【C++深度探索】继承机制详解(一)

hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;大耳朵土土垚的博客 &#x1…

43.三倍游戏

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/390 题目描述 三倍游戏是一种单人游戏。玩…

忍法:声音克隆之术

前言&#xff1a; 最近因为一直在给肚子里面的宝宝做故事胎教&#xff0c;每天&#xff08;其实是看自己心情抽空讲下故事&#xff09;都要给宝宝讲故事&#xff0c;心想反正宝宝也看不见我&#xff0c;只听我的声音&#xff0c;干脆偷个懒&#xff0c;克隆自己的声音&#xf…

【SpringBoot】SpringBoot应用Yaml 解析冒号(:)字符串踩坑排查记录

文章目录 一、现象二、原因排查三、怎么办 一、现象 某次在配置中心Nacos上配置了一个字符串&#xff0c;采用YAML格式&#xff0c;如下&#xff1a; id: 114:1代码中采用的是Value注解的形式获取配置&#xff1a; Value("${id}")代码中预期获取的是字符串&#x…

微服务中的Docker详细学习

Docker的个人理解 首先我对于Docker的理解分为两部分&#xff0c;第一是对名字上的理解&#xff0c;我们都知道docker的英文翻译是“码头工人”的意思&#xff0c;所以我们也可以理解为docker是码头上的一个个集装箱的使用。这也与他的图标很相似。其次我是对于其功能上的理解&…

ASP.Net.WebAPI和工具PostMan

1.WebAPI概述 1.1 WebAPI WebAPI 是一种传统的方式&#xff0c;用于构建和暴露 RESTUI风格的Web服务。它提供了丰富的功能和灵活性&#xff0c;可以处理各种HTTP请求&#xff0c;并支持各种数据格式&#xff0c;如JSON、XML等。 WebAPI使用控制器(Controllers)和动作方法(Ac…

力扣每日一题 6/30 记忆化搜索/动态规划

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;IT竞赛 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 494.目标和【中等】 题目&#xff1a; 给你一个非负整数数组 nums 和一个…

INS-GPS组合导航——卡尔曼滤波

系列文章目录 《SAR笔记-卫星轨道建模》 《SAR笔记-卫星轨迹&#xff08;三维建模&#xff09;》 《常用坐标系》 文章目录 前言 一、经典卡尔曼滤波 二、扩展卡尔曼滤波 三、无迹卡尔曼滤波 总结 前言 SAR成像仪器搭载于运动平台&#xff0c;平台的自定位误差将影响SAR…

Redis缓存问题二、缓存雪崩

缓存雪崩 缓存雪崩&#xff1a;是指在同一时段大量的缓存key同时失效或者Redis服务宕机&#xff0c;导致大量请求到达数据库&#xff0c;带来巨大压力。 缓存雪崩的解决方案&#xff1a; 给不同的Key的TTL添加随机值利用Redis集群提高服务的可用性给缓存业务添加降级限流策略…

数据库物理结构设计-定义数据库模式结构(概念模式、用户外模式、内模式)、定义数据库、物理结构设计策略

一、引言 如何基于具体的DBMS产品&#xff0c;为数据库逻辑结构设计的结果&#xff0c;即关系数据库模式&#xff0c;制定适合应用要求的物理结构 1、在设计数据库物理结构前&#xff0c;数据库设计人员首先 要充分了解所用的DBMS产品的功能、性能和特点&#xff0c;包括提供…

DarkGPT:基于GPT-4-200k设计的人工智能OSINT助手

关于DarkGPT DarkGPT是一款功能强大的人工智能安全助手&#xff0c;该工具基于GPT-4-200k设计并实现其功能&#xff0c;可以帮助广大研究人员针对泄露数据库进行安全分析和数据查询相关的OSINT操作。 工具要求 openai1.13.3 requests python-dotenv pydantic1.10.12 工具安装 …

word2016中新建页面显示出来的页面没有页眉页脚,只显示正文部分。解决办法

问题描述&#xff1a;word2016中新建页面显示出来的页面没有页眉页脚&#xff0c;只显示正文部分。设置了页边距也不管用。 如图1 图1 解决&#xff1a; 点击“视图”——“多页”——“单页”&#xff0c;即可。如图2操作 图2 结果展示&#xff1a;如图3 图3

操作系统精选题(三)(简答题、概念题)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;操作系统 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 前言 简答题 一、对 CPU、内存、外设并…