使用VUE 组件实现HMI 模型
Posted 姚家湾
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用VUE 组件实现HMI 模型相关的知识,希望对你有一定的参考价值。
HMI模型化的目的是通过模型能够实现HMI 视图的组态化。
HMI 组态化方法
HMI 组态要使用一个HMI 设计工具来实现,这个工具类似于图形编辑软件。使用者从UI 组件库中选择合适的模板,放置在页面中,并且配置各种参数。HMI 设计的结果是产生一个页面模型。存储到系统模型库中。当系统运行时,由后台读取HMI 模型,形成一个HMI 模型表,下载到前端,由前端程序形成最终的HMI 页面。
HMI的分层结构
HMI 界面是一种分层结构,最顶层是Page,然后可以进一步分为面板(Panel),按钮,滑杆,仪表盘以及众多特定行业的HMI 单元,例如电机,阀门,反应釜等等。
复杂的HMI 是由基本的单元构建而成的。HMI模型化的第一步就是建立HMI基本单元的模型。
NMI 单元的模型
HMI 单元的模型由两个部分组成:
- 系统中的模型
HMI 单元的信息模型和系统中的其它节点是相同的,可以使用json模板来描述:
一个HMI 模板的实例-标题
Name:"Title",
DisplayName:"标题",
Description:"",
NodeType:"Object",
Catalog:["HMI","Data"],
Attributes:[
{Name:"Widget",Value:"TextBox"},
{Name:"Position",Value:[10,20]},
{Name:"Size",Value:[640,120]},
{Name:"BackgroundColor",Value:"Green"},
{Name:"Color",Value:"White"},
{Name:"Align",Value:"center"},
{Name:"Text",Value:"HMI Demostration"},
{Name:"FontSize",Value:"48px"},
],
Childs:[],
Reference:[]
}
由此可见,HMI 的信息模型的主要区别可能就是它们的属性比较多。
- 前端HMI UI组件
在HMI 的前端,要有一个UI 组件与信息模型相对应,平台能够根据系统的HMI模型生成和配置前端的UI 组件。
作为HMI单元的VUE组件
在我前面的博文中,曾经介绍使用Jquery,Bootstrap,html5,CSS,javascript 这些基础技术构建HMI UI组件。尽管这样做能够了解组件的底层逻辑,但是代码工作量比较大。在现代前端架构angular,VUE 中普遍基于了组件(Component)的技术。
组件是一段可重用的代码,这意味着我们创建一次并在整个 vue 应用程序中重用它。 vue组件是一个单一文件,将HTML,CSS和Javascript包含在一个文件中。
原始的HTML5 是将完整的页面归结为三个大的文件,它们分别是HTML,CSS和Javascript 文件。组件的思想就是根据以页面中的元素,分解成为一段一段的单元,也就是组件 这样的思想和我们系统模型的概念非常契合。因此,我主张使用VUE 组件来实现HMI 的UI 组件。
HMI 单元的组件有下面几个特点
- 绝对定位
HMI页面设计采用了类似图形设计软件的方式,直接将需要的组件放置在页面的合适位置,这就要求组件是绝对位置定位。
- 动态导入
HMI 页面是前端运行时根据HMI 节点的模型动态地生成的。因此,需要能够动态地导入组件。
- 以事件方式返回数据
一个HMI VUE 组件实例
<template>
<object ref='object'>
<b-button id="btn" variant="info" @click="clickConfirm()">Click</b-button>
<b-button id="btn" variant="info" @click="clickCancel()">Canel</b-button>
<img width="100" src="../assets/images/dout.svg">
</object>
</template>
<script>
export default {
name:"HMI_gauge",
data() {
return {
Name:"",
ID:0,
Options:{
Size:"400px",
Position:{
X:"400px",
Y:"20px"
}
},
}
},
components:{
},
mounted:function(){
this.$refs.object.style.top=this.Options.Position.Y;
this.$refs.object.style.left=this.Options.Position.X;
},
methods: {
clickConfirm(){
this.$emit('HMIEvent', {
"Event":"Confirm",
"Param":{
"ComponentName":this.Name
}
});
},
clickExit(){
this.$emit('HMIEvent', {
"Event":"Cancel",
"Param":{
"ComponentName":this.Name
}
});
}
}
}
</script>
<style scoped>
object {
position:absolute;
}
</style>
动态导入VUE 组件
前面提到,HMI组件不是静态导入。而且导入的组件的数量,类型都是不确定的。所以不能采取预先在Template 中定义组件标签,然后导入组件。要在挂载点Append child 的方式添加组件。
网络上有一些关于VUE 动态载入组件的介绍,但是都似乎有一些小问题,我尝试了几乎一天时间才实现。
我采用下面的方式导入HMI 组件
<template>
<div class="wrapper">
<div class="a">
<div id="mount-point" ref="mount-point"></div>
</div>
</div>
</template>
<script>
import Vue from 'vue';
export default {
name: "ExtendMode",
data(){
return {
instance: null
}
},
created:function(){
this.switchComponent("./HMI_gauge",{
Position:{
X:"100px",
Y:"100px"
}
});
this.switchComponent("./HMI_gauge",{
Position:{
X:"100px",
Y:"400px"
}
});
},
methods: {
switchComponent: function (name,Options) {
if(this.instance){
this.instance.$destroy();
this.$refs['mount-point'].removeChild(this.instance.$el);
}
import(`${name}`).then(component => {
let VueConstructor = Vue.extend(component.default); //使用Vue.extend创建组件构造器
this.instance = new VueConstructor({
data:{
Options:Options,
}
});
this.instance.$mount();
this.$refs['mount-point'].appendChild(this.instance.$el);//挂载到指定dom上
});
}
}
上面的例子中导入了两个组件。
组件与平台的通信
HMI 节点需要与外界交换信息。
值得一提的是,在节点中需要调用外部的方法。这可以通过Event 机制来实现:
this.$emit('HMIEvent', {
"Event":"CallMethod",
"Param":{
"ComponentName":this.Name,
"Method":"PublishData"
"Arguments":{....}
}
});
进一步地研究
由于本人对VUE 架构并不熟悉,本文中难免有不准确的地方。下一步要研究如何导入SVG 图形,VUE 组件与SVG 的交互等问题。
以上是关于使用VUE 组件实现HMI 模型的主要内容,如果未能解决你的问题,请参考以下文章