Monaco Editor教程(二十):在编辑器的某个特定位置插入自定义的dom内容,图片,表单,表格,视频

news2024/11/28 14:47:18

前言

哇咔咔,这是我的第20篇Monaco教程,写完这一篇会暂时休息一段时间,练练字,存存稿,读读书,顺便修修文章。
目前全网成系统的monaco中文专栏应该只有我这一个,欢迎评论区打脸。自结束了GitLab CI/CD的专栏后,我就一直在利用业余时间学习Monaco相关的知识,一是为了弥补公司项目上的不足,二是看准了这东西以后肯定会大放异彩。不过目前它还是处于VS Code的光彩下。你说vscode大家都知道是啥,你说摩纳哥编辑器,大家就会问你,这是啥玩意。monaco editor是vscode的核心编辑器,vscode就是基于它开发出来的。

说实话,虽然写了20篇文章,但感觉还是只学到了一点皮毛,对于很多特性还没有时间去研究,去思考它们的使用场景,以及如何为项目赋能。 马上过年了,暂时休息一段时间,好好规划一下后面的内容。

在写这一篇文章之前其实有两个选题,一是介绍创建monaco的参数配置,从那100多个配置参数中找几十个常用参数 一一分析他们的作用和使用场景。另一个选题就是在编辑器中插入一下自定义的dom元素,包括实现一个评论区域,表单,弹层。前一个选题对新手很学习很有帮助,网上也有些零碎的文章介绍。后一个选题比较少。这也是我写这篇文章的原因。不为别的,只因很酷。

技术分析

前言写了500多字,在加300字就能当做高考作文了。
今天要解析的功能 是monaco中一个很重要的特性。就是在编辑器中加入一些自定义的dom元素。
如果你的公司使用gitlab 你可能在一个MR中见过这样的操作页面。
在这里插入图片描述
在一个合并请求中,会有一些人对某一行改动的代码添加注释,或者给出建议。当他点击行号左侧的对话框图标时,就会在该行的下方,出现一个评论区域,开发者可以在该区域填写表单,发表评论。
其实这一功能正是借助了monaco的内嵌dom元素来实现的。具体的插入dom元素的方法 至少有三种。
而本文主要讲解二种,IContentWidgetIOverlayWidget

下面看一下,monaco内置的组件。
鼠标左键菜单。
在这里插入图片描述
右上角的查询组件

在这里插入图片描述
自动完成的下拉选项
在这里插入图片描述

在编辑器中,点击鼠标左键出现的菜单项,是一种内置的dom元素,其类型是IContentWidget

IOverlayWidgetIContentWidget 有很多相同点,也有很大的区别点。下面我们就来揭开二者的面纱。使用他们看一让我们的WEB IDE 注入一些奇奇怪怪的东西。如果你想,你可以在输入一个tree单词时,在编辑器中间出现一棵动态的银杏树图片 ,或者你可以在输入一个dog单词后,显示一个拉布拉多犬图片,你甚至可以让它汪汪两声。所以说学会这一功能的使用,你可以在编辑器器中为所欲为。 哈哈。。。

核心方法

IOverlayWidget

我们先来看一下IOverlayWidget 这个接口,该接口的定义位置在这里
描述是 An overlay widgets renders on top of the text. 一个渲染在文本之上的浮窗部件。
(下文统一使用 OverlayWidget来表述)

正如字面意思,它的内容会渲染在编辑器文本之上,例如查找组件就是使用它来完成的。它的内容会遮盖编辑器中的文本。

解释上很好理解,我们看下它的属性有哪些。以及可使用的方法有那些。
OverlayWidget只有三个方法,没有再多的属性,这相比上一篇的CompletionItem类型15个属性,真是让我轻松了不少。

  • getDomNode 用于设置该组件要显示的dom内容,需要返回HTMLElement
  • getId 一个独一无二的组件id,如monaco.fizz.overlaywidget
  • getPosition 组件的显示位置,返回参数的类型为 IOverlayWidgetPosition,内部是一个枚举值,三个待选项,右下角,顶部中心,右上角三个位置可以选。如果返回null,则组件会自己放置自己。

以上是OverlayWidget的定义,我们可以根据定义创建一个自己的部件,如下

const fizzOverlayWidget = {
  getDomNode() {
    const domNode = document.createElement('div')
    domNode.innerHTML = `<p class="import-info">无所谓,我会出手 ${new Date()}</p>`
    domNode.style.background = '#ffc107';
    domNode.style.borderRadius = '4px';
    domNode.style.right = '200px';
    domNode.style.width = '130px';
    domNode.style.padding = '0 8px';
    domNode.style.top = '50px';
    domNode.style.color = '#ff5722'
    return domNode
  },
  getId() {
    return 'monaco.fizz.overlaywidget'
  },
  getPosition() {
    return {
      // preference: monaco.editor.OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER
      // preference: monaco.editor.OverlayWidgetPositionPreference.TOP_CENTER
      preference: monaco.editor.OverlayWidgetPositionPreference.TOP_RIGHT_CORNER
    }
    // return null
  }
}

以上就是OverlayWidget的定义,只需要定义三个参数即可。而且还有一个 getPosition 参数可以为空。
下面我们将自定义的OverlayWidget添加到编辑器,看看是什么效果

有关OverlayWidget的方法有这些。这些方法都在editor下。

  • removeOverlayWidget(widget: IOverlayWidget): void 移除一个OverlayWidget
  • layoutOverlayWidget(widget: IOverlayWidget): void 重新渲染一个OverlayWidget,可以使用它来改变一个OverlayWidget的位置
  • addOverlayWidget(widget: IOverlayWidget): void 添加一个OverlayWidget,组件必须有一个独一无二的id,否则将会变为更新,覆盖现有组件内容。

ok,现在让我们一个一个体验三个方法。

首先是

editor.addOverlayWidget(fizzOverlayWidget)

渲染到右上角
在这里插入图片描述

渲染到顶部中心
在这里插入图片描述

组件的样式表现
在这里插入图片描述
我们通过修改组件显示的位置,来查看不同的表现。
由多次尝试得知,当组件显示的位置为null时,我们可以设置组件的top,left,bottom,right,来自定义组件相对于编辑器的位置。其实使用OverlayWidgetPositionPreference,本质也是相对定位,设置right,bottom。果真是实践出真知。

看完addOverlayWidget方法,在来看一下removeOverlayWidget方法,该方法需要传入一个完整的OverlayWidget。不过既然每个OverlayWidget都有一个id,是不是只设置id就可以了。我们试试。

移除组件时我们直接这样写,只定义getId。

editor.removeOverlayWidget({
  getId() {
    return 'monaco.fizz.overlaywidget'
  },
})

实验之后,果然可以,NBNB。

看完了添加和移除还有一个layoutOverlayWidget方法。
试了一下。
我们首先在编辑器addOverlayWidget一个顶部中间的组件,然后修改该组件getPosition使其指向,右上角,
然后再调用layoutOverlayWidget方法,我们发现,组件的位置确实变了。

editor.layoutOverlayWidget(fizzOverlayWidget)

所以讲,layoutOverlayWidget是可以更新同一id的组件的位置,不能更新内容,不可添加新的组件。
addOverlayWidget可以添加多个同id,不同或相同的组件,可以同时存在。(不知道是不是bug)

IContentWidget

IContentWidget的类型解释在此处可以查看到。
它的解释是A content widget renders inline with the text and can be easily placed 'near' an editor position. 会渲染到编辑器的行内内容组件,并且很容易将其防止在某个固定位置附近。
根据描述我们就知道,相比layoutOverlayWidget只能从三个渲染位置选择,IContentWidget可以渲染到某个固定的位置附近,那么鼠标左键的菜单,自动完成的候选项,都是可以使用该组件完成的。
为了方便描述,下文统一使用ContentWidget

ContentWidget类型有二个属性,五个方法
属性:

  • allowEditorOverflow 是否允许组件溢出编辑器
  • suppressMouseDown 是否支持鼠标按下操作,这是为了不让事件穿透。让用户可以点击组件的dom元素。

方法:

  • afterRender 在渲染组件后,设置组件的显示位置,设置一个枚举值,可以在position的下方,上方,附近显示。
  • beforeRender 设置ContentWidget组件的宽和高,将会被ContentWidget引用。
  • getDomNode 与上面的layoutOverlayWidget组件一样,都是用户设置组件的dom元素,返回HTMLElement
  • getId 组件唯一的id
  • getPosition 组件显示的位置,类型为IContentWidgetPosition(有四个属性position,positionAffinity,preference,range)。

getPosition 中的四个属性:
position(类型IPosition), 组件被放置的坐标
positionAffinity(类型PositionAffinity), 可选参数
preference(类型为ContentWidgetPositionPreference[],可以设置多个枚举值,从三个选项),将组件放置在position的上方还是上方,或者精确的位置。
range,(类型IRange)可选参数,组件更为精确的影响范围。

由定义我们创建一个ContentWidget

const fizzContentWidget = {
  allowEditorOverflow: true,
  suppressMouseDown: false,
  afterRender(position) {
    console.log(position)
  },
  beforeRender() {
    const dimension = {
      height: 200,
      width: 200,
    }
    return dimension
  },
  getDomNode() {
    const domNode = document.createElement('div')
    domNode.innerHTML = `<p class="import-info">无所谓,我会出手</p>`
    domNode.style.background = '#ffc107';
    domNode.style.borderRadius = '4px';
    domNode.style.width = '130px';
    domNode.style.padding = '0 8px';
    domNode.style.color = '#ff5722'
    return domNode
  },
  getId() {
    return 'monaco.fizz.contentwidth'
  },
  getPosition() {
    const contentWidgetPosition = {
      position: {
        column: 0,
        lineNumber: 2
      },
      preference: [
        monaco.editor.ContentWidgetPositionPreference.ABOVE,
        monaco.editor.ContentWidgetPositionPreference.BELOW,
      ],
    }
    return contentWidgetPosition
  },
}

我们设置 position{column: 0,lineNumber: 2},该组件将会在地2行,第0列渲染。
调用editor.addContentWidget(fizzContentWidget) 将会被渲染到页面上。
效果图如下:

在这里插入图片描述

我们看到该组件的内容同样是渲染在文本上层的,并没有渲染在编辑器中,也没有撑开第2行与第3行。
那么在编辑器中添加评论表单,而不用遮挡底部的文本内容,到底应该怎么显示那?

其实这涉及到了另一个API,changeViewZones。这里不展开讲这个API,后续会单独写一篇文章,详细讲解它的使用,与应用场景。
这里我们编写这样一个我们看到该组件的内容同样是渲染在文本上层的,并没有渲染在编辑器中,也没有撑开第2行与第3行。
那么在编辑器中添加评论表单,而不用遮挡底部的文本内容,到底应该怎么显示那?

其实这涉及到了另一个API,changeViewZones。由于该API过于强大,这里不展开讲这个API,后续会单独写一篇文章,详细讲解它的使用与应用场景。
这里我们编写这样一个函数

function addZone(){
  var viewZoneId = null;
  editor.changeViewZones(function (changeAccessor) {
    var domNode = document.createElement('div');
    domNode.style.background = 'lightgreen';
    viewZoneId = changeAccessor.addZone({
      afterLineNumber: 2,
      heightInLines: 3,
      domNode: domNode
    });
  });
}

重点是 afterLineNumber: 2, heightInLines: 3, 他表示,在编辑器中创建一个区域,该区域是在第2行,开始渲染,一共占据3行。这一区域我们可以设置一个dom元素,也可以使用一个ContentWidget来覆盖在上层。
下面让我来看一下这个案例,完整的效果

效果图

在这里插入图片描述

完整代码

<!DOCTYPE html>
<html>

<head>
  <title>Hello World Monaco Editor(CSDN@拿我格子衫来)</title>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
</head>

<body>
  <h2>Hello World Monaco Editor(CSDN@拿我格子衫来)</h2>
  <button onclick="addOverlay()">添加IOverlayWidget</button>
  <button onclick="layoutOverlay()">layout IOverlayWidget</button>
  <button onclick="delOverlayWidget()">移除IOverlayWidget</button>

  <button onclick="addContent()">添加IContentWidget</button>
  <button onclick="layoutContent()">layout IContentWidget</button>
  <button onclick="delContent()">移除IContentWidget</button>

  <button onclick="addZone()">添加留白区域</button>

  <div id="container" style="width: 800px; height: 600px; border: 1px solid grey"></div>

  <script src="./monaco-editor/package/min/vs/loader.js"></script>
  <script src="./const.js"></script>
  <script>
    require.config({ paths: { vs: './monaco-editor/package/min/vs' } });
    let editor;

    require(['vs/editor/editor.main'], function () {
      editor = monaco.editor.create(document.getElementById('container'), {
        value: `
function mo(){
  console.log(12)
}
function fi(){
  console.log(12)
}
function mo(){
  console.log(12)
}
function fi(){
  console.log(12)
}
function mo(){
  console.log(12)
}
function fi(){
  console.log(12)
}
function mo(){
  console.log(12)
}
function fi(){
  console.log(12)
}
function mo(){
  console.log(12)
}
function fi(){
  console.log(12)
}
function mo(){
  console.log(12)
}
function fi(){
  console.log(12)
}
function mo(){
  console.log(12)
}
function fi(){
  console.log(12)
}
function fi(){
  console.log(12)
}
function mo(){
  console.log(12)
}
function fi(){
  console.log(12)
}
  `,
        language: 'javascript'
      });


    });

    function addOverlay() {
      editor.addOverlayWidget(createOverlayWidget())
    }

    function layoutOverlay() {
      const lay = createOverlayWidget()
      lay.getPosition = () => {
        return { preference: monaco.editor.OverlayWidgetPositionPreference.TOP_RIGHT_CORNER }
      }
      lay.getDomNode = () => {
        const domNode = document.createElement('div')
        domNode.innerHTML = `<p class="import-info">无所谓,我会出手${new Date()}</p>`
        return domNode
      }
      editor.layoutOverlayWidget(lay)
      // editor.addOverlayWidget(lay)
    }

    function createOverlayWidget() {
      const fizzOverlayWidget = {
        getDomNode() {
          const domNode = document.createElement('div')
          domNode.innerHTML = `<p class="import-info">无所谓,我会出手</p>`
          domNode.style.background = '#ffc107';
          domNode.style.borderRadius = '4px';
          domNode.style.right = '200px';
          domNode.style.width = '130px';
          domNode.style.padding = '0 8px';
          domNode.style.top = '50px';
          domNode.style.color = '#ff5722'
          return domNode
        },
        getId() {
          return 'monaco.fizz.overlaywidget'
        },
        getPosition() {
          // return {
          //   // preference: monaco.editor.OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER
          //   preference: monaco.editor.OverlayWidgetPositionPreference.TOP_CENTER
          //   // preference: monaco.editor.OverlayWidgetPositionPreference.TOP_RIGHT_CORNER
          // }
          return null
        }
      }
      return fizzOverlayWidget
    }


    function delOverlayWidget() {
      editor.removeOverlayWidget({
        getId() {
          return 'monaco.fizz.overlaywidget'
        },
      })
    }

    const fizzContentWidget = {
      allowEditorOverflow: true,
      suppressMouseDown: false,
      afterRender(position) {
        console.log(position)
      },
      beforeRender() {
        const dimension = {
          height: 200,
          width: 200,
        }
        return dimension
      },
      getDomNode() {
        const domNode = document.createElement('div')
        domNode.innerHTML = `<p class="import-info">无所谓,我会出手</p>`
        domNode.style.background = '#ffc107';
        domNode.style.borderRadius = '4px';
        domNode.style.width = '130px';
        domNode.style.padding = '0 8px';
        domNode.style.color = '#ff5722'
        return domNode
      },
      getId() {
        return 'monaco.fizz.contentwidth'
      },
      getPosition() {
        const contentWidgetPosition = {
          position: {
            column: 0,
            lineNumber: 2
          },
          preference: [
            monaco.editor.ContentWidgetPositionPreference.ABOVE,
            monaco.editor.ContentWidgetPositionPreference.BELOW,
          ],
        }
        return contentWidgetPosition
      },
    }

    function addContent() {
      editor.addContentWidget(fizzContentWidget)
    }

    function layoutContent() {
      fizzContentWidget.getPosition = () => {
        const contentWidgetPosition = {
          position: {
            column: 0,
            lineNumber: 4
          },
          preference: [
            monaco.editor.ContentWidgetPositionPreference.ABOVE,
            monaco.editor.ContentWidgetPositionPreference.BELOW,
          ],
        }
        return contentWidgetPosition
      }

      editor.layoutContentWidget(fizzContentWidget)
    }


    function delContent() {
      editor.removeContentWidget({
        getId() {
          return 'monaco.fizz.contentwidth'
        },
      })
    }

    function addZone() {
      var viewZoneId = null;
      editor.changeViewZones(function (changeAccessor) {
        var domNode = document.createElement('div');
        domNode.style.background = 'lightgreen';
        viewZoneId = changeAccessor.addZone({
          afterLineNumber: 2,
          heightInLines: 3,
          domNode: domNode
        });
      });
    }

  </script>
</body>

</html>

后记

monaco的东西还有很多,让我们慢慢到来。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

面试题------线程池的拒绝策略

面试题------线程池的拒绝策略 线程池有7个核心参数 1.核心线程数 2.最大线程数 3.非核心线程存活时间 4.存活时间的单位 5.工作队列 6.线程自定义的一些配置 7.拒绝策略&#xff08;当达到最大线程数、且工作队列也满了会执行拒绝策略&#xff09; public ThreadPoolExecutor…

马上2023年了,学一下gradle(Gradle)安装及配置

Gradle学习 例如&#xff1a;相信已经很多公司在用了&#xff0c;但是小伙伴对此还是很模糊 文章目录Gradle学习Gradle一、Gradle介绍&#xff1f;二、常见的项目构建工具gradle安装1.下载2. 配置&#xff08;环境变量&#xff09;2.1打开环境变量2.2**新建环境变量**2.3在Pat…

【C++】STL—vector的常用接口

文章目录前言一、vector介绍二、vector的使用1. vector的定义2. vector的遍历2.1.operator[ ]2.2.迭代器2.3.范围for3. vector的空间增长问题3.1.size和capacity3.2.max_size和empty3.3.reserve3.4.resize3.5.Shrink to fit4. vector的增删查改4.1.push_back和pop_backinsert和…

Vue 3的高颜值UI组件库

Vue 3.0 已经发布两年多的时间&#xff0c;今年 2 月 Vue 3.0 也正式成为新的默认版本。今天就来分享 7 个适用于 Vue 3 的高颜值 UI 组件库&#xff01; Element Plus Element Plus 是一套由饿了么开源出品的为开发者、设计师和产品经理准备的基于 Vue 3.0 的组件库。Elemen…

【能源管理】制造行业中汽车厂房综合能效管理平台应用分析

安科瑞 李亚俊 平台概述 壹捌柒贰壹零玖捌柒伍柒AcrelEMS-EV汽车厂房能效管理平台集变电站综合自动化、电力监控、电气安全、电能质量分析及治理、能耗管理、能效分析、照明控制、充电桩运营管理、设备运维于一体&#xff0c;为建立可靠、安全的工厂能源管理体系提供数据支持…

【Flink】处理迟到元素(续)、自定义水位线和多流的合并与合流

文章目录一 处理迟到元素1 处理策略&#xff08;3&#xff09;使用迟到元素更新窗口计算结果a 代码编写b 测试二 自定义水位线1 产生水位线的接口2 自定义水位线的产生逻辑三 多流的合流与分流1 union算子2 水位线传递规则&#xff08;1&#xff09; 分流a 代码编写b 测试&…

virtio-net 实现机制【二】(图文并茂)

4. virio-net前端驱动分析 4.1 重要数据结构 4.1.1 send_queue结构 send_queue结构是对virtqueue的封装&#xff0c;是virtio-net的发送队列&#xff0c;即数据流向从前端驱动&#xff08;Guest&#xff09;到后端驱动&#xff08;Host&#xff09; 4.1.2 receive_queue结构…

【PlasticSCM Could Edition】新版本云托管浅试2

【PlasticSCM Could Edition】新版本云托管浅试2首先修复更改托管提一嘴首先 建议还是使用 PlasticHub&#xff0c;不要去用 PlasticSCM Cloud 原因&#xff1a; 由于比较新&#xff0c;伴随着的就是 —— 太多 bigs 了&#xff01;而且不知道怎么去改。 当时我创建了一个…

数据结构复习

期末的一套模拟题&#xff0c;仅供参考&#xff0c;切莫作为期末考试依据&#xff01;&#xff01;&#xff01; 选择题 数组A[1..5,1..6]每个元素占5个单元&#xff0c;将其按行优先次序存储在起始地址为1000的连续的内存单元中&#xff0c;则元素A[5,5]的地址为&#xff1a;…

轻量应用服务器部署vue项目

首先我已经拥有一个轻量云服务器了.windows2012的版本&#xff1a; 1.搭建 FTP 服务 为了将我们打包好的vue项目传到服务器&#xff0c;我们要先在服务器搭建FTP服务。 具体步骤可以参考官方文档&#xff0c;官方文档的教程十分清楚详细&#xff0c;按照步骤来就不会出错&am…

传奇服务端服务端运行7个窗口的各窗口功能讲解

大家都知道打开传奇版本里的游戏引擎后&#xff0c;就会弹出7各窗口&#xff0c;下面给大家讲解下各窗口的功能定义 GameCenter是游戏服务器启动程序&#xff0c;负责将DBServer.exe处转来的客户 端转发到相应的M2Server.exe。 DBServer.exe是用户数据库服务器&#xff0c;负责…

Allure与Jenkins持续集成

目标&#xff1a;每次提交代码到代码托管平台&#xff08;gitee&#xff09;&#xff0c;自动触发jenkins项目构建&#xff0c;生成allure测试报告&#xff0c;并发送邮件通知。 1、部署jenkins Jenkins — 快速入门 2、配置Gitee &#xff08;1&#xff09;Plugin Manager&…

01_openstack概述

一、openstack起源 Openstack是一个由NASA(美国国家航空航天局)和Rackspace合作研发并发起的项目Openstack是一套IaaS解决方案Openstack是一个开源的云计算管理平台以Apache许可证为授权二、Openstack七大组件 1、Horizaon组件 Horizon为Openstack服务的Web控制面板&#xff…

leecode#用Read4读取n个字符#相交链表

题目描述&#xff1a; 给你一个文件&#xff0c;并且该文件只能通过给定的 read4 方法来读取&#xff0c;请实现一个方法使其能够读取 n 个字符。 分析&#xff1a; read4 方法&#xff1a;API read4 可以从文件中读取 4 个连续的字符&#xff0c;并且将它们写入缓存数组 buf…

为什么电脑运行越来越慢?解决方法又是什么呢?

文章目录为什么电脑运行越来越慢&#xff1f;解决方法又是什么呢&#xff1f;一&#xff0c;电脑运行慢的原因二&#xff0c;提高电脑运行速度的方法1&#xff0c;重启电脑2&#xff0c;还原&#xff08;重置&#xff09;操作系统3&#xff0c;关闭不使用的应用程序4&#xff0…

CrossOver2023Win电脑软件操作在Mac、Linux系统运行教程

在Mac系统中一直存在一个比较令用户们头疼的问题&#xff0c;那就是安装不了想要的Windows软件。如果使用的第一台电脑就是MacBook那接触到的Windows软件想必并不是很多。但我们中的大多数人都是从小先学习了Windows的操作系统&#xff0c;再过渡到Mac系统上的。 那有小伙伴会…

面试:插件化相关---service

插件service启动分析 同样的&#xff0c;先来看看service的常规启动流程 调用contextimpl.startService/bindService/stopService -> AMS&#xff0c;AMS对应创建ServiceRecord和token后&#xff0c;通知ActivityThreadActivityThread收到startService后&#xff0c;会创建…

少儿编程 电子学会图形化编程等级考试Scratch一级真题解析(选择题)2022年9月

2022年9月scratch一级真题解析 选择题(共25题,每题2分,共50分) 1、点击绿旗,下列哪个选项可以实现播放马叫声并在声音全部播放完后,马向右移动 A、 B、 C、 D、

[附源码]计算机毕业设计JAVA小说网站的设计与实现1

[附源码]计算机毕业设计JAVA小说网站的设计与实现1 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM m…

基于RV1126 Video分析-----链接 isp 与mipi csi 的media模块

从前文&#xff1a;<<图像处理模块所代表的V4L2设备注册>> 中了解到。rkcif_mipi设备注册的过程就是以设备通知器为线索&#xff0c;从顶向下&#xff0c;依次找到下一级设备&#xff0c;添加到V4L2设备种&#xff0c;循环处理。将全部的子设备整理到 V4L2设备中&a…