使用Vue和GoJS创建组件并进行动态数据传递
最编程
2024-01-12 12:56:25
...
父组件:
<!-- message为子组件取数据所用,diagramData为父页面数据 -->
<go-model :message="diagramData"></go-model>
// 引入子组件gojs
import goModel from '../../commonTools/go.vue';
export default {
components: {
goModel // 生命组件
},
data () {
return {
ipData:'',
// 定义为全局数据
diagramData:[]
}
},
mounted (){
},
methods: {
//结合实际情况调用this.init();
init() {
// 从服务器请求JSON格式的文本数据
let url = RESREQUESTPREFIX + '/custom/garph/findresources?source_id='+this.resId;
this.$http.get(url).then(function(response){
if(response.status === 200){
this.diagramData = response.data;
// 判断数据不为空是执行,不然会报错
if(this.diagramData != ''){
// 子组件中心位置数据
this.diagramData[0].ip = this.ipData;
}
}
},function(){
this.$Message.error('数据获取失败,请检查接口是否正常!');
})
}
}
}
子组件
<!-- myDiagramDiv为vue取dom所用 -->
<div ref='myDiagramDiv' style="min-width:500px; width: 100%;height:350px"></div>
<script>
// 需要先定义全局变量,不然会报错
let go = window.go;
let gm = go.GraphObject.make; //定义模版,这里官网用的$太敏感,被我替换掉了
export default {
props:['message'], //接收父组件的数据
data () {
return {
myDiagram:'',
currentValue:this.message //data接收转一下为方便watch监听使用
}
},
mounted (){
// 创建页面加载创建图表,不可以加在事件中,因为一个dom只可以画一个图
this.myDiagram = gm(go.Diagram,
this.$refs.myDiagramDiv, //gojs中可以直接取到id名(如‘id’)vue中不可以,所以用refs来取dom
{initialContentAlignment: go.Spot.Center,}); // 图表居中显示
var graygrad = gm(go.Brush, "Linear", { 0: "#F5F5F5", 1: "#F1F1F1" }); // 定义图表格式刷
// 定义节点模版
this.myDiagram.nodeTemplate = gm(
go.Node, "Auto",
{ isShadowed: true }, // 是否投影
// 定义节点的外部形状
gm(go.Shape, "RoundedRectangle", // 形状为圆角矩形
{ fill: graygrad, stroke: "#D8D8D8"},
new go.Binding("fill", "color")),
// 定义节点的文本
gm(go.TextBlock,
{ margin: 10,height:40, font: "bold 11px Helvetica, bold Arial, sans-serif" },
new go.Binding("text", "key")),
gm(go.Panel,
{ defaultAlignment: go.Spot.TopLeft, //位置
margin:10,
},
new go.Binding("itemArray", "reasonsList")// 汉字说明
)
);
// 连接线样式
this.myDiagram.linkTemplate = gm(
go.Link,
{ routing: go.Link.Orthogonal, corner: 5 },
gm(go.Shape, { strokeWidth: 3, stroke: "#555" })
);
},
methods: {
init() {
// watch监听数据结果把数据放入图表中 为双树创建模型
this.myDiagram.model = new go.TreeModel(this.currentValue);
this.doubleTreeLayout(this.myDiagram);
},
doubleTreeLayout(diagram) {
// 根据方向,将节点和链接分成两组
var leftParts = new go.Set(/*go.Part*/);
var rightParts = new go.Set(/*go.Part*/);
this.separatePartsByLayout(diagram, leftParts, rightParts);
// 但是ROOT节点将在两个集合中
//创建并执行两个TreeLayout,每个方向一个,
//在不移动ROOT节点的情况下,在节点和链接的不同子集上
var layout1 =
gm(go.TreeLayout,
{ angle: 180,// 距离root的左侧距离
arrangement: go.TreeLayout.ArrangementFixedRoots,// 布置单独的树,必选
setsPortSpot: false });
var layout2 =
gm(go.TreeLayout,
{ angle: 0,// 距离root的右侧距离
arrangement: go.TreeLayout.ArrangementFixedRoots,
setsPortSpot: false });
layout1.doLayout(leftParts);
layout2.doLayout(rightParts);
diagram.commitTransaction("Double Tree Layout");
},
separatePartsByLayout(diagram, leftParts, rightParts) {
var root = diagram.findNodeForKey(this.ipData); // 获取中心点
if (root === null) return;
// ROOT节点由两个子树共享
leftParts.add(root);
rightParts.add(root);
// 查看ROOT节点的所有直接子节点
root.findTreeChildrenNodes().each(function(child) {
// 这个节点在哪个方向延长
var dir = child.data.dir;
var coll = (dir === "left") ? leftParts : rightParts;
// 从此子节点开始添加整个子树
coll.addAll(child.findTreeParts());
// 还添加了从ROOT节点到该子节点的链接
coll.add(child.findTreeParentLink());
});
},
},
watch: {
// 监听父组件的message数据,因为子组件是和父组件一起加载模版,所以oldValue第一次为空,需要把newValue监听到的新数据返回给页面绘图
message(newValue, oldValue){
this.currentValue = newValue
// 赋完数据之后调用
this.init();
},
}
}
</script>
推荐阅读
-
一种结构设计模式,允许在对象中动态添加新行为。它通过创建一个封装器来实现这一目的,即把对象放入一个装饰器类中,然后把这个装饰器类放入另一个装饰器类中,以此类推,形成一个封装器链。这样,我们就可以在不改变原始对象的情况下动态添加新行为或修改原始行为。 在 Java 中,实现装饰器设计模式的步骤如下: 定义一个接口或抽象类作为被装饰对象的基类。 公共接口 Component { void operation; } } 在本例中,我们定义了一个名为 Component 的接口,该接口包含一个名为 operation 的抽象方法,该方法定义了被装饰对象的基本行为。 定义一个实现基类方法的具体装饰对象。 公共类 ConcreteComponent 实现 Component { public class ConcreteComponent implements Component { @Override public void operation { System.out.println("ConcreteComponent is doing something...") ; } } 定义一个抽象装饰器类,该类继承于基类,并将装饰对象作为一个属性。 公共抽象类装饰器实现组件 { protected Component 组件 public Decorator(Component component) { this.component = component; } } @Override public void operation { component.operation; } } } 在这个示例中,我们定义了一个名为 Decorator 的抽象类,它继承了 Component 接口,并将被装饰对象作为一个属性。在操作方法中,我们调用了被装饰对象上的同名方法。 定义一个具体的装饰器类,继承自抽象装饰器类并实现增强逻辑。 公共类 ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component 组件) { super(component); } } public void operation { super.operation System.out.println("ConcreteDecoratorA 正在添加新行为......") ; } } 在本例中,我们定义了一个名为 ConcreteDecoratorA 的具体装饰器类,它继承自装饰器抽象类,并实现了操作方法的增强逻辑。在操作方法中,我们首先调用被装饰对象上的同名方法,然后添加新行为。 使用装饰器增强被装饰对象。 公共类 Main { public static void main(String args) { Component 组件 = new ConcreteComponent; component = new ConcreteDecoratorA(component); 组件操作 } } 在这个示例中,我们首先创建了一个被装饰对象 ConcreteComponent,然后通过 ConcreteDecoratorA 类创建了一个装饰器,并将被装饰对象作为参数传递。最后,调用装饰器的操作方法,实现对被装饰对象的增强。 使用场景 在 Java 中,装饰器模式被广泛使用,尤其是在 I/O 中。Java 中的 I/O 库使用装饰器模式实现了不同数据流之间的转换和增强。 让我们打开文件 a.txt,从中读取数据。InputStream 是一个抽象类,FileInputStream 是专门用于读取文件流的子类。BufferedInputStream 是一个支持缓存的数据读取类,可以提高数据读取的效率,具体代码如下: @Test public void testIO throws Exception { InputStream inputStream = new FileInputStream("C:/bbb/a.txt"); // 实现包装 inputStream = new BufferedInputStream(inputStream); byte bytes = new byte[1024]; int len; while((len = inputStream.read(bytes)) != -1){ System.out.println(new String(bytes, 0, len)); } } } } 其中 BufferedInputStream 对读取数据进行了增强。 这样看来,装饰器设计模式和代理模式似乎有点相似,接下来让我们讨论一下它们之间的区别。 第三,与代理模式的区别: 代理模式的目的是控制对对象的访问,它在对象外部提供一个代理对象来控制对原对象的访问。代理对象和原始对象通常实现相同的接口或继承相同的类,以确保两者可以相互替换。 装饰器模式的目的是动态增强对象的功能,而这是通过对象内部的包装器来实现的。在装饰器模式中,装饰器类和被装饰对象通常实现相同的接口或继承自相同的类,以确保两者可以相互替代。装饰器模式也被称为封装器模式。 在代理模式中,代理类附加了与原类无关的功能。
-
使用Vue和GoJS创建组件并进行动态数据传递