最近在專案裡接手別人的程式碼來做完善,其中一個是修復獲取不到MAC地址的bug,仔細看了下程式碼,發現需要用到Activex控制元件。
上一位同事在寫的時候把<object></object>寫在index.html檔案中,獲取mac地址的js程式碼也寫在了index.html中,讀取完之後儲存在localStorage裡面,但是這裡有個問題,這個Activex控制元件獲取mac地址是一個非同步操作,如果第一次獲取mac地址並且快取沒有mac地址的資訊,必定會報錯。
這次修改的關鍵點就是如何將這個非同步操作變成同步操作,或者當控制元件獲取到mac之後傳播到元件裡,元件再做相對應的動作。
所以,演變成index.html檔案的資料如何跟元件通訊。
既然找到關鍵點,那麼就來解決問題吧!
我們都知道vue元件裡通訊有幾個辦法:
子 -> 父元件通訊:子元件$on,父元件$emit;
父 -> 子元件通訊:子元件定義props,父元件使用子元件時通過props向子元件傳值;
兄弟元件或者平行元件:定義一個eventBus,引入eventBus,通過eventBus的$on和$emit來通訊;
如果專案比較大,推薦使用vuex來通訊。
上面的方法,在index.html中貌似都用不上...除非將它們綁在window物件上...
所以變通一下,
在main.js檔案中:
window.eventBus = new Vue();
接下來我們在index.html中的script標籤列印下eventBus:
很好,能列印出來就行。
index.html檔案,在body標籤裡插入:
<object classid="CLSID:76A64158-CB41-11D1-8B02-00600806D9B6" id="locator" style="display:none;visibility:hidden"></object>
<object classid="CLSID:75718C9A-F029-11d1-A1AC-00C04FB6C223" id="foo" style="display:none;visibility:hidden"></object>
script程式碼:
<script FOR="foo" EVENT="OnObjectReady(objObject,objAsyncContext)" LANGUAGE="JScript">
var IPEnabled = objObject.IPEnabled;
var IPAddress = objObject.IPAddress(0);
if (IPEnabled != null && IPEnabled != "undefined" && IPEnabled == true ) {
if (IPAddress) {
window.sIPAddr = objObject.IPAddress(0);
}
if (objObject.MACAddress) {
window.sMacAddr = objObject.MACAddress;
}
if (objObject.DNSHostName) {
window.sDNSName = objObject.DNSHostName;
}
}
</script>
<script FOR="foo" EVENT="OnCompleted(hResult,pErrorObject, pAsyncContext)" LANGUAGE="JScript">
// console.log("獲取mac地址成功:", sMacAddr);
window.eventBus.$emit('getMac', window.sMacAddr);
</script>
vue元件裡的方法:
clickPort() {
var userAgent = navigator.userAgent;
if (userAgent.indexOf(".NET") > -1 && userAgent.indexOf("NT 10.0") > -1) {
var service = locator.ConnectServer(); // eslint-disable-line
service.Security_.ImpersonationLevel = 3;
service.InstancesOfAsync(foo, "Win32_NetworkAdapterConfiguration"); // eslint-disable-line
}
eventBus.$off('getMac'); // 關閉上一次的監聽
eventBus.$on('getMac', (_mac) => {
alert(`獲取MAC地址:${_mac}`);
this.msg = _mac;
});
}
ok,來執行一把:
成功!
以上是第一種方法,利用的是eventBus,記住在使用eventBus的時候,記得關閉上一次的監聽
下面是第二種方法:
怎麼在index.html中給元件賦值呢?或者說怎麼呼叫元件裡的方法呢?
利用同樣的原理,將this繫結到window上就可以了。
上程式碼,
元件:
clickPort() {
var userAgent = navigator.userAgent;
window.thisComponent = this; // 將元件例項賦予一個全域性變數
if (userAgent.indexOf(".NET") > -1 && userAgent.indexOf("NT 10.0") > -1) {
var service = locator.ConnectServer(); // eslint-disable-line
service.Security_.ImpersonationLevel = 3;
service.InstancesOfAsync(foo, "Win32_NetworkAdapterConfiguration"); // eslint-disable-line
}
}
index.html:
<script FOR="foo" EVENT="OnCompleted(hResult,pErrorObject, pAsyncContext)" LANGUAGE="JScript">
// 先判斷是否存在window.thisComponent.componentThis為vue元件例項
if (window.thisComponent) {
// 將mac地址賦予例項的一個屬性
window.thisComponent.sMacAddr = window.sMacAddr;
// 致空,以免造成記憶體洩露;
window.thisComponent = null;
// console.log(window.componentThis);
}
</script>
執行一把:
沒毛病,並且直接在模板裡展示出來;
使用第二種方法,需要在元件的data函式中初始化sMacAddr欄位,否則不會在模板中展示出來,並且在index.html檔案中window.thisComponent.sMacAddr,這裡的sMacAddr欄位必須跟元件裡初始化的欄位一致
總結:
在這無論用哪個方法,都得利用到window這個物件;這個也是沒辦法的事,其實利用同樣的道理,也是直接繫結在VUE的例項上;
條條大路通羅馬,小弟獻上一點技巧。
文章參考:https://blog.csdn.net/zyw_anq...
歡迎轉載,轉載請注出處!https://segmentfault.com/a/11...