一. Cytoscape.js简介与安装

1.1 Cytoscape.js是什么?

cytoscape.js是一个做网页可视化的常用工具 。cytoscape.js包含图论模型和可选的渲染器,用于显示交互式图形。该库旨在使程序员和科学家尽可能轻松地在他们的应用程序中使用图形理论,无论是用于Node.js应用程序中的服务器端分析还是用于丰富的用户界面。

1.2 Cytoscape.js安装及HelloWorld

1.2.1 使用包管理工具进行安装

  • npm : npm install cytoscape
  • bower : bower install cytoscape
  • jspm : jspm install npm:cytoscape

1.2.2 使用Script标签直接引入

<script src="cytoscape.min.js"></script>

1.2.3 HelloWorld

var cy = cytoscape({container: document.getElementById('cy') // container to render in
});
也可以给container传递jQuery实例
var cy = cytoscape({container: $('#cy')
});

1.2.4 常用参数

{// very commonly used optionscontainer: undefined,elements: [ /* ... */ ],style: [ /* ... */ ],layout: { name: 'grid' /* , ... */ },// initial viewport state:zoom: 1,pan: { x: 0, y: 0 },// interaction options:minZoom: 1e-50,maxZoom: 1e50,zoomingEnabled: true,userZoomingEnabled: true,panningEnabled: true,userPanningEnabled: true,boxSelectionEnabled: true,selectionType: 'single',touchTapThreshold: 8,desktopTapThreshold: 4,autolock: false,autoungrabify: false,autounselectify: false,// rendering options:headless: false,styleEnabled: true,hideEdgesOnViewport: false,textureOnViewport: false,motionBlur: false,motionBlurOpacity: 0.2,wheelSensitivity: 1,pixelRatio: 'auto'
}

二. 图形操作

1. 添加元素

cy.add()

1.1 添加单个节点

cy.add({group: 'nodes',data: { weight: 75 },position: { x: 200, y: 200 }
});

1.2 添加节点和边

var eles = cy.add([{ group: 'nodes', data: { id: 'n0' }, position: { x: 100, y: 100 } },{ group: 'nodes', data: { id: 'n1' }, position: { x: 200, y: 200 } },{ group: 'edges', data: { id: 'e0', source: 'n0', target: 'n1' } }
]);

2. 删除元素

cy.remove()

2.1 移除单个元素

var j = cy.$('#j');
cy.remove( j );

2.2 移除集合中的元素

var collection = cy.elements('node[weight > 50]');
cy.remove( collection );

2.3 使用选择器来进行元素删除

var collection = cy.elements('node[weight > 50]');
cy.remove( collection );

3. 使用集合

cy.collection() — 获取一个空集合

例如使用集合保存被点击过的节点

var collection = cy.collection();
cy.nodes().on('click', function(e){var clickedNode = e.target;collection = collection.union(clickedNode);
});

4. 使用getElementById()来根据id获取指定元素

cy.getElementById( id ) 参数为元素的id值

cy.getElementById('j');
或者使用下列方式
cy.getElementById('j');

5. 元素匹配

5.1 cy.$( selector )

cy.$("#a")  // 获取id值为a的元素

5.2 cy.elements( selector )

cy.elements('[weight > 50]');  // 获取权重大于50的元素

5.3 cy.nodes( selector )

cy.nodes('[weight > 50]');   // 获取权重大于50的节点

5.4 cy.edges( selector )

cy.edges('[source = "j"]'); // 获取源点为id为j的节点的边

5.5 cy.filter( selector )

cy.filter('[weight > 50]');

5.6 cy.filter( ( ele, i, eles ) => {} )

使用回调函数的方式实现上面用选择器匹配的效果

cy.filter(function(element, i){return element.isNode() && element.data('weight') > 50;
});

6. 批量操作

这允许在不触发多个样式计算或多个元素重绘的情况下操作元素。此函数对于同时对元素进行许多更改非常有用。当指定的回调函数完成时,只有需要它的元素才会更新它们的样式,而呈现器最多只会重新绘制一次。

包含下列三个API:

  • cy.batch(() => { // do something })
  • cy.startBatch() — 手动开始批量操作,主要用于异步操作
  • cy.endBatch() – 手动结束批量操作,主要用于异步操作

6.1 不使用批处理涉及到对元素的多个样式更新

cy.$('#j').data('weight', '70')   // 样式更新.addClass('funny')      // 样式更新.removeClass('serious') // 样式更新// 至少一次,至多3次重绘,这取决于上述操作执行的速度

这对于少数元素的样式更新没有问题,但是如果对于大批量的元素进行上述操作,会造成很多冗余的重绘,导致性能问题,下面用批处理来解决上述问题

6.2 批处理中对元素的多样式更新

cy.batch(function(){cy.$('#j').data('weight', '70').addClass('funny').removeClass('serious');
});

6.2 如果采取手动控制批处理的开始与结束

cy.startBatch();cy.$('#j').data('weight', '70').addClass('funny').removeClass('serious')
;cy.endBatch();

7. 元素的挂载与卸载

cy.mount( container ) container参数为挂载的dom元素

cy.mount( container ) 移除container dom元素上挂载的cytoscape实例

8. 元素的销毁

销毁cytoscape实例

cy.destroy()

可以使用cy.cy.destroy()来判断cytoscape实例是否已经被销毁

三. 数据绑定

3.1 图数据绑定及获取

  • cy.data() — 获取整个图的数据对象

  • cy.data( name ) — 获取指定字段名的数据

  • cy.data( name, value ) — 绑定键为name,值为value的数据

  • cy.data( obj ) — 通过对象更新途中的多个字段值数据

3.2 图数据删除

  • cy.removeData() — 删除图的所有可变数据
  • cy.removeData(names) — 删除指定字段名的数据, names参数为要删除的字段的空格分隔列表

3.3 图数据暂存

3.3.1 cy.scratch()

设置或获取暂存数据,其中可以存储临时数据或非json数据。应用程序级别的暂存数据应该使用带下划线前缀的名称空间,如’_foo’

  • cy.scratch() — 获取图所有名称空间下的暂存数据

  • cy.scratch( namespace ) — 获取指定名称空间下的暂存数据

  • cy.scratch( namespace, value ) — 添加名称空间namespace,并设置暂存值为value

3.3.2 cy.removeScratch()

移除图的暂存数据

cy.removeScratch( namespace ) 移除指定命名空间下的暂存数据, 不添加命名空间参数则会清空所有图相关的暂存数据

四. 事件监听

4.1 事件普通绑定方式cy.on()

别名: cy.bind(),cy.listen(),cy.addListener()

事件的绑定方式如下:

cy.on( events [, selector], function(event) )

  • events

    空格分隔的时间名列表

  • selector

    可选参数, 如果不传递,事件将被绑定在整个图实例上

    选择器,匹配到的元素将被绑定事件

  • function(event)

    事件监听的回调函数

    • event

      监听到的事件对象

一个实例

cy.on('tap', 'node', function(evt){var node = evt.target;console.log( 'tapped ' + node.id() );
});

下列代码没有指定选择器,则事件被绑定到了整个图实例上

cy.on('tap', function(event){// target holds a reference to the originator// of the event (core or element)var evtTarget = event.target;if( evtTarget === cy ){console.log('tap on background');} else {console.log('tap on some element');}
});

4.2 可以获取Promise对象的事件绑定方式cy.promiseOn()

别名: pon

事件触发后将获取到一个成功态的的Promise对象
cy.promiseOn( events [, selector] )

cy.pon('tap').then(function( event ){console.log('tap promise fulfilled');
});

4.3 只生效一次的事件监听cy.one()

绑定的事件只响应一次

cy.one('tap', 'node', function(){console.log('tap!');
});cy.$('node').eq(0).trigger('tap'); // 触发事件,事件不再响应
cy.$('node').eq(1).trigger('tap'); // 事件不再响应

4.4 事件监听的移除

4.4.1 cy.removeListener()

cy.removeListener( events [, selector] [, handler] )

  • events

    空格分隔的事件名列表

  • selector

    选择器,匹配到的元素将进行事件移除,可选参数,如果不指定,则移除对象为图实例

  • handler
    可选参数,可指定移除指定的处理器函数对象关联的事件,不指定则移除所有指定类型的事件处理器监听

如下:
实例1: 不指定具体的事件处理器

cy.on('tap', function(){ /* ... */ });// remove all tap listener handlers, including the one above
cy.removeListener('tap');

实例2: 针对具体的事件处理器进行事件绑定和解绑

var handler = function(){console.log('called handler');
};
cy.on('tap', handler);var otherHandler = function(){console.log('called other handler');
};
cy.on('tap', otherHandler);// just remove handler
cy.removeListener('tap', handler);

4.4.2 移除图实例所有事件监听

cy.removeAllListeners()

4.4.3 事件的主动触发

cy.emit(), 别名cy.trigger()

cy.emit( events [, extraParams] )

cy.on('tap', function(evt, f, b){console.log('tap', f, b);
});cy.emit('tap', ['foo', 'bar']);

4.4.4 图准备就绪事件的监听

cy.ready()

一旦图形准备好(即初始数据加载和初始布局完成),就运行一个回调。

cy.ready(function(event){// do something
}

五. 视口操作

5.1 使用cy.container()获取图实例的dom容器

cy.container()

5.2 居中操作cy.center()

  • cy.center() — 以图中所有元素为中心进行居中。
  • cy.center( eles ) — 以指定元素为中心进行居中
var j = cy.$('#j');
cy.center( j );

5.3 自适应

cy.fit() — 自动调整图的平移距离和缩放级别以达到正好容纳元素的效果

  • cy.fit() — 调整视口以容纳图中的所有元素
  • cy.fit( [eles], [ padding]) — 调整视口以容纳指定元素,并可以指定padding
cy.fit( cy.$('#j, #e') );

5.3 重置图的默认缩放级别和平移位置

cy.reset()

setTimeout( function(){cy.pan({ x: 50, y: -100 });
}, 1000 );setTimeout( function(){cy.zoom( 2 );
}, 2000 );setTimeout( function(){cy.reset();
}, 3000 );

5.4 获取或设置图形的平移位置。

  • cy.pan() — 获取当前平移位置
  • cy.pan( renderedPosition ) — eg: { x: 100, y: 200 }
cy.pan({x: 100,y: 100
});console.log( cy.pan() );

5.5 对于当前位置相对地平移图形

cy.panBy( renderedPosition )

如将图形向右平移100像素:

cy.panBy({x: 100,y: 0
});

5.6 设置是否可以支持平移操作

  • cy.panningEnabled() — 获取是否当前图实例支持进行平移操作
  • cy.panningEnabled( bool ) — 设置当前图实例是否支持进行平移操作
  • cy.userPanningEnabled() — 获取是否启用了用户平移(用户的拖拽操作)。
  • cy.userPanningEnabled( bool ) — 设置是否启用用户平移
cy.panningEnabled( bool )
cy.userPanningEnabled( true );

5.7 指定缩放级别

5.7.1 cy.zoom()

  • cy.zoom() 获取缩放级别

  • cy.zoom( level ) 设置缩放级别

  • cy.zoom( options ) options The options for zooming.

    • level

      缩放级别

    • position

      要缩放的位置

    • renderedPosition

      缩放到的位置

    position和renderedPosition不要同时指定

eg:

cy.zoom({level: 1.5,position: cy.getElementById('a').position()
});
  • cy.minZoom() — 获取最小缩放级别

  • cy.maxZoom() – 设置最小缩放级别

  • cy.viewport( zoom, pan ) — 通过一个函数来设置缩放级别和平移位置

    cy.viewport({zoom: 2,pan: { x: 100, y: 100 }
    });
    

5.7.2 cy.zoomingEnabled()

  • cy.zoomingEnabled() — 获取是否支持缩放

  • cy.zoomingEnabled(bool) — 设置是否支持缩放

  • userZoomingEnabled() — 获取是否支持用户使用鼠标等交互方式进行缩放

  • userZoomingEnabled( bool ) — 设置是否支持用户使用鼠标等交互方式进行缩放

5.8 boxSelectionEnabled

获取或设置是否启用了框选择。如果同时启用平移,用户必须按住shift、control、alt或command中的一个来启动框选择

  • cy.boxSelectionEnabled() — 获取是否支持扩选
  • cy.boxSelectionEnabled( bool ) — 设置是否支持扩选
cy.boxSelectionEnabled( true );

5.9 cy.selectionType()

设置或设置选择类型。“single”选择类型是默认的,点击一个元素将选择该元素并取消选择前面的元素。

还可以指定为追加类型"additive", 可逐次选中多个元素

  • cy.selectionType()
  • cy.selectionType( type ) “single”(default)或者"additive"

5.10 获取视口宽度和高度

  • cy.width()
  • cy.height()
  • cy.extend()
    获取viewport的范围,模型坐标中的一个边界框让您知道在viewport中哪些模型位置是可见的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0B18sP3a-1604913881342)(/Users/liwei/Library/Application Support/typora-user-images/image-20200418201051078.png)]

5.11 cy.autolock()

获取或设置节点是否被自动锁定(即,如果为真,则无论节点的状态如何都被锁定)

  • cy.autolock() — 获取图节点是否自动锁定
  • cy.autolock( bool ) — 设置图节点是否自动锁定
cy.autolock( bool )

5.12 设置节点是否自动取消抓取autoungrabify

  • cy.autoungrabify() — 获取是否自动取消抓取被启用
  • cy.autoungrabify( bool ) — 设置是否启动自动取消抓取

5.13 获取或设置节点是否自动取消选择

  • cy.autounselectify()
  • cy.autounselectify( bool )

5.14 强制渲染器重新计算视口边界

cy.resize()

别名: cy.invalidateDimensions()

六. 动画Animation

6.1 动画执行cy.animate()

  • cy.animated() 判断是否有动画在进行

  • cy.animate( options ) 操纵视口执行动画options An object containing the details of the animation.

    • zoom

      一个缩放级别(数字)或一个缩放配置对象。

      • level

        要使用的缩放级别。

      • position

        缩放发生的位置。这将自动修改pan,使指定的模型位置在缩放期间保持在viewport区段中的相同位置。

      • renderedPosition

        关于缩放发生的渲染位置,作为使用模型位置的替代。这将自动修改pan,使模型位置(与动画开始时呈现的位置相对应)在缩放期间保持在viewport区段中的相同位置。

    • pan

      图形将被移动到的平移位置。

    • panBy

      图形将被移动到的相对平移位置。

    • fit
      一个包含图自动调整以适应对应元素的参数对象

      • eles

        视口将进行调整以容纳对应元素

      • padding

        Padding to use with the fitting (default 0).

    • center

      一个对象,该对象包含将从其中对图形进行动画处理的居中选项。

      • eles

        将视口置于中心的elements或选择器

    • duration

      动画执行时间

    • queue

      一个布尔值,指示是否对动画进行排队(默认为“true”)。核心上排队的动画按顺序运行,直到队列为空。

    • easing

      指定 transition- time- function 类型,以形成动画的进度曲线。

    • complete
      动画执行完成时候执行的回调函数

    • step

      动画步骤调用回调。

    eg:

    1. 操纵pan和zoom
    cy.animate({pan: { x: 100, y: 100 },zoom: 2
    }, {duration: 1000
    });
    
    1. 视口自适应容纳元素
    cy.animate({fit: {eles: j,padding: 20}
    }, {duration: 1000
    });
    

6.2 动画获取cy.animation()

获取视口的动画。

cy.animation( options )

options参数同上, 该函数用来获取指定配置信息的动画

6.3 为动画添加延迟cy.delay()

cy.delay( duration, complete )

cy.animate({fit: { eles: '#j' }}).delay(1000)   // 1s.animate({fit: { eles: '#e' }})
;

6.4 获取视口的延迟动画cy.delayAnimation()

cy.delayAnimation( duration ) — duration为延迟时间

6.5 停止动画

stop(clearQueue, jumpToEnd)
clearQueue是一个布尔值(默认为false),表示动画队列是否应该被清空。
jumpToEnd一个布尔值(默认为false),指示当前运行的动画是否应该跳转到它们的末端,而不是中途停止。

cy.animate({fit: { eles: '#j' }
}, { duration: 2000 });// stop in the middle
setTimeout(function(){cy.stop();
}, 1000);

6.6 清空动画队列cy.clearQueue()

删除viewport中所有排队的动画。

七.布局 Layout

cy.layout()

别名: cy.createLayout(), cy.makeLayout()

获取一个新的布局,它可以用于用算法在图中定位节点。

cy.layout( options )

  • options 布局参数, options.name必须指定

cy.layout()会返回一个布局实例,可以基于这个实例进行其他操作

var layout = cy.layout({name: 'random'
});layout.run();

八. 样式Style

cy.style()

  • cy.style() — 获取当前图的样式对象
  • cy.style( stylesheet ) — 为图指定新的样式对象
    stylesheet 参数可以是一个 cytoscape.stylesheet() 对象, 一个样式对象的字符串, 也可以指定为JSON格式的字符串(格式参考options.style`)

8.1 样式字符串

cytoscape({container: document.getElementById('cy'),// ...style: 'node { background-color: green; }'// , ...
});

8.2 普通JSON格式

cytoscape({container: document.getElementById('cy'),// ...style: [{selector: 'node',style: {'background-color': 'red'}}// , ...]// , ...
});

8.3 cytoscape.stylesheet()`用法

cytoscape({container: document.getElementById('cy'),// ...style: cytoscape.stylesheet().selector('node').style({'background-color': 'blue'})// ...// , ...
});

8.4 根据元素data进行样式绘制

cytoscape({container: document.getElementById('cy'),// ...style: cytoscape.stylesheet().selector('node').style({'background-color': function( ele ){ return ele.data('bg') }// which works the same as// 'background-color': 'data(bg)'})// ...// , ...
});

8.5 设置一个全新的样式

cy.style().clear() //清除默认样式而应用一个全新的样式// 定义节点样式.selector('node').style('background-color', 'magenta')// 定义边样式.selector('edge').style({'width': 3,'line-color': 'yellow'})// ....update() // 显示声明样式更新代码的结束,通知cytoscape更新元素样式
;

8.6 从样式字符串创建style

cy.style().fromString('node { background-color: blue; }').update() // update the elements in the graph with the new style
;

8.7 获取当前样式的JSON对象

var styleJson = cy.style().json();
var serializedJson = JSON.stringify( styleJson );

九. 图的导出

9.1 将当前图形视图导出为PNG图像

cy.png( options )

  • options

    导出参数设置

    • output

      输出应该是“base64uri”(默认)、“base64”、“blob”还是“blob-promise”(返回解析为blob的Promise)。

    • bg

      图像的背景颜色(默认为白色)。

    • full

      是导出当前的viewport视图(“false”,默认)还是导出整个图(“true”)。

    • scale

      此值指定一个正数,该正数缩放生成的图像的大小。

    • maxWidth

      指定与“maxHeight”组合的自动比例,以便生成的图像宽度不超过“maxWidth”。

    • maxHeight

      指定与“maxWidth”组合的自动比例,以便生成的图像不高于“maxHeight”。

eg:

var png64 = cy.png();// put the png data in an img tag
document.querySelector('#png-eg').setAttribute('src', png64);

9.2 导出图为jpg

cy.jpg()

cy.jpg( options )

  • options

    导出参数对象

    • output

      输出应该是“base64uri”(默认)、“base64”、“blob”还是“blob-promise”(返回解析为blob的Promise)。

    • bg

      图像的背景颜色(默认为白色)。

    • full

      是导出当前的viewport视图(“false”,默认)还是导出整个图(“true”)。

    • scale

      此值指定一个正数,该正数缩放生成的图像的大小。

    • maxWidth

      指定与“maxHeight”组合的自动比例,以便生成的图像宽度不超过“maxWidth”。

    • maxHeight

      指定与“maxWidth”组合的自动比例,以便生成的图像不高于“maxHeight”。

    • quality

      指定从’ 0 ‘(低质量,低文件大小)到’ 1 '(高质量,高文件大小)的图像质量。如果没有设置,则使用浏览器的默认质量值。

    var jpg64 = cy.jpg();// put the png data in an img tag
    document.querySelector('#jpg-eg').setAttribute('src', jpg64);
    

9.3 导出JSON

cy.json()

以初始化时使用的相同JSON格式导入或导出图数据。

cy.json( flatEles )

  • flatEles

    resulant JSON是否应该将元素包含为平面数组(’ true ‘)或两个按组键控的数组(’ false ',默认)。

cy.json( cyJson )

将图形作为JSON导入,只更新指定的字段。

  • cyJson

    具有与应该更改的状态对应的字段的对象。

eg:

cy.json({zoom: 2
});

前端追梦人Cytoscape.js教程相关推荐

  1. 前端追梦人JavaScript教程

    一. 基础知识 1.1 JavaScript之HelloWorld <script>console.log("hello world!!!") </script& ...

  2. 前端追梦人响应式网页设计

    一. 响应式元素及媒介 1.1 基于宽度百分比的图像缩放 <!DOCTYPE html> <html lang="en"> <head>< ...

  3. 来CSDN第四年的第一篇博客,不谈技术,谈谈心理话(无论何时何地,我们皆是追梦人)

    差不多是刚上大一的时候吧,那时候机缘巧合之下就接触了csdn这个平台了,那时候主要目的就是搜索每个学期课程的一些知识点,有时候还会找一些课设来作为学校的程序设计的大作业任务.总而言之,那时候刚接触到c ...

  4. 【数据追梦人】毕业6年自学代码,2周面试30家企业,1年376张报表,选择决定人生!

     起初看到"数据追梦人"活动时候,我就在不理解数据和追梦有什么关系,数据不就是简单的从抽取.清洗.分析.报表.可视化等处理过程吗?然后我就草草关闭了页面继续了我的工作. 周末在家中 ...

  5. OceanBase 十年:一群追梦人的成长史

    "如果等会出了问题,我们就从这跳下去!" 说话的人叫阳振坤,OceanBase 创始人.他指着作战会议室里一扇打开的窗,面前是时任蚂蚁金服董事长的彭蕾.这是 2014 年 11 月 ...

  6. 《“ 追梦人” 的逐梦路:探寻大学生创客群体的发展之道》

    据了解,<"追梦人"的逐梦路:探寻大学生创客群体的发展之道>依托学校丰富的创业教育实践,以"大学生创客群体"为研究对象,以构筑创业梦.走近" ...

  7. 2019年,做努力奔跑的追梦人

    2019,给自己一个努力的机会,给自己一个拼搏的机会,给自己一个追梦的机会. 回顾2018 2018年,是思维转变,努力求上进的一年. 在2018年年初,离开了原公司,到了新环境.bye hbjt,h ...

  8. 用计算机弹追梦人,新学期!你好,计算机追梦人

    原标题:新学期!你好,计算机追梦人 料峭春风吹人醒 新学期.新征程 亲爱的同学们 你准备好了吗? 你好,新学期 看,校园里 花儿悄悄迎寒绽放 过了一个假期 你是否感受到春的气息 2019.03.04 ...

  9. 用计算机弹追梦人,黑大 “追梦人” | 计算机前的精灵——叶健雄

    原标题:黑大 "追梦人" | 计算机前的精灵--叶健雄 巾帼不让须眉 飘渺的网络世界里 她背上行囊 在无尽的荒野中 探索新的绿洲 人物介绍 叶健雄,2016级计算机科学技术学院.软 ...

最新文章

  1. 编程体系结构(07):JavaEE之Web开发
  2. movelast对数据记录数有要求吗_新颁布丨药品记录与数据管理要求(试行)解读...
  3. Spring Cloud 相关配置信息说明
  4. 编译win10的WSL2内核(windows subsystem linux)
  5. ArcGIS地图文档(mxd)过大的问题
  6. 20180124现货黄金复盘
  7. #9733;如何解释特修斯之船问题?
  8. PowerVR 6系列架构分析
  9. GD32官方资料学习体系(主要包括MCU选型、原理图PCB设计、软件开发入门及用户手册等)
  10. 推荐一些前端小姐姐的公众号
  11. 计算机应用基础文章 茶的功效,【课程改革论文】茶文化下的计算机应用基础教程课程改革(共5535字)...
  12. (免量产,免格式化)手动将PE安装到移动硬盘/U盘或无系统硬盘!
  13. 美国印钱 为什么不会通货膨胀
  14. 16进制格式的字符串怎样转换为整数
  15. 机器学习 - 线性模型
  16. 省钱兄(APP+H5+公众号+小程序)自营商城源码分销系统社区团购线上线下核销吃喝玩乐系统源码前端模板
  17. 超强AI绘画Midjourney使用教程
  18. Spark 多维分析
  19. 《万历十五年》笔记——皇权与相权的博弈
  20. 啥是老北京涮羊肉,身在南方的北方人需要记得……

热门文章

  1. JavaScript快速入门到高级 JS精品视频课程
  2. 零基础如何学习java,要学多久?
  3. 将边缘云装进胶囊数据中心需要几步?
  4. 【C#】System.MissingMethodException:Method not found: 'xxx.get_xxx()'
  5. 星际争霸人族兵种音效中英对照翻译
  6. 纳斯达克的区块链野望
  7. Windows Server2012常见版本
  8. [Windows实用软件推荐:1]本地搜索工具Everything
  9. creator中关于旋转所使用的欧拉角和四元数
  10. 急!急!急!如何申请公网ip