当前位置:首页 » 《随便一记》 » 正文

利用renderjs在app端加载for web库

3 人参与  2024年02月23日 15:31  分类 : 《随便一记》  评论

点击全文阅读


需求背景

公司网页端地图实现使用的是天地图,且已经在其基础上开发了很多功能,现在要在 app 上也实现地图功能,但是 uni-app 官方的 Map 组件只支持 高德、谷歌、腾讯等。为了方便复用已有功能和避免重复购买,要想办法在 app 端也能使用 天地图

技术分析

已知 uni-app 打包出的 app 实际上是一个套壳的网页,在 webview 外层套了一层 app 的壳子,而在 webview 上肯定是支持使用 h5 的那一套东西的。那我们就得想办法操控 webview,实际上 uni-app 官方提供了一个 webview 组件:

在这里插入图片描述
那么利用它我们肯定可以实现需求,但本文重点说的不是它,而是另一个有趣得东西——renderjs:

在这里插入图片描述

我们主要关注它的第二个主要作用:在视图层操作dom,运行 for webjs库,好,听起来不错,动手试试吧:

技术实现

页面结构和样式

这一块就比较简单,搞个容器用来展示地图

<template>  <view>    <view id="tmap-box"></view>  </view></template><style lang="scss" scoped>  #tmap-box {    width: 668rpx;    height: 900rpx;  }</style>

页面逻辑

<script>  export default {    data() {      return {            }    }  }</script><script module="TMap" lang="renderjs">  export default {    data() {      return {        tMapInstance: null, // 天地图      }    },    mounted() {      const tmapScript = document.createElement('script')      tmapScript.src = `https://api.tianditu.gov.cn/api?v=4.0&tk=${'天地图密钥'}`      tmapScript.type = "text/javascript"      document.head.appendChild(tmapScript)      tmapScript.onLoad = this.initMap.bind(this)    },    methods: {      initMap() {        this.tMapInstance = new T.Map('tmap-box')        const lnglat = new T.LngLat(116.40969,39.89945)        this.tMapInstance.centerAndZoom(lnglat,12)      }    }  }</script>

可以看到,我们搞了两个 script 标签,第一个就是我们平时页面的 script,我们姑且称为 “原始模块”,第二个我们加了 module="TMap" lang="renderjs" 这两个属性,而这个 script 就是 renderjs 的模块,命名为 “TMap模块”,而我们加载天地图的逻辑主要在 TMap 模块中。

效果

在这里插入图片描述

两个模块间通信

renderjs模块向原始模块发送信息

renderjs 模块任意位置可以调用 this.$ownerInstance.callMethod('methodName', data) 来向原始模块发送信息。

而在原始模块中需要提前定义函数 methodName

methods: {  methodName(data) {    // 接收到 renderjs 模块传过来的信息 data  }}

那我们可以在 renderjs 模块定义一个统一发送的函数,在原始模块中定义一个统一接收的函数:

// renderjsmethods: {  sendMsg(msg, data) {    this.$ownerInstance.callMethod('reciveMessage', {      msg,      data    })  }}// 原始模块methods: {  reciveMessage(msgObj) {    console.log(msg.data)    switch (msgObj.msg) {      case 'a':        // ....        break      case 'b':        // ....        break    }  }}

原始模块向renderjs模块发送消息(renderjs模块监听原始模块数据变化)

其实原始模块没法主动向 renderjs 模块发送消息,而是 renderjs 模块可以选择监听原始模块某些数据的变化

绑定监听

以我之前的例子来说,假如原始模块的 data 中有这些数据:

data() {  return {    flag: false,    str: '',    num: 0,    arr: [],    obj: {      a: false,      b: '111',      c: 0,      d: [],      e: {},      f: null    }  }}

那么在原始模块需要这样绑定:

<template>  <view     :flag="flag"    :change:flag="TMap.handleFlagChange"    :str="str"    :change:str="TMap.handleStrChange"    :num="num"    :change:num="TMap.handleNumChange"    :arr="arr"    :change:arr="TMap.handleArrChange"    :obj="obj"    :change:obj="TMap.handleObjChange"  >    <view id="tmap-box"></view>  </view></template>

而在 TMap 模块中就需要定义对应的处理函数:

methods: {  handleFlagChange(nV, oV) {    // 页面刚加载的时候会触发一次,nV 打印 false,oV 打印 undefined    if(oV !== undefined) {      // 处理逻辑    }  },  handleStrChange(nV, oV) {    // 页面刚加载的时候会触发一次,nV 打印 '111',oV 打印 undefined  },  handleNumChange(nV, oV) {    // 页面刚加载的时候会触发一次,nV 打印 0,oV 打印 undefined    },  handleArrChange(nV, oV) {    // 页面刚加载的时候会触发一次,nV 打印 [],oV 打印 undefined    },  handleObjChange(nV, oV) {    // 页面刚加载的时候会触发一次,nV 打印 { a: false, b: '111',  c: 0, d: [], e: {}, f: null },oV 打印 undefined    },}

是不是有点向平时 vue 中使用的 watch ?,要注意的是,这些监听函数在页面刚加载的时候就会执行一次,打印的 nV 的值就是原始模块中绑定的初始值,oV 的值则都是 undefined,所以要判断后再处理。

注意

renderjs 模块和原始模块不能互相访问对方 data 中绑定的属性的,即:

<template>  <view>    <view id="tmap-box"></view>  </view></template><script>  export default {    data() {      return {        flagA: false      }    },    mounted() {      console.log(this.flagB) // 报错    }  }</script><script module="TMap" lang="renderjs">  export default {    data() {      return {        flagB: false      }    },   mounted() {      console.log(this.flagA) // 报错   }  }</script>

而如果想在 renderjs 模块中直接访问原始模块中的数据,则需要像之前说的一样绑定属性和处理函数:

<template>  <!-- 不能只绑定属性,一定要同时绑定处理函数 -->  <view :flagA="flagA" :change:flagA="TMap.handleChangeFlagA">    <view id="tmap-box"></view>  </view></template><script>  export default {    data() {      return {        flagA: false      }    }  }</script><script module="TMap" lang="renderjs">  export default {   mounted() {      console.log(this.flagA) // false   },   methods: {     handleChangeFlagA(nV, oV) {       // 不用做任何处理,但这个函数一定要有     }   }  }</script>

至于想在原始模块中访问 renderjs 模块中的数据,目前好像没有办法,也可能是我不知道。

总结

renderjs 使用起来还是很麻烦的,但是它可以使你的 app 可以使用 for web 的库,这个作用还是很大的,而它的语法和使用方式,我也了解的不太全面,大家文章中也可能有错误的和不全面的地方,大家有懂得欢迎评论区指正,谢谢。


点击全文阅读


本文链接:http://m.zhangshiyu.com/post/69626.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1