需求描述:需要在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中進行事件綁定了。后面的回調函數顯示重量數值就很簡單了。
其中 new ActiveXObject("MSCOMMLib.MSComm.1"); 引號中的是activex控件的ProgID,在注冊表中classid所對應下的項中可以找到。也就是創建控件的時候起的名字。
下面貼上實現的完整代碼(直接從實現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,"");
}