持续更新中...

一、简单介绍

以下有什么不恰当的地方还请多多指教,因为公司业务需求,被迫看了浅学习了一下antv-g6,之前一直使用Echarts,感觉Echarts就很好用,可是看过g6之后,觉得确实很漂亮,而且也能实现一些业务中比较变态的要求。接下来我就从我刚入手的角度,谈一下自己的心得体会。

二、安装引用(两种方式,建议第一种)

1.在项目中直接NPM包引入

Step 1: 使用命令行在项目目录下执行以下命令:

npm install --save @antv/g6

Step 2: 在需要用的 G6 的 JS 文件中导入:

import G6 from '@antv/g6';

2. 在 HTML 中使用  CDN 引入

// version <= 3.2
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-{$version}/build/g6.js"></script>// version >= 3.3
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/{$version}/dist/g6.min.js"></script>// version >= 4.0
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script>

三、简单的树图

这里我直接用在项目中的自己写的一个简单的树图,通过各个属性来延伸一下其他的属性。这里对每个属性进行了简单的注释,当然也不是全部的,只是一些最常用到的属性,其他具体的属性可以看antv的官方文档。

Step1:创建一个容器
<div id="g6Box"></div>Step2:数据结构(数据结构就是tree结构)
data: {id: "1",label: '老大(最外层)',"children": [{"id": "1-1",label: '第二层1',},{"id": "1-2",label: '第二层2',},{"id": "1-3",label: '第二层3',},{"id": "1-4",label: '第二层4',},{"id": "1-5",label: '第二层5',"children": [{"id": "1-5-1",label: '第三层1',children: [{"id": "1-5-1-1",label: '第四层1'},{"id": "1-5-1-2",label: '第四层2'},{"id": "1-5-1-3",label: '第四层3'}]},{"id": "1-5-2",label: '第三层2',children: [{"id": "1-5-2-1",label: '第四层4'},{"id": "1-5-2-2",label: '第四层5'}]},{"id": "1-5-3",label: '第三层3',children: [{"id": "1-5-3-1",label: '第四层6'},{"id": "1-5-3-2",label: '第四层7'},{"id": "1-5-3-3",label: '第四层8'},{"id": "1-5-3-4",label: '第四层9'},{"id": "1-5-3-5",label: '第四层10'}]},{"id": "1-5-4",label: '第三层4',children:[{"id": "1-5-4-1",label: '第四层11'},{"id": "1-5-4-2",label: '第四层12'},{"id": "1-5-4-3",label: '第四层13'},{"id": "1-5-4-4",label: '第四层14'}]}]},{"id": "1-6",label: '第二层6'}]}Step3:节点、线的修改,数据配置,渲染
initTree (data) {// 定义画布的宽高const width = document.getElementById('g6Box').scrollWidth || 800;const height = document.getElementById('g6Box').scrollHeight || 800;// 实例化G6  // 因为我们用的是树图,所以这里是G6.TreeGraph(),还有其他,像是普通图的配置G6.Graph(),一般y用的比较多的就像是树图这种,还有组织架构图一类的。const graph = new G6.TreeGraph({// 图的  DOM 容器,对应上面我们定义的idcontainer: 'g6Box',width,height,// 是否开启画布自适应。开启后图自动适配画布大小。fitView: true,// fitView 为 true 时生效。图适应画布时,指定四周的留白。可以是数组,fitViewPadding: [ 20, 40, 50, 20 ]fitViewPadding: 10,// v3.5.1 后支持。开启后,图将会被平移,图的中心将对齐到画布中心,但不缩放。优先级低于 fitView。fitCenter: true,// 最小缩放比例// minZoom: 1.5,// 最大缩放比例maxZoom: 1.5,// 指定边是否连入节点的中心linkCenter: false,// 设置画布的交互模式modes: {default: [{// 只适用于树图,展开或收起子树type: 'collapse-expand',// trigger:收起和展开节点分组的方式。支持 'click' 和 'dblclick' 两种方式。默认为 'dblclick',即双击。trigger: 'click',},// 拖拽画布'drag-canvas',// 缩放画布'zoom-canvas',],},// 配置节点的属性defaultNode: {// 节点类型,cicle:圆形,rect:矩形,ellipse:椭圆,diamond:菱形,triangle:三角形,star:五角星,image:图片,modelRect:卡片type: 'rect',// size 设置矩形的长和宽size: [120, 34],// 指定边连入节点的连接点的位置,可以为空,具体可以看一下官网是通过0、0.5、1来控制哪个点的。anchorPoints: [[0, 0.5],[1, 0.5]],// 节点样式style: {// 节点填充色fill: '#DDE2E9',// 节点的描边颜色。stroke: '',// 阴影颜色shadowColor: '#f00',// 阴影范围shadowBlur: 5,// 鼠标经过是的形状,跟css是一样的。cursor:'pointer',// 圆角radius: 4,},// 配置节点中的文字。labelCfg: {// 节点文字位置// position: 'top',// 偏移量// offset: 5,// 标签的样式属性。style: {// 文本颜色fill: '#535D79',// 文本字体大小fontSize: 14,},},// 文本文字 (如果自定义节点了或者用graph.node()配置了节点,这里不生效,因为那两种优先级更高,下面的边也是一样)label: 'node-label'},// 配置边的属性defaultEdge: {// 指定边的类型,可以是内置边的类型名称,也可以是自定义边的名称。// line:直线,polyline:折线,arc:圆弧线,quadratic:二阶贝塞尔曲线,cubic:三阶贝塞尔曲线,cubic-vertica:垂直方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点。cubic-horizontal:水平方向的三阶贝塞尔曲线,不考虑用户从外部传入的控制点。loop:自环type: 'cubic-horizontal',// 边的样式属性style: {// 边的颜色stroke: '#A3B1BF',// 边的宽度lineWidth: 5,// 边是否带箭头endArrow:true,},// 配置边上文本的属性labelCfg: {// 文本相对于边的位置,目前支持的位置有:'start','middle','end'。默认为'middle'。position: 'middle',// 标签文字是否跟随边旋转autoRotate: true,style: { //     文本颜色fill: '#f00'}},// 文本文字 (如果自定义节点了或者用graph.edge()配置了节点,这里不生效,因为那两种优先级更高)label: '边'},// 布局配置项layout: {// 布局名称,这个可就太多了,这个只是树图结构中的一种。比如还有compactBox:紧凑树布局,dendrogram:生态树布局,indented:缩紧树布局。type: 'mindmap', // 脑图树布局direction: 'H', // H / V / LR / RL / TB / BT 这些是控制节点分布位置,从左往右、从右往左、从中间往上下延伸、从中间往左右延伸...具体可以看官网// 节点 id 的回调函数getId: function getId(d) {return d.id;},// 下面都是一些控制节点与节点间距离的回调函数,具体可以试着修改一下值。// 节点高度的回调函数getHeight: function getHeight() {return 16;},// 节点宽度的回调函数getWidth: function getWidth() {return 16;},// 节点纵向间距的回调函数// getVGap: function getVGap() {//   return 50;// },// 节点横向间距的回调函数getHGap: function getHGap(val) {return 100;},},// 动画属性animate: true,});// 设置各个节点样式及其他配置,该方法必须在 render 之前调用,否则不起作用,必须要 return。// 如果节点不满足自己的需求,可以在这里设置想要的节点样式,这只是其中的一种,后面还会介绍功能更加全面的自定义节点。graph.node(function (node) {if (node.id === '1-6' || node.id === '1-1') {return {labelCfg: {style: {fill: '#fff',},},style: {fill: '#946DFF',}}}return true});// 设置边的属性及其他配置,跟上面设置节点一样,这里设置了,上面defaultEdge里面设置的边不管写什么都不会生效,因为这个的优先级要比上面的defaultEdge优先级高。// 也可以通过判断来实现不同边的样式、文字等,后面也会介绍更加全面的自定义边。graph.edge(function(node) {return {label: '边'}})// 初始化的图数据graph.data(data);// 根据提供的数据渲染视图。graph.render();// 让画布内容适应视口graph.fitView();},

四、自定义节点

本以为直接按照官网的图标示例,再稍微看一下一些属性就能搞定,但是后来发现不只是这一种简单的可以直接实现的g6图,有个不仅仅只是简单的节点里面是文字,有的节点里面还会有很多不同文字、icon图标、图片等等。这就需要能实现更多功能的自定义节点。(自定义节点和自定义边基本一样,这里具体介绍自定义节点的使用。)

先来看一下官方给的自定义节点说明:

先简单介绍一下,写的其实很详细了,'nodeName'就是自定义节点的名称,要跟下面defaultNode中的type保持一致,这里写什么,下面就要写什么,后面会在代码中体现的。draw(cfg, group){ },绘制节点的主要就用这个东西,也主要介绍这个的用法,剩下的那几个我也没用到,主要是当数据源改变的时候,更新节点的吧。具体没用过...

// 自定义节点G6.registerNode('rectNode',{draw: (cfg, group) => {// 节点宽度function nodeWidth (node) {if (node.id === '1') {return 200}return 150}// 节点高度function nodeHeight (node) {if (node.id === '1') {return 40}return 70}// 最外层的节点--盒子// group.addShape 就是增加一个节点,第一个值可选值有circle、rect、ellipse、polygon、fan、image、marker、path、text、dom,用的最多的应该就是circle、rect、path、text,这里dom比较特殊,后面单独讲一下。const shape = group.addShape('rect', {draggable: true, // 该图形分组是否允许被拖拽attrs: {// 这是控制节点的宽和高,因为不是所有的节点不是一样大的,就写了两个函数来控制一下,这里可以根据自己的要求来自己用函数来控制。width: nodeWidth(cfg),height: nodeHeight(cfg),fill: cfg.id === '1' ? '#4570FF' : '#fff', // 节点填充色stroke: '#B1BDCE', // 边框颜色radius: 4, // 圆角}})// 自定义节点中的文字,因为是文字,所以是type是textgroup.addShape('text', {attrs: {textAlign: 'center', // 文字相对于节点的位置// x,y是控制文字的更加精确的位置y: cfg.id === '1' ? 25 : 40, x: cfg.id === '1' ? 110 : 70,lineHeight: 15, // 自定义文字行高fontSize:11,    // 文字大小text: cfg.label, // 根据后端字段名来显示的文字,这个上下文中的cfg就是每个节点中的所有属性。fill: cfg.id === '1' ? '#fff' : '#000' // 文字颜色}})// 添加dom,比较特殊,后面讲group.addShape('dom',{attrs: {x: -cfg.x + 10,y: -cfg.y - 50,width: 20,height: 20,html:cfg.id === '1' ? '<em class="iconfont iconshouye-shouye" style="color: #fff;" />': ''},name: 'image-shape',})return shape}})const graph = new G6.TreeGraph({defaultNode: {type: 'rectNode', // 这个名要跟上面自己定义的保持一致,之前写过的下面的一些控制节点的属性也可以直接在上面自定义节点里面写。},
})

五、自定义边

自定义边和自定义节点基本是一致的,只要能懂上面的自定义节点,照猫画虎是一样的,直接上代码。

// 自定义边G6.registerEdge('regEdge',{draw: (cfg, group) => {const startPoint = cfg.startPoint;const endPoint = cfg.endPoint;const shape = group.addShape('path', {attrs: {stroke: '#B1BDCE', // 边的颜色// 这个path是来调节边的高度和长度的,因为这里我用的是折线,所以它有个起始点、结束点、还有两个转折的地方,就是一点一点的调的,哈哈。path: [["M", startPoint.x, startPoint.y],["L", startPoint.x, (startPoint.y + endPoint.y) / 2.3],["L", endPoint.x, (startPoint.y + endPoint.y) / 2.3],["L", endPoint.x, endPoint.y],]},name: 'path-shape',});// 这里可以控制边上的描述文字,以及在边上的位置,下面也是一样,因为有两个描述信息,具体可以看官网更加详细的属性配置。group.addShape('text',{attrs: {text: cfg.targetNode['_cfg'].model.text,x: endPoint.x -5,y: endPoint.y - startPoint.y/2 - 10,fill: '#4570FF',textAlign: 'right',},name: 'text-shape',})group.addShape('text',{attrs: {text: cfg.targetNode['_cfg'].model.rate,x: endPoint.x +5,y: endPoint.y - startPoint.y/2 - 10,fill: '#4570FF',textAlign: 'left',},name: 'text-shape',})return shape;},}) const graph = new G6.TreeGraph({defaultNode: {type: 'regEdge', // 这个名要跟上面自己定义的保持一致,之前写过的下面的一些控制边的属性也可以直接在上面自定义边里面写。},
})

六、自定义节点中的特殊类型—dom

项目中遇到在节点中要加入icon图标,就是阿里巴巴图标库中的那种图标,然后要想加这种就要直接给它加个dom,但是js中又无法直接写个标签给它加上,后来才发现自定义节点中有个dom类型,然后就觉得这个问题解决了,但是加上不好使,又去antvg6去看官方文档,人家清清楚楚的写着要加一个属性才能用这个自定义节点的dom...

// 还记得上面自定义节点中的dom节点嘛,如果不加下面这行代码,是报错的。const graph = new G6.TreeGraph({renderer: 'svg',
})

除了用自定义节点dom来实现,其实官方有自带的icon属性,不过也不是全部的节点都可以用的,一起来看一下。

官方给的节点类型是有下面这些:

每一个节点类型都有对应的配置项说明,只有官方让用icon属性的才可以用icon图标,总结了一下能用的有circle、ellipse、diamond、triangle、star、dount这几种类型

// 定义节点
graph.node(function(node) {type: '', // circle、ellipse、diamond、triangle、star、dount这里面的才可以icon: {show: true, // 是否开启fontFamily: 'iconfont', // 对应css里面的font-family: "iconfont"text: '\ue73b', // 对应iconfont.css 里面的content,注意加ufill: '#fff', // 填充色width: 45,height: 45,fontSize: 25 // icon大小}
})

七、同一级数据控制左(上)右(下)的节点个数

当children中有很多同一级的数据时,我们又想让它们左右或者上下分类显示,之前想的是用自定义节点来实现,但是要控制每一个的位置,感觉不好实现就没尝试,最后通过看文档,找到了一个切合这个实际的属性,来看一下代码。

// 数据结构
{id: '1',label: '春天花花幼儿园分园',children: [{id: '1-1',label: '我在左边',state: 'child-left'},{id: '1-2',label: '我在左边',state: 'child-left'},{id: '1-3',label: '我在左边',state: 'child-left'},{id: '1-4',label: '我是右边的'},{id: '1-5',label: '我是右边的'},{id: '1-6',label: '我是右边的'},{id: '1-7',label: '我在左边',state: 'child-left'},{id: '1-8',label: '我是右边的'},{id: '1-9',label: '我是右边的'},{id: '1-10',label: '我是右边的'}]
}
// 这里其他的属性还是参考上面,只写控制左右的属性
const graph = new G6.TreeGraph({layout: {type: 'mindmap',direction: 'H',getId: function getId (d) {return d.id},getHeight: function getHeight () {return 20},getWidth: function getWidth () {return 10},getVGap: () => {return 15},getHGap: function getHGap () {return 160},// 这个getSide就是控制节点位置的属性了,通过数据结构中定义的值做判断,来控制左右,注意的是这个官方写的只能return 'left'和'right',当我们的树结构是竖着的呢?难道是用top和bottom?这里我也试过了,用top和bottom是不好使的,因为人家官方确确实实的只有left和right,通过尝试,其实left就对应top,right对应bottom,所以要控制节点在上面就写left,在下面就写right。getSide: (node) => {if(node.data.state === 'child-left') {return 'left'}return 'right'}},
})

这个getSide就是控制节点位置的属性了,通过数据结构中定义的值做判断,来控制左右,注意的是这个官方写的只能return 'left'和'right',当我们的树结构是竖着的呢?难道是用top和bottom?这里我也试过了,用top和bottom是不好使的,因为人家官方确确实实的只有left和right,通过尝试,其实left就对应top,right对应bottom,所以要控制节点在上面就写left,在下面就写right。

八、从外面拿到graph实例对象,并实现操作方法

从官方文档可以看到,g6的方法乱七八糟一大堆,在绘制canvas之前,我们可以运用里面的方法实现自己想要的效果,但是当外面有个独立的按钮,我们想在外面操作里面的各个节点该怎么做呢?接下来就一起来看一下吧。


<button @click="clickBtn">点击</button>data() {return {// 随便自定义一个名字canvasGraph: '',}
},
methods:{clickBtn(){// 拿到graph就可以用官网提供的一些操作元素的方法了,还有整体渲染的各种方法,可以自己尝试一下console.log(this.canvasGraph)},initG6(data) {// 实例化g6const graph = new G6.TreeGraph({container: 'container',width,height,fitView: true,fitCenter: true,maxZoom: 1.1,minZoom: 0.5,linkCenter: false,// renderer: 'svg',fitViewPadding: 5,modes: {default: []},defaultNode: {anchorPoints: [[0, 0.5],[1, 0.5]]},defaultEdge: {},layout: {}})// 操作节点graph.node((node) => {})// 这里从data中自定义一个属性,在渲染之前把graph直接赋值给它this.canvasGraph = graphgraph.data(data)grapg.render()}
}

九、官方提供的一些常用的方法

1、当节点中的文本太长超出节点时,一开始我是自己写了个函数,来实现文本的换行,后来发现文档中有处理文本太长的示例。传入的参数str—文本,maxWidth—节点盒子宽度,fontSize—文本尺寸。

一般配合鼠标指向弹出层使用——Tooltip,这也是官方提供的一个插件。例如还有Legend图例插件,Grid在画布绘制网格,Menu配置节点上的右击菜单,ToolBar,Fisheye鱼眼放大镜···

// 处理超长文本的函数  可根据自己的需求进行加工处理~
function labelLength (str, maxWidth, fontSize) {const ellipsis = '...'const ellipsisLength = G6.Util.getTextSize(ellipsis, fontSize)[0]let currentWidth = 0let res = strconst pattern = new RegExp('[\u4E00-\u9FA5]+')str.split('').forEach((letter, i) => {if (currentWidth > maxWidth - ellipsisLength) returnif (pattern.test(letter)) {currentWidth += fontSize} else {currentWidth += G6.Util.getLetterWidth(letter, fontSize)}if (currentWidth > maxWidth - ellipsisLength) {res = `${str.substr(0, i)}${ellipsis}`}})return res
}
// <1> 在实例对象的直接使用,内置的Behaviorconst graph = new G6.Graph({container: 'mountNode',width: 500,height: 500,modes: {default: [{// 节点文本提示type: 'tooltip',// 格式化函数,可以返回文本或者 HTMLformatText(model) {return model.label;},// tooltip 距离鼠标的偏移量offset: 10,// 是否允许 toolip 出现,此处可以判断父节点不出现,只让子节点出现shouldBegin(e) {},// 是否允许 toolip 内容更新shouldUpdate(e) {}},],},
});// <2> 自定义Tooltipconst tooltip = new G6.Tooltip({offsetX: 10,offsetY: 20,getContent(e) {const outDiv = document.createElement('div');outDiv.style.width = '180px';outDiv.innerHTML = `<h4>自定义tooltip</h4><ul><li>Label: ${e.item.getModel().label || e.item.getModel().id}</li></ul>`return outDiv},itemTypes: ['node']
});const graph = new G6.Graph({//... 其他配置项container: 'mountNode',width: 500,height: 500,plugins: [tooltip], // 配置 Tooltip 插件
});

自定义Tooltip的配置项:

2、再带图片下载的方法,直接通过实例对象来实现canvas的下载。
      也可将画布上的元素自动生成url然后实现下载~

3、通过不同文字的长短,自动适配节点盒子的宽度。(G6.Util.getTextSize这个方法会自动根据文字长短计算出需要节点的宽度和高度)
     根据字体大小获取单个字母的宽度。(G6.Util.getLetterWidth这个方法会根据字体大小计算出单个字母的宽度)

// str是节点文字,fontSize是节点字体大小
let width = G6.Util.getTextSize(str, fontSize)[0]// 根据字体大小获取单个字母的宽度
let oneStrWidth = G6.Util.getLetterWidth(str, fontSize)

总结

今天就介绍这些了,还有好多坑,以后遇到了会继续补充。本人也是第一次用antvG6这个组件库,也是把自己的一点点微不足道的认识写一下,但是还有很多需要尝试的,欢迎大佬们也留下自己的看法。

持续更新中...

vue antvG6树图的摸索总结—新手入门相关推荐

  1. 新手入门指导:Vue 2.0 的建议学习顺序

    起步 1. 扎实的 JavaScript / HTML / CSS 基本功.这是前置条件. 2. 通读官方教程 (guide) 的基础篇.不要用任何构建工具,就只用最简单的 <script> ...

  2. vue antvG6 多功能tree图 树图树结构

    vue antvG6 多功能tree图 树图树结构 效果展示 代码环境 tree图页代码 效果展示 antvg6 树结构效果图 antvg6 tree图搜索节点 antvg6 tree图显示时间,状态 ...

  3. Nokia Lumia(WP7.5) 新手入门的摸索

    什么是吊丝? 吊丝就是在WP8发布会之后买了WP7! 使用了几天,还在适应WP中,暂无越狱打算-- 如果你目前使用MS的office/MSN/Hotmail(Outlook)/SkyDrive,那你真 ...

  4. php网站入门鹿泉银山,01PHP编程新手入门第一步

    01PHP编程新手入门第一步 很多时候刚入手不知道从哪里下手.这个时候选择一些课程是最好的方法,自己摸索半天可能比不过别人5分钟讲解.就编程而言: 1:有个地方存储程序和数据库 可以选择云服务器,也可 ...

  5. Vue2.0 新手入门 — 从环境搭建到发布

    什么是 Vue.js? Vue.js 是用于构建交互式的 Web 界面的库. Vue.js 提供了 MVVM 数据绑定和一个可组合的组件系统,具有简单.灵活的 API. 本章节是关于 Vue1.x 版 ...

  6. Android新手入门,怎样才是正确的学习方式

    对于android新手入门,遇到的学习瓶颈和困难是无限大的,新手入门,没有一个好学的学习方向,没有一个学习规划,更多的则是在百度上搜索,查阅相关资料,如果没有辅导,纯粹就是瞎摸索.百度上面搜索资料,更 ...

  7. Node.js 新手入门

    Node.js 新手入门 Node.js是运行在服务端的JavaScript运行环境(runtime).实际上它是对Google V8引擎进行了封装.V8引 擎执行Javascript的速度非常快,性 ...

  8. 《挑战30天C++入门极限》新手入门:C/C++中枚举类型(enum)

        新手入门:C/C++中枚举类型(enum) 如果一个变量你需要几种可能存在的值,那么就可以被定义成为枚举类型.之所以叫枚举就是说将变量或者叫对象可能存在的情况也可以说是可能的值一一例举出来. ...

  9. LINUX新手入门-1.装系统

    LINUX新手入门-1.装系统 首先我们用虚拟机模拟 装linux系统,然后下一步下一步,然后完成后,编辑一些设置,把镜像放上面就可以了 选第一项,安装系统,查看镜像是否能运行,直接跳过,选择语言 和 ...

最新文章

  1. python tk text scrollbar_tk.Scrollbar控件的使用
  2. Flutter 仿掘金之动态Tabbar
  3. 靠,上班打游戏!不,我只是在Minecraft里管理Kubernetes...
  4. php.ini在哪里 微赞_Php.ini文件位置在哪里 Php.ini文件找不到
  5. Java中弹出对话框的方法
  6. Android开发之高德地图无法显示地图的原因
  7. Vue中 $ref 的用法
  8. jstat gc各参数含义
  9. OC基础1:一些基本概念
  10. Ecliplse安装tomcat插件
  11. 按键精灵修改计算机名,最新按键精灵脚本代码大全 按键精灵命令运行方法
  12. malloc函数说明
  13. 关于/etc/login.defs
  14. 三个臭皮匠赛过诸葛亮!白话Blending和Bagging
  15. 车牌号合法性校验正则表达式(含新能源车牌)
  16. 机器人运动学---雅克比矩阵伪逆
  17. @Aspect注解使用场景
  18. React 函数组件导出自定义方法的办法说明
  19. c++实训 选猴子当大王
  20. 欧盟CE法规及标准查询常用网站

热门文章

  1. 【学习笔记】倍增 + 二分
  2. 保底掉落装备matlab,强化保底上线?这些增加强化几率的道具也别忘记使用
  3. Xposed Android hook框架入门 -开发步骤
  4. BAT、TMD薪资级别,公司福利
  5. 已解决ERROR: Cannot find command ‘git’- do you have ‘git’ installed and in your PATH?
  6. 让chatGPT 作为 面试官 / 辩手 / 演说家 / 哲学家 / SQL终端的 Prompt 命令
  7. 证件号通用脱敏、名称脱敏
  8. linux kangle漏洞,Kangle EP漏洞:多个EP主机可重复绑定域名,挂黑页的bug解析
  9. 狄克斯特拉(Dijkstra)算法求一个顶点到其余各个顶点的最短路径
  10. 【LuatOS-sensor】4 色彩识别传感器TCS34725