JointJS速览

入门
Hello World
下面时官方给出的入门demo例子,可以看到 JointJS 依赖jquery、lodash、backbone,使用 JointJS 只需要引入joint.css和joint.js即可。定义一个div用来盛放绘制的图形。

<!DOCTYPE html>
<html>
<head><link rel="stylesheet" type="text/css" href="css/joint.css" />
</head>
<body>
<!-- content -->
<div id="myholder"></div>
<!-- dependencies -->
<script src="js/jquery.js"></script>
<script src="js/lodash.js"></script>
<script src="js/backbone.js"></script>
<script src="js/joint.js"></script>
<!-- code -->
<script type="text/javascript">var graph = new joint.dia.Graph;var paper = new joint.dia.Paper({el: document.getElementById('myholder'),model: graph,width: 600,height: 100,gridSize: 1});var rect = new joint.shapes.standard.Rectangle();rect.position(100, 30);rect.resize(100, 40);rect.attr({body: {fill: 'blue'},label: {text: 'Hello',fill: 'white'}});rect.addTo(graph);var rect2 = rect.clone();rect2.translate(300, 0);rect2.attr('label/text', 'World!');rect2.addTo(graph);var link = new joint.shapes.standard.Link();link.source(rect);link.target(rect2);link.addTo(graph);
</script>
</body>
</html>

代码解析
在上面的js代码中,有以下几类对象:

paper:JointJS中最外层的对象,用来连接内外:内部装载的是哪个graph,外部是渲染在哪个div中。gridSize属性是用来指明元素对齐的网格的大小。影响元素移动的粒度。paper在渲染过后,可以使用paper.scale()去实现缩放,使用paper.translate()去实现整体位移。paper的完整属性可以参看这里。

graph:用来承载各个元素的画布。

Rectangle:矩形元素。一个元素可以是通过构造器,如new joint.shapes.standard.Rectangle(),来实例化,也可以通过clone方法去得到。shapes.standard下提供了十几种常见的图形元素,比如圆形、椭圆、带标题的矩形等等。官网提到,可以通过继承Element对象,来自定义自己的元素。Element最常用的几个方法如下:

element.position() - 设置元素原点(左上角)相对于paper坐标系的位置(考虑paper缩放和其他变换)。
element.resize() - 设置元素的尺寸。
element.clone() - 克隆现有元素,包括其位置,尺寸和属性。
element.translate() - 沿两个坐标轴移动元素指定的距离。还有缩放和旋转元素的方法。
element.addTo() - 将元素添加到graph中以便可以呈现它。
每个元素都可以通过element.attr方法来重写属性。这个元素支持哪些属性,可以通过joint.js中查看代码来得知,比如Rectangle元素在joint.js中的定义代码如下:

Element.define('standard.Rectangle', {attrs: {body: {refWidth: '100%',refHeight: '100%',strokeWidth: 2,stroke: '#000000',fill: '#FFFFFF'},label: {textVerticalAnchor: 'middle',textAnchor: 'middle',refX: '50%',refY: '50%',fontSize: 14,fill: '#333333'}}
}, {markup: [{tagName: 'rect',selector: 'body',}, {tagName: 'text',selector: 'label'}]
});

改变Element的属性在上例html中演示了两种写法rect,rect2,个人感觉第二种更直观。

Link:线条元素。指明线条的两个端点即实现了连线。Link和普通的元素没有很大区别。

中级

特殊属性
相对维度
使用SVG时最常见的请求之一是相对设置SVGElements的维度。 JointJS允许您使用一组ref属性来实现。这些属性允许您将子元素的大小调整为形状模型的尺寸的百分比。此外,由于所有计算都是程序化的,并且不依赖于浏览器的bbox测量,因此使用这些属性不会影响应用程序的性能。

refWidth和refHeight - 设置子元素相对于模型bbox的宽度。
refX和refY - 设置子元素左上角相对于模型bbox左上角的坐标。百分比是相对于模型bbox的。
refCx和refCy - 设置圆/椭圆中心的坐标。百分比是相对于模型bbox的。可以与refX / refY一起使用。
refRx和refRy - 设置椭圆相对于模型bbox尺寸的半径。百分比是相对于模型bbox的。
refR - 设置圆的半径相对于模型bbox的短边的长度。百分比是相对于模型bbox的。
refRCircumscribed - 设置圆的半径相对于模型bbox的最长对角线。
基于文本的相对维度
暂不关心细节,略过。

Link箭头
可以通过SourceMarker和TargetMarker为Link自定义箭头,如下面的示例代码为其定义了一个矩形箭头和圆形箭尾:、

link.attr({line: {sourceMarker: {'type': 'rect','width': 50,'height': 10,'y': -5,'fill': 'rgba(255,0,0,0.3)','stroke': 'black'},targetMarker: {'type': 'circle','r': 10,'cx': 10,'fill': 'rgba(0,255,0,0.3)','stroke': 'black'}}
});

事件

paper的内建事件
Paper提供了常见的事件捕捉,如单元格/元素/线条/空白处被点击,鼠标移动,线条连接元素,线条取消连接元素等等,详细的可参见。事件的回调写法如下:

paper.on('blank:pointerdown', function(evt, x, y) {alert('pointerdown on a blank area in the paper.')
})

连续的一组事件,可以共享数据,写法如下:

// Create a new link by dragging
paper.on({'blank:pointerdown': function(evt, x, y) {var link = new joint.dia.Link();link.set('source', { x: x, y: y });link.set('target', { x: x, y: y });link.addTo(this.model);evt.data = { link: link, x: x, y: y };},'blank:pointermove': function(evt, x, y) {evt.data.link.set('target', { x: x, y: y });},'blank:pointerup': function(evt) {var target = evt.data.link.get('target');if (evt.data.x === target.x && evt.data.y === target.y) {// remove zero-length linksevt.data.link.remove();}}
});

graph的内建事件
graph提供了一些捕捉element位置变化、大小变化的事情,如change:position是监测element的位置发生了变化,change:target是监测link的指向发生了变化,示例代码如下:

graph.on('change:position', function(cell) {var center = cell.getBBox().center();var label = center.toString();cell.attr('label/text', label);
});
graph.on('change:target', function(cell) {var target = new g.Point(cell.target());var label = target.toString();cell.label(0, {attrs: {label: {text: label}}});
});

子元素监听事件
在下面的代码中定义了一个新的元素,他由一个矩形+一个按钮组成。现在我们想监听按钮被点击的事情,该怎么处理?注意97行代码,我们需要通过子元素的event属性,告知上层event是需要监听的。然后通过paper.on来捕捉,并定义响应。

<!DOCTYPE html>
<html>
<head><link rel="stylesheet" type="text/css" href="css/joint.css" />
</head>
<body>
<!-- content -->
<div id="paper"></div>
<!-- dependencies -->
<script src="js/jquery.js"></script>
<script src="js/lodash.js"></script>
<script src="js/backbone.js"></script>
<script src="js/joint.js"></script>
<!-- code -->
<script type="text/javascript">var graph = new joint.dia.Graph;var paper = new joint.dia.Paper({el: document.getElementById('paper'),model: graph,width: 600,height: 100,gridSize: 10,drawGrid: true,background: {color: 'rgba(0, 255, 0, 0.3)'}});var CustomElement = joint.dia.Element.define('examples.CustomElement', {attrs: {body: {refWidth: '100%',refHeight: '100%',strokeWidth: 2,stroke: 'black',fill: 'white'},label: {textVerticalAnchor: 'middle',textAnchor: 'middle',refX: '50%',refY: '50%',fontSize: 14,fill: 'black'},button: {cursor: 'pointer',ref: 'buttonLabel',refWidth: '150%',refHeight: '150%',refX: '-25%',refY: '-25%'},buttonLabel: {pointerEvents: 'none',refX: '100%',refY: 0,textAnchor: 'middle',textVerticalAnchor: 'middle'}}}, {markup: [{tagName: 'rect',selector: 'body',}, {tagName: 'text',selector: 'label'}, {tagName: 'rect',selector: 'button'}, {tagName: 'text',selector: 'buttonLabel'}]});var element = new CustomElement();element.position(250, 30);element.resize(100, 40);element.attr({label: {pointerEvents: 'none',visibility: 'visible',text: 'Element'},body: {cursor: 'default',visibility: 'visible'},button: {event: 'element:button:pointerdown',fill: 'orange',stroke: 'black',strokeWidth: 2},buttonLabel: {text: '_', // fullwidth underscorefill: 'black',fontSize: 8,fontWeight: 'bold'}});element.addTo(graph);paper.on('element:button:pointerdown', function(elementView, evt) {evt.stopPropagation(); // stop any further actions with the element view (e.g. dragging)var model = elementView.model;if (model.attr('body/visibility') === 'visible') {model.attr('body/visibility', 'hidden');model.attr('label/visibility', 'hidden');model.attr('buttonLabel/text', '+'); // fullwidth plus} else {model.attr('body/visibility', 'visible');model.attr('label/visibility', 'visible');model.attr('buttonLabel/text', '_'); // fullwidth underscore}});
</script>
</body>
</html>

自定义视图事件
对于更高级的事件自定义,我们可以通过重写paper的默认view来实现,下面是示例代码。在下面的例子中,我们禁用了默认的视图,通过elementview和linkview重写了事件。新的效果是,当某个元素或者线条被双击时会删除它本身。

var paper = new joint.dia.Paper({el: document.getElementById('paper-custom-view-events'),model: graph,width: 600,height: 100,gridSize: 1,background: {color: 'white'},interactive: false, // disable default interaction (e.g. dragging)elementView: joint.dia.ElementView.extend({pointerdblclick: function(evt, x, y) {this.model.remove();}}),linkView: joint.dia.LinkView.extend({pointerdblclick: function(evt, x, y) {this.model.remove();}})
});

自定义元素
可以先看一下源码中是如何定义一个Rectangle Element的,代码如下:

joint.dia.Element.define('standard.Rectangle', {attrs: {body: {refWidth: '100%',refHeight: '100%',strokeWidth: 2,stroke: '#000000',fill: '#FFFFFF'},label: {textVerticalAnchor: 'middle',textAnchor: 'middle',refX: '50%',refY: '50%',fontSize: 14,fill: '#333333'}}
}, {markup: [{tagName: 'rect',selector: 'body',}, {tagName: 'text',selector: 'label'}]
});
  • 通过Element.define函数去声明这是一个Element的定义。

  • standard.Rectangle是所定义Element的名称,应是唯一的。这里隐藏了joint.shapes,所以实际上的全名是joint.shapes.standard.Rectangle。

  • markup是定义子元素的地方。tagName指明了子元素的名字rect->SVGRectElement,text->SVGTextElement。selector给出了两个子元素的在本元素类的名称。可以看出joint.js最底层是svg对象。

  • attrs设置默认属性。使用在markup中定义的selector标识符,为各个子元素指定属性。可以看到这里子元素的大小都是通过相对维度去设定的。

这里还没有提到的是构造函数。在上面的元素定义中,还可以增加一个构造函数段,如下:

{createRandom: function() {var rectangle = new this();var fill = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6);var stroke = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6);var strokeWidth = Math.floor(Math.random() * 6);var strokeDasharray = Math.floor(Math.random() * 6) + ' ' + Math.floor(Math.random() * 6);var radius = Math.floor(Math.random() * 21);rectangle.attr({body: {fill: fill,stroke: stroke,strokeWidth: strokeWidth,strokeDasharray: strokeDasharray,rx: radius,ry: radius},label: { // ensure visibility on dark backgroundsfill: 'black',stroke: 'white',strokeWidth: 1,fontWeight: 'bold'}});return rectangle;}

这样,使用的时候,就可以通过joint.shapes.standard.Rectangle.createRandom();来调用构造函数去创建元素对象。

自定义属性
自定义属性需要在使用时通过以下方法进行:

var rect3 = new joint.shapes.lefer.Rectangle()
rect3.attr('bussiness/title', 'lefer');

需要注意的是,自定义的业务属性需要在自定义元素时没有出现过才能成功。

使用port
前面的示例中是在渲染时就指明了图形的连接关系,还有一种很常见的情况是由用户来拖拽连线。这个时候需要用到joint.shapes.devs.js。下面是示例代码

WORKING WITH PORTS
Many diagramming applications deal with elements with ports. Ports are usually displayed as circles inside diagram elements and are used not only as "sticky" points for connected links but they also further structure the linking information. It is common that certain elements have lists of input and output ports. A link might then point not to the element as a whole but to a certain port instead.
JointJS has a built-in support for elements with ports, linking between ports and a facility for defining what connections are allowed and what not. This is useful if you, for example, want to restrict linking in between input ports, or output ports or between a certain port of an element A and a certain port of an element B. This tutorial shows you how you can do all that.
Creating elements with ports
The easiest way to start with elements with ports is using the joint.shapes.devs plugin. Search for joint.shapes.devs.js file. This plugin defines one important shape, the joint.shapes.devs.Model*. You can just instantiate that shape and pass the inPorts and outPorts arrays as parameters. You can further set the coloring of the ports and label for your element as you can see in the example below. Moreover, JointJS takes care of preparing the view and the magnets** for UI interaction. That's why you can already click and drag a port and JointJS automatically creates a link coming out of that port.
JointJS and the joint.shapes.devs.Model also makes it easy to change ports. Simply set the inPorts/outPorts arrays of your element:
element.set('inPorts', ['newIn1', 'newIn2', 'newIn3']);
element.set('outPorts', ['newOut1', 'newOut2']);
*DEVS is an abbreviation for Discrete EVent System specification and is a formalism for modeling and analyzing general systems. This formalism uses two types of models (Atomic and Coupled) both having a set of input and output ports.
**Magnets in JointJS are SVG sub-elements that serve as sticky points for links. If you use the joint.shapes.devs plugin, you don't have to define your magnets yourself, instead the joint.shapes.devs.Model shape does it for you.(function() {
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({ el: $('#paper-create'), width: 650, height: 200, gridSize: 1, model: graph });
var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }}
});
graph.addCell(m1);
}());
Linking elements with ports
Now when you have your elements with ports created, you can start observing what port is connected with a link to what other port. This is easy to do thanks to JointJS storing the information about ports in the link models themselves once the links are created via the UI. The following example shows you how you can get the linking information. Try to connect a port of one element to another port of another element.(function() {
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({ el: $('#paper-link'), width: 650, height: 200, gridSize: 1, model: graph });
var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }}
});
graph.addCell(m1);
var m2 = m1.clone().translate(300, 0).attr('.label/text', 'Model 2');
graph.addCell(m2);
graph.on('change:source change:target', function(link) {var sourcePort = link.get('source').port;var sourceId = link.get('source').id;var targetPort = link.get('target').port;var targetId = link.get('target').id;var m = ['The port <b>' + sourcePort,'</b> of element with ID <b>' + sourceId,'</b> is connected to port <b>' + targetPort,'</b> of elemnt with ID <b>' + targetId + '</b>'].join('');out(m);
});
function out(m) {$('#paper-link-out').html(m);
}
}());
Linking restrictions
Now you know how to create elements with ports and how to get the linking information. Another practical functionality related to elements with ports and their links is restricting certain connections. Say you want links to never start in input ports and never end in output ports. This is the most usual case. However, all kinds of restrictions are possible and application specific. JointJS doesn't limit you. Instead, it allows you to define a function that simply returns true if a connection between a source magnet of a source element and a target magnet of a target element is allowed, and false otherwise. If the connection is not allowed JointJS does not connect the magnets (and associated ports). Furthermore, you can mark certain magnets as "passive" in which case JointJS treats these magnets in a way that they can never become a source of a link. For further information, please see the list of options that you can pass to the joint.dia.Paper in the API reference page, especially the two related functions: validateConnection() and validateMagnet().(function() {
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({el: $('#paper-restrict'),width: 650, height: 200, gridSize: 1,model: graph,defaultLink: new joint.dia.Link({attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' } }}),validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {// Prevent linking from input ports.if (magnetS && magnetS.getAttribute('port-group') === 'in') return false;// Prevent linking from output ports to input ports within one element.if (cellViewS === cellViewT) return false;// Prevent linking to input ports.return magnetT && magnetT.getAttribute('port-group') === 'in';},validateMagnet: function(cellView, magnet) {// Note that this is the default behaviour. Just showing it here for reference.// Disable linking interaction for magnets marked as passive (see below `.inPorts circle`).return magnet.getAttribute('magnet') !== 'passive';}
});
var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085',magnet: 'passive'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }}
});
graph.addCell(m1);
var m2 = m1.clone();
m2.translate(300, 0);
graph.addCell(m2);
m2.attr('.label/text', 'Model 2');
}());
Link snapping
To improve user experience little bit you might want to enable the link snapping. While the user is dragging a link, it searches for the closest port in the given radius. Once a suitable port is found (it meets requirements specified in validateConnection()) the link automatically connects to it. You can try this functionality in the example below.(function() {
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({el: $('#paper-link-snapping'),width: 650, height: 200, gridSize: 1,model: graph,defaultLink: new joint.dia.Link({attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' } }}),validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {// Prevent loop linkingreturn (magnetS !== magnetT);},// Enable link snapping within 75px lookup radiussnapLinks: { radius: 75 }
});
var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085',magnet: 'passive'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }}
});
graph.addCell(m1);
var m2 = m1.clone();
m2.translate(300, 0);
graph.addCell(m2);
m2.attr('.label/text', 'Model 2');
})();
Marking available magnets
Another way how to make user's life easier can be to offer him all magnets he can connect to while he is dragging a link. To achieve this you have to enable markAvailable option on the paper and add some css rules into your stylesheet like in the example bellow./* port styling */
.available-magnet {fill: yellow;
}
/* element styling */
.available-cell rect {stroke-dasharray: 5, 2;
}
(function() {var graph = new joint.dia.Graph;var paper = new joint.dia.Paper({el: $('#paper-mark-available'),width: 650, height: 200, gridSize: 1,model: graph,defaultLink: new joint.dia.Link({attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' } }}),validateConnection: function(cellViewS, magnetS, cellViewT, magnetT, end, linkView) {// Prevent linking from input ports.if (magnetS && magnetS.getAttribute('port-group') === 'in') return false;// Prevent linking from output ports to input ports within one element.if (cellViewS === cellViewT) return false;// Prevent linking to input ports.return magnetT && magnetT.getAttribute('port-group') === 'in';},// Enable marking available cells & magnetsmarkAvailable: true});var m1 = new joint.shapes.devs.Model({position: { x: 50, y: 50 },size: { width: 90, height: 90 },inPorts: ['in1','in2'],outPorts: ['out'],ports: {groups: {'in': {attrs: {'.port-body': {fill: '#16A085',magnet: 'passive'}}},'out': {attrs: {'.port-body': {fill: '#E74C3C'}}}}},attrs: {'.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },rect: { fill: '#2ECC71' }}}).addTo(graph);var m2 = m1.clone().translate(300, 0).attr('.label/text', 'Model 2').addTo(graph);
})();

文章转自;https://www.lefer.cn/posts/8954/

JointJs快速入门相关推荐

  1. Shiro第一个程序:官方快速入门程序Qucickstart详解教程

    目录 一.下载解压 二.第一个Shiro程序 1. 导入依赖 2. 配置shiro配置文件 3. Quickstart.java 4. 启动测试 三.shiro.ini分析 四.Quickstart. ...

  2. 计算机入门新人必学,异世修真人怎么玩?新手快速入门必备技巧

    异世修真人怎么快速入门?最近新出来的一款文字修仙游戏,很多萌新不知道怎么玩?进小编给大家带来了游戏新手快速入门技巧攻略,希望可以帮到大家. 新手快速入门攻略 1.开局出来往下找婆婆,交互给点钱,旁边有 ...

  3. Spring Boot 2 快速教程:WebFlux 快速入门(二)

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘 ...

  4. Apache Hive 快速入门 (CentOS 7.3 + Hadoop-2.8 + Hive-2.1.1)

    2019独角兽企业重金招聘Python工程师标准>>> 本文节选自<Netkiller Database 手札> 第 63 章 Apache Hive 目录 63.1. ...

  5. 《iOS9开发快速入门》——导读

    本节书摘来自异步社区<iOS9开发快速入门>一书中的目录,作者 刘丽霞 , 邱晓华,更多章节内容可以访问云栖社区"异步社区"公众号查看 目 录 前 言 第1章 iOS ...

  6. BIML 101 - ETL数据清洗 系列 - BIML 快速入门教程 - 序

    BIML 101 - BIML 快速入门教程 做大数据的项目,最花时间的就是数据清洗. 没有一个相对可靠的数据,数据分析就是无木之舟,无水之源. 如果你已经进了ETL这个坑,而且预算有限,并且有大量的 ...

  7. python scrapy菜鸟教程_scrapy学习笔记(一)快速入门

    安装Scrapy Scrapy是一个高级的Python爬虫框架,它不仅包含了爬虫的特性,还可以方便的将爬虫数据保存到csv.json等文件中. 首先我们安装Scrapy. pip install sc ...

  8. OpenStack快速入门

    OpenStack云计算快速入门(1) 该教程基于Ubuntu12.04版,它将帮助读者建立起一份OpenStack最小化安装.我是五岳之巅,翻译中多采用意译法,所以个别词与原版有出入,请大家谅解.我 ...

  9. Expression Blend实例中文教程(2) - 界面快速入门

    上一篇主要介绍Expression系列产品,另外概述了Blend的强大功能,本篇将用Blend 3创建一个新Silverlight项目,通过创建的过程,对Blend进行快速入门学习. 在开始使用Ble ...

  10. 图文并茂!60页PPT《快速入门python数据分析路线》(附链接)

    一个月不走弯路快速入门学python和python数据分析路线,呕心沥血加班加点做了2天,一共63页,该课件讲的都是路线中的核心知识,今天把该PPT分享给大家,能根据该课件提到的知识有针对性的学,做到 ...

最新文章

  1. 如何查看OpenCV自带函数的源代码
  2. .bat文件(%~dp0)和call、echo批处理环境变量
  3. MESSL(maven + extjs + spring portlet mvc + spring web flow + liferay )整合架构 5
  4. ObservableCollection 类
  5. 程序实现switch语句判断年龄_【回顾】(选择执行语句if else和switch)乐创DIY C语言讲义——3.8节(4)...
  6. tomcat各目录(文件)作用
  7. 【UIKit】UITableView.02
  8. springMVC中添加命名空间(edit namespace)
  9. 【五级流水线CPU】—— 5. 转移指令(14条)
  10. bootstrap下的双选时间插件使用方法
  11. SpringBoot Logback配置,SpringBoot日志配置
  12. java 字符长度判断_java判断中文字符串长度的简单实例
  13. mac mysql 移动硬盘_mac挂载移动硬盘可以读写的方法
  14. 新颖的自我介绍_有关最新颖的自我介绍
  15. Python爬虫入门指南
  16. 【1034】计算三角形面积
  17. 树莓派ubuntu换源
  18. CASE工具 ——软件产业危机的解决方案
  19. java读取mp3文件
  20. java网上书店管理系统_基于JAVA的网上书店管理系统的开发.doc

热门文章

  1. 小学计算机课的微案例,全国中小学信息技术课程教学案例大赛获奖作品 趣味造型制作.doc...
  2. vs2010旗舰版密钥
  3. 熊猫烧香源码分析_熊猫体育分析入门
  4. Samsung GT-P5100刷andorid 4.3
  5. WAP PUSH解析(2)——WSP以及WBXML编码
  6. yolo标注文件转换工具,python做的
  7. java实现ping_java实现Ping示例代码
  8. php 5.3 include 上层 function,php5.3开始出现的Function ereg() is deprecated Error问题解决办法...
  9. GEO学习笔记-P1-P2
  10. BPM波导matlab,用Matlab画平板波导色散图详解.doc