需求描述:需要在web端用js获取电子秤的重量。(由于erp限制的原因只能通过js获取,不能修改html,不能引用jquery)
实现目标:电子秤面板上的数据实时反映在我们公司内部erp系统界面上。
通常实现步骤:
首先要从web端获取串口数据需要用到activex(由于我们目前这个需求只需要考虑在IE浏览器下的正常运行)
网上关于对这个控件的调用一般是这样写的
<object classid="clsid:648A5600-2C6E-101B-82B6-000000000014" id="MSComm1" codebase="MSCOMM32.OCX" type="application/x-oleobject" style="left: 54px; top: 14px"> <param name="CommPort" value="4"> <!--设置并返回通讯端口号。--> <param name="DTREnable" value="1"> <param name="Handshaking" value="0"> <param name="InBufferSize" value="1024"> <param name="InputLen" value="0"> <param name="NullDiscard" value="0"> <param name="OutBufferSize" value="512"> <param name="ParityReplace" value="?"> <param name="RThreshold" value="1"> <param name="RTSEnable" value="1"> <param name="SThreshold" value="2"> <param name="EOFEnable" value="0"> <param name="InputMode" value="0"> <!--comInputModeText 0 (缺省) 通过 Input 属性以文本方式取回数据。comInputModeBinary 1 通过 Input 属性以二进制方式检取回数据。--> <param name="DataBits" value="8"> <param name="StopBits" value="1"> <param name="BaudRate" value="38400"> <param name="Settings" value="38400,N,8,1"> </object>
而由于前面所说的我们erp的限制,我无法修改html文件,因此无法在html文件中添加对MSCOMM32.dll的引用。因此我是用如下方法实现的:
//创建MSComm对象 function uf_GetSerPortData() { try { MSComm1 = new ActiveXObject("MSCOMMLib.MSComm.1"); if ((typeof (MSComm1) == "undefined") || (MSComm1 == null)) { alert("创建MSComm1对象失败!"); } else { //绑定事件 fn(); } } catch (err) { alert(err.description); } } var fn=function(){ function MSComm1::OnComm() { MSComm1_OnComm(); } }
在这里有两个地方需要解释一下:
- 打开端口的时候提示创建对象失败:
如果后面设置MSComm1的PortOpen提示失败时,就需要添加对MScomm控件的注册。具体的注册方法在如下链接里面有详细说明:http://jingyan.baidu.com/article/375c8e19a2953b25f2a22986.html
需要注意的是链接中给出的是32位系统的解决方案,对于64位系统路径可能有所不同。需要用户根据自己的系统情况进行修改。
- 绑定控件的事件:
我目前所使用的电子秤有两种输出模式,一种是连续输出打印的一种是在屏幕上按键打印输出的。现在我们讨论在连续输出模式下的问题。由于是连续输出因此我们需要对电子秤的输出做一个事件绑定,并且通过一个回调函数来实现获取重量数据后在erp中进行对应的数据展示。一般我们可以通过诸如下面的代码来实现事件绑定
<script language="javascript" for="window" event="onload"> ...... </script>
但是由于无法修改html代码,仅仅只能修改js代码的限制,我们现在无法通过这种方式实现事件绑定。(我也想过通过js动态在html中插入这段引用,但实际结果并没有触发事件,不知道是由于加载顺序的原因,还是erp本身对于这块的安全限制)因此我们只能另寻他法.在这里就用到了下面的代码了
function uf_GetSerPortData() { try { MSComm1 = new ActiveXObject("MSCOMMLib.MSComm.1"); if ((typeof (MSComm1) == "undefined") || (MSComm1 == null)) { alert("创建MSComm1对象失败!"); } else { //绑定事件 fn(); } } catch (err) { alert(err.description); } } var fn=function(){ function MSComm1::OnComm() { MSComm1_OnComm(); } }
对于 function MSComm1::OnComm() 这种写法,我之前从没见过,后来是在一篇博文上面看到的,试了下发现真的可以实现,事件绑定。这样就完成了在js中进行事件绑定了。后面的回调函数显示重量数值就很简单了。
下面贴上实现的完整代码(直接从实现demo当中抠出来的,关于数值显示的地方代码丑陋大家略过就行。但肯定是可以实现需求的,已经测试过)
//创建MSComm对象 function uf_GetSerPortData() { try { MSComm1 = new ActiveXObject("MSCOMMLib.MSComm.1"); if ((typeof (MSComm1) == "undefined") || (MSComm1 == null)) { alert("创建MSComm1对象失败!"); } else { //绑定事件 fn(); } } catch (err) { alert(err.description); } } var fn=function(){ function MSComm1::OnComm() { MSComm1_OnComm(); } } //事件响应 function MSComm1_OnComm() { switch(MSComm1.CommEvent) { case 1:{ window.alert("Send OK!"); break;} //发送事件 case 2: { Receive();break;} //接收事件 default: alert("Event Raised!"+MSComm1.CommEvent);; } } function OperatePort() { if(MSComm1.PortOpen==true) { try{MSComm1.PortOpen=false; SKButton1.value="打开串口"; }catch(ex) {alert(ex.message);} } else{ try{ MSComm1.PortOpen=true; MSComm1.InBufferCount = 0; SKButton1.value="关闭串口"; }catch(ex) {alert(ex.message);} } } function ConfigPort() { var comport=""; var boundRate=""; var jiaoyanwei=""; var shujuwei=""; var tingzhiwei=""; comport=SKDBcombobox1.value; boundRate=SKDBcombobox2.value; jiaoyanwei=SKDBcombobox3.value; shujuwei=SKDBedit5.value; tingzhiwei=SKDBedit6.value; if(MSComm1.PortOpen==false) { try{ /* MSComm1.CommPort=comport; MSComm1.Settings=boundRate+","+jiaoyanwei+","+shujuwei+","+tingzhiwei; MSComm1.OutBufferCount =0; //清空发送缓冲区 MSComm1.InBufferCount = 0; //滑空接收缓冲区 */ MSComm1.CommPort="4"; switch(SKDBcombobox1.value) { case "COM1": MSComm1.CommPort="1"; break; case "COM2": MSComm1.CommPort = "2"; break; case "COM3": MSComm1.CommPort = "3"; break; } MSComm1.Settings="9600"+ ","+"n"+ ","+"8"+ ","+"1"; MSComm1.OutBufferCount =0; //清空发送缓冲区 MSComm1.InBufferCount = 0; //滑空接收缓冲区 MSComm1.RThreshold=1; //接收一个字节就触发omcom事件 alert("已配置串口COM"+MSComm1.CommPort+"\n 参数:"+MSComm1.Settings); }catch(ex){alert(ex.message);} } else{ alert("请先关闭串口后再设置!");} } var tmpWeight = ""; //接收数据 function Receive() { //alert("InBufferCount::"+MSComm1.InBufferCount); var inputvalue = MSComm1.Input; if (inputvalue.indexOf(‘g‘) >= 0) { return; } // alert(inputvalue); tmpWeight+=inputvalue.replace(‘-‘, ‘‘); if(tmpWeight.length>16) { if(tmpWeight.indexOf(‘000‘)) { var weight=trim(tmpWeight.substr(5,5)); if(weight.indexOf(‘0‘)==0) { weight=weight.replace("0","0.") } SKDBedit7.value=weight; tmpWeight=""; } } //alert("InBufferCount::"+MSComm1.InBufferCount); } /* var weight; var myArray=new Array(); function GetWeight() { } */ function serPortInit() { SKDBcombobox1.value="COM4"; SKDBcombobox2.value="9600"; SKDBcombobox3.value="无NONE"; SKDBedit5.value="8"; SKDBedit6.value="1"; //初始化创建MSComm1对象 uf_GetSerPortData(); } function trim(str){ //删除左右两端的空格 return str.replace(/(^\s*)|(\s*$)/g, ""); } function ltrim(str){ //删除左边的空格 return str.replace(/(^\s*)/g,""); } function rtrim(str){ //删除右边的空格 return str.replace(/(\s*$)/g,""); }