乐趣区

vue项目中indexhtml数据与组件之间通信传值以获取MAC地址为例

最近在项目里接手别人的代码来做完善,其中一个是修复获取不到 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…

退出移动版