当前位置: 首页 > news >正文

我是如何在markdown编辑器中完成视频的插入和播放的

如果你有更好用的编辑器组件,请一定推荐给我!!!(最好附带使用说明🤓️)

介绍

在开发一个社区页面的时候,需要完成发帖、浏览帖子的能力。这里考虑接入markdown编辑器进行开发,也符合大多数用户的习惯。

首先是编辑器的选择,经过深思熟虑(随缘)后,确定了为 ByteMd, 主要是平时用掘金看到它们也是这个编辑器。
安装很简单:

npm install bytemd

用起来更简单:

    import '@/assets/static/editor_index.css' // 引入布局文件,防止样式错乱// 可以去了解下每个插件的功能,都是现有的,不再赘述const plugins = [gfm(), highlight(), breaks(), frontmatter(), footnotes(), gemoji(), mediumZoom()]<Editorlocale={zhHans} // 选择语言value={content} // 内容区域plugins={plugins} //支持的插件onChange={(v) => {setContent(v);}}// 自定义内容区域媒体文件的上传uploadImages={async (files): Promise<Pick<Image, "alt" | "title" | "url">[]> => {console.log("files", files);const imageUrl = await uploadImage(files[0]);return [{title: files.map((i) => i.name).join(),url: imageUrl,},];}}/>

这样就很快的实现了一个markdown的编辑器。不出问题的话就要出问题了

要支持上传视频

挠头,这个功能区没有上传视频的区域啊,这咋搞呢?去掘金上看看,掘金是有的,那肯定是可以有的。那么就看看如何在tools栏增加一个视频的icon
bytemd本身支持对tools bar做扩展,这样就简单了很多。可以拉下来源码看一下,新增一个tool的代码也很简单
    export default function videoPlugin(saveEditorContext: (editorContext: BytemdEditorContext) => void) {const ADD_VIDEO = "url" // 视频tool的展示iconconst handleUploadVideo = () => {window.dispatchEvent(showUploadAVDialog) // 点击时的事件处理,这里也是发通知给别处去处理了}return {actions: [{title: '视频',icon: `<img src="${ADD_VIDEO}" alt={"logo"} style="width: 24px; height: 24px;"/>`,handler: {type: 'action',click(context: BytemdEditorContext) {handleUploadVideo()saveEditorContext(context)},},},]}}

然后 把这个** videoPlugin** 加到前面的plugins列表里面

image.png
这样就有了一个上传视频的icon,点击后需要你来实现一下打开文件选择器 -> 选择视频 -> 上传到服务器 -> 处理上传后的链接 这套逻辑(不一定是这样,得看具体的业务流程)

当然,这肯定还没完,上传之后,需要像图片一样,在编辑区把视频展示出来吧。
一开始想得很简单,直接用一个<\iframe>或者 <\video> 标签,把视频播出了不就好了。but,这肯定是行不通的,为了防止XSS,这些特殊的标签都是不允许直接在输入框内进行使用的。掘金不太一样,它只能插入它们指定播放源的视频,也就是说要保证视频源的可靠才能插入。
我们业务暂时不需要考虑,都是自己人,也不会干这种事。于是参考了其他一些网站的实现,直接将视频内容展示为一个视频播放的缩略图。对,就是下面的 – ![\AVFile](${url})\n

    const handleUploadSuccess = (url: string, file: File) => {if (editorContext) {// 创建一个视频播放器的 HTML 代码const videoHtml = `![AVFile](${url})\n`;const {line, ch} = editorContext.editor.getCursor();editorContext.editor.replaceRange(videoHtml, {line, ch});setContent(editorContext.editor.getValue());} else {message.error("上传失败,请重试")}};

在视频上传完成后,我们在插入视频的文本光标后面 主动添加视频的缩略图展示。

要注意一点,这里用到的 editorContext 是前面 videoPlugin组件中获取的,需要在用的组件内保存一下。

细心的你肯定会问:这里的url是视频的URL,用图片的语法展示会裂吧?
确实会有这个问题,于是我们还需要对整个编辑区的内容做一个处理,把展示的内容里面 视频的url替换成统一的视频缩略图(注意,只是展示位置的图片被替换了,实际上保存的还是视频的URL哈

于是我们再实现一个转换内容的插件,前提是基于你已经了解了 bytemd的 这几个接口的含义和调用时机,我不是来讲原理的,所以就不细嗦了。
image.png

    export default function videoEmbedPlugin() {const DEFALUT_VIDEO_URL = 'http://cdn.qboost.woa.com/files/community_article_pic/%E8%A7%86%E9%A2%91%20%281%29_1716435376866.png'return {// @ts-ignoreremark: (processor) =>// @ts-ignoreprocessor.use(() => (tree) => {visit(tree, 'image', (node) => {if (node.alt === 'AVFile') {// 替换图片 URLnode.url = DEFALUT_VIDEO_URL;}});}),};}

OK,编辑区支持上传视频的能力也算是大功告成了。不过,查看markdown文章的展示区也还需要适配,毕竟它是不可能自动播放你添加上去的视频的。

查看视频

对于展示区的处理,会简单很多,因为我们在上传视频的时候,对视频的url做了特殊处理,也就是在前面添加了[AVFile], 那么我们就可以在布局完成后,通过遍历展示区的html结点,找到 AVFile的img标签,然后将html中的这部分标签,替换为 <video>标签,就可以播放视频了

// 替换为<video>标签
export function handlePicToVideo() {const markdownBodyElement = document.querySelector('.markdown-body');if (markdownBodyElement) {// 查找所有的 <p><img> 元素const images = markdownBodyElement.querySelectorAll('img.medium-zoom-image[alt="AVFile"]');images.forEach((img) => {const videoUrl = img.getAttribute('src');// 创建 video 元素const videoElement = document.createElement('video');videoElement.setAttribute('controls', 'controls');videoElement.setAttribute('width', 'auto');const sourceElement = document.createElement('source');sourceElement.setAttribute('src', videoUrl!);sourceElement.setAttribute('type', 'video/mp4');videoElement.appendChild(sourceElement);const noSupportText = document.createTextNode('Sorry, your browser doesn't support embedded videos.');videoElement.appendChild(noSupportText);// 替换 img 元素为 video 元素const parentParagraph = img.parentElement;if (parentParagraph) {parentParagraph.replaceChild(videoElement, img);}});}
}

相关文章:

我是如何在markdown编辑器中完成视频的插入和播放的

如果你有更好用的编辑器组件&#xff0c;请一定推荐给我!!!&#xff08;最好附带使用说明&#x1f913;️&#xff09; 介绍 在开发一个社区页面的时候&#xff0c;需要完成发帖、浏览帖子的能力。这里考虑接入markdown编辑器进行开发&#xff0c;也符合大多数用户的习惯。 …...

Ltv 数据粘包处理

测试数据包的生成 校验程序处理结果和原始的日志保温解析是否一致 程序粘包分解正常...

银联支付,你竟然还不知道它怎么工作?

银联支付咱都用过&#xff0c;微信和支付宝没这么“横行”的时侯&#xff0c;我们取款、转账、付款时用的ATM机、POS机&#xff0c;都是银联支付完成的。 今天&#xff0c;就让咱们了解一下银行卡支付的工作原型。 首先&#xff0c;说说中国银联 中国银联&#xff08;China U…...

查找程序中隐藏界面的思路

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动 某些程序&#xff0c;它会有管理员界面&#xff08;比如棋牌游戏&#xff0c;它一般会有一个控制端界面&#xff0c;用来控制发牌、换牌&#xff09;&#xff0c;但是这种界…...

umount

umount命令用于卸载文件系统&#xff0c;使得挂载点的文件和目录变为不可访问。 基本用法&#xff1a; umount [选项] 设备或文件夹 常见选项&#xff1a; -f&#xff1a;强制卸载&#xff0c;即使文件系统处于忙碌状态&#xff08;在某些情况下使用&#xff0c;如网络文件…...

electron录制应用-自由画板功能

功能 录屏过程中的涂画功能允许用户在录制屏幕操作的同时&#xff0c;实时添加注释和高亮显示&#xff0c;以增强信息的传达和观众的理解。 效果 electron录制-添加画布 代码实现 1、利用HTML5的Canvas元素实现一个自由涂画的功能&#xff0c;允许用户在网页上进行手绘创作。…...

版本控制工具-git分支管理

目录 前言一、git分支管理基本命令1.1 基本命令2.1 实例 二、git分支合并冲突解决三、git merge命令与git rebase命令对比 前言 本篇文章介绍git分支管理的基本命令&#xff0c;并说明如何解决git分支合并冲突&#xff0c;最后说明git merge命令与git rebase命令的区别。 一、…...

医卫医学试题及答案,分享几个实用搜题和学习工具 #学习方法#知识分享#经验分享

可以说是搜题软件里面题库较为齐全的一个了&#xff0c;收录国内高校常见的计算机类、资格类、学历类、外语类、工程类、建筑类等多种类型的题目。它可以拍照解题、拍照答疑、智能解题&#xff0c;并支持每日一练、章节练习、错题重做等特色功能&#xff0c;在帮助大家解答疑惑…...

在dolphinDB上直接保存一个dataframe为分布式数据表

步骤1&#xff1a;获取链接 import dolphindb as ddb from loguru import loggerdef get_dolphin_session():"""获取dolphinDB的session"""dolphin_config {"host": "127.0.0.1","port": 13900,"username&…...

awk

awk grep 查 sed 增删改查 awk 按行取列 awk默认分割符&#xff1a; 空格&#xff1b;tab键。多个空格压缩成一个空格 [roottest2 opt]# cat awk.txt 1 2 3 [roottest2 opt]# awk {print $3} awk.txt 3 awk的工作原理&#xff1a; 根据指令信息&#xff0c;逐行的读…...

如何加速AI原生应用进程?华为云开天aPaaS提出新范式

每一次新旧代际转换时&#xff0c;都会上演这样的一幕&#xff1a;“畅想很多&#xff0c;落地很少”&#xff0c;AI原生应用似乎也不例外。 关于AI原生应用的呼声已经持续一段时间&#xff0c;但普通用户对“AI原生”依然陌生。除了新业态普及的周期性&#xff0c;AI原生应用…...

Matlab基础语法:变量和数据类型,基本运算,矩阵和向量,常用函数,脚本文件

目录 一、变量和数据类型 二、基本运算 三、矩阵和向量 四、常用函数 五、脚本文件 六、总结 一、变量和数据类型 Matlab 支持多种数据类型&#xff0c;包括数值类型、字符类型和逻辑类型。掌握这些基本的变量和数据类型&#xff0c;是我们进行数学建模和计算的基础。 数…...

弥补iPhone不足,推荐金鸣识别等几款APP神器

在数字时代的浪潮中&#xff0c;iPhone以其独特的设计和强大的性能赢得了全球众多用户的喜爱。然而&#xff0c;即便是这样一款近乎完美的设备&#xff0c;也难免存在一些局限性和缺陷。幸运的是&#xff0c;App Store中蕴藏着许多鲜为人知的app&#xff0c;它们可以弥补iPhone…...

KLayout 中的默认数据类型

KLayout 中的默认数据类型 这里给大家介绍一下 KLayout 中的默认数据类型。从这个官方文档 KLayout 数据类型 中我们可以获取到 KLayout 中的默认数据类型有如下几种&#xff1a; Column 1Column 2TypeBoolean布尔值TypeCallback按键返回类型TypeDouble浮点数类型TypeInt整型Ty…...

视频云存储平台LntonCVS国标视频平台功能和应用场景详细介绍

LntonCVS国标视频融合云平台基于先进的端-边-云一体化架构设计&#xff0c;以轻便的部署和灵活多样的功能为特点。该平台不仅支持多种通信协议如GB28181、RTSP、Onvif、海康SDK、Ehome、大华SDK、RTMP推流等&#xff0c;还能兼容各类设备&#xff0c;包括IPC、NVR和监控平台。在…...

C语言 将程序第4,5行改为 c1=197;c2=198;将程序第3行改为int c1,c2;

问题代码如下&#xff1a; #include<stdio.h> int main() { char c1,c2; c197; c298; printf(“c1%c,c2%c\n”&#xff0c;c1,c2); printf(“c1%d,c2%d\n”&#xff0c;c1,c2); return 0; } 运行时会输出什么信息&#xff1f;为什么&#xff1f;如果将程序第4&am…...

【总线】AXI4第五课时:信号描述

大家好,欢迎来到今天的总线学习时间!如果你对电子设计、特别是FPGA和SoC设计感兴趣&#xff0c;那你绝对不能错过我们今天的主角——AXI4总线。作为ARM公司AMBA总线家族中的佼佼者&#xff0c;AXI4以其高性能和高度可扩展性&#xff0c;成为了现代电子系统中不可或缺的通信桥梁…...

创建单例模式的六种方式

一、单例模式 单例模式是一种创建型的设计模式&#xff0c;构造函数是私有的&#xff0c;因此只能在类中创建一个实例&#xff0c;且对外提供一个静态公有方法获取这个实例。 二、创建方法 1. 懒汉式&#xff08;线程不安全&#xff09; public class Singleton{private st…...

实用软件下载:CrossOver 2024最新安装包及详细安装教程

​根据软件大数据显示上传或者手动输入软件都非常简单&#xff0c;一般来说CrossOver会自动连接到一个Win文件共享服务器&#xff08;Samba或CIFS&#xff09;上&#xff0c;使用者能够直接在这个服务器中选择并上传软件执行文件。实际上我们可以这样讲调整CrossOver设置&#…...

开启调试模式

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 run()方法虽然适用于启动本地的开发服务器&#xff0c;但是每次修改代码后都要手动重启它。这样并不够方便&#xff0c;如果启用了调试支持&#xff…...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统

目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索&#xff08;基于物理空间 广播范围&#xff09;2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...

使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度

文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...