【经验分享】如何实现小程序代码热更新| 江海计划

简介: 【经验分享】如何实现小程序代码热更新| 江海计划

江海入海,知识涌动,这是我参与江海计划的第1篇。

前言:

对于开发小程序的同学来说,能不能实现这样的一个小需求:如何动态替换小程序的axml、js的代码?很多人的第一反应是使用富文本/eval语法等方式实现,但是富文本只能做页面代码的显示,对于js的逻辑处理是做不到的,而官方已经严禁使用eval语法了。

那么我们导致能不能实现动态生成小程序axml代码及动态js逻辑呢?既然今天分享了这篇文章,说明是有办法实现的,别方,接着往下看。


知识点:

  • template模板
  • 万能跳转


方向:

小程序开发者应该都知道目前各个平台的小程序都是支持template模板的,那么我们今天就通过template模板实现该功能,众所周知,前端代码里常用的都是div、ul、li、span、img、表单等等标签,那么我们的方案就是:使用模板循环嵌套遍历出匹配的标签,然后动态添加到axml上。以下图片是青团社内部的配置平台(外部有比较多的低代码搭建平台可供大家使用),当保存后会生成一套前后端约定好的类HTMLString 节点树。



通过拖动配置生成如下的类HTML String的配置。

{
      wxAppendData: [{
        "node": "config",
        "pageName": "page003",
        "topBarTitle": "青团RPO"
      }, {
        "node": "element",
        "tag": "img",
        "src": "https://qiniu-image.qtshe.com/1554357586839_24.png"
      }, {
        "node": "element",
        "tag": "img",
        "src": "https://qiniu-image.qtshe.com/1554357609062_218.png"
      }, {
        "node": "element",
        "tag": "btn",
        "content": "按钮1",
        "style": "position: absolute; top: 551px; left: 49px; width: 74px; height: 20px; "
      }, {
        "node": "element",
        "tag": "btn",
        "content": "按钮2",
        "style": "position: absolute; top: 551px; left: 154px; width: 74px; height: 21px; "
      }, {
        "node": "element",
        "tag": "btn",
        "content": "按钮3",
        "style": "position: absolute; top: 551px; left: 257px; width: 74px; height: 21px; "
      }, {
        "node": "element",
        "tag": "link",
        "style": "position: absolute; top: 65px; left: 31px; width: 316px; height: 70px; ",
        "url": "http://www.baidu.com"
      }]
    }

上述是配置平台后生成的节点树代码,然后下一步就是小程序里需要实现模版的遍历出小程序中对应的节点标签。

// 简单举个例子,可扩展
div => view
span => text
img => image
input type="button" => button

而对应小程序里模板内可一直嵌套,这样就可实现动态生成axml的代码了,以下代码只是简单的给大家提供思路:

<template name="Tmpl">
  <block a:for="{{wxAppendData}}" a:key="">
    <template is="Tmpl1" data="{{item}}" />
  </block>
</template>
<template name="Tmpl1">
  <block a:if="{{item.node == 'element'}}">
    <block a:if="{{item.tag == 'div'}}">
      <view style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="e895-1e11-9652-507e" class="ptp_exposure">
        {{item.content}}
        <block a:for="{{item.child}}" a:key="">
          <template is="Tmpl2" data="{{item}}" />
        </block>
      </view>
    </block>
    <!-- img标签 -->
    <block a:if="{{item.tag == 'img'}}">
      <image mode="widthFix" style="{{item.style}}" src="{{item.src}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="bd91-1cee-bdf5-7a5f" class="ptp_exposure" />
    </block>
    <!-- text标签 -->
    <block a:if="{{item.tag == 'span'}}">
      <text style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="b0cd-1dd5-80a9-910d" class="ptp_exposure">
        {{item.content}}
        <block a:for="{{item.child}}" a:key="">
          <template is="Tmpl2" data="{{item}}" />
        </block>
      </text>
    </block>
    <!-- button标签 -->
    <block a:if="{{item.tag == 'btn'}}">
      <button hover-class="none" style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="385a-15a5-b4af-803e" class="ptp_exposure">{{item.content}}</button>
    </block>
  </block>
</template>
<template name="Tmpl2">
  <block a:if="{{item.node == 'element'}}">
    <block a:if="{{item.tag == 'div'}}">
      <view style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="370d-1885-b971-b861" class="ptp_exposure">
        {{item.content}}
        <block a:for="{{item.child}}" a:key="">
          <template is="Tmpl3" data="{{item}}" />
        </block>
      </view>
    </block>
    <!-- img标签 -->
    <block a:if="{{item.tag == 'img'}}">
      <image mode="widthFix" style="{{item.style}}" src="{{item.src}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="1ac7-1d7c-bc86-360c" class="ptp_exposure" />
    </block>
    <!-- text标签 -->
    <block a:if="{{item.tag == 'span'}}">
      <text style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="2d35-12ec-ab8b-8a6b" class="ptp_exposure">
        {{item.content}}
        <block a:for="{{item.child}}" a:key="">
          <template is="Tmpl3" data="{{item}}" />
        </block>
      </text>
    </block>
    <!-- button标签 -->
    <block a:if="{{item.tag == 'btn'}}">
      <button hover-class="none" style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="9b24-1589-9178-e140" class="ptp_exposure">{{item.content}}</button>
    </block>
  </block>
</template>
<template name="Tmpl3">
  <block a:if="{{item.node == 'element'}}">
    <block a:if="{{item.tag == 'div'}}">
      <view style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="c059-14a4-a1e9-1f17" class="ptp_exposure">
        {{item.content}}
        <block a:for="{{item.child}}" a:key="">
          <template is="Tmpl4" data="{{item}}" />
        </block>
      </view>
    </block>
    <!-- img标签 -->
    <block a:if="{{item.tag == 'img'}}">
      <image mode="widthFix" style="{{item.style}}" src="{{item.src}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="29f1-15b9-8713-07d5" class="ptp_exposure" />
    </block>
    <!-- text标签 -->
    <block a:if="{{item.tag == 'span'}}">
      <text style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="884b-17ac-83bd-b0c3" class="ptp_exposure">
        {{item.content}}
        <block a:for="{{item.child}}" a:key="">
          <template is="Tmpl4" data="{{item}}" />
        </block>
      </text>
    </block>
    <!-- button标签 -->
    <block a:if="{{item.tag == 'btn'}}">
      <button hover-class="none" style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="7c3e-199e-8a0a-8458" class="ptp_exposure">{{item.content}}</button>
    </block>
  </block>
</template>
<template name="Tmpl4">
  <block a:if="{{item.node == 'element'}}">
    <block a:if="{{item.tag == 'div'}}">
      <view style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="c073-173b-87cb-b609" class="ptp_exposure">
        {{item.content}}
      </view>
    </block>
    <!-- img标签 -->
    <block a:if="{{item.tag == 'img'}}">
      <image mode="widthFix" style="{{item.style}}" src="{{item.src}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="d79c-1cd9-a0e7-573c" class="ptp_exposure" />
    </block>
    <!-- text标签 -->
    <block a:if="{{item.tag == 'span'}}">
      <text style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="a239-19a2-8534-a489" class="ptp_exposure">{{item.content}}</text>
    </block>
    <!-- button标签 -->
    <block a:if="{{item.tag == 'btn'}}">
      <button hover-class="none" style="{{item.style}}" data-param="{{item.param || '{}'}}" onTap="{{item.jump1 ? 'universalJump' : ''}}" data-ptpid="86a4-1e71-8c4e-fcf0" class="ptp_exposure">{{item.content}}</button>
    </block>
  </block>
</template>


那么对应的小程序js是如何动态的呢?前面说了个功能叫万能跳转,从字面意思可以理解为点击后可跳转至任意地方。如何实现万能跳转?

前端可以写死在小程序本地(当然配置也可以服务端返回),跟服务端同学约定好jumpKey的值,封装个universalJump方法。

// 万能跳转解析,这里列举几个例子,大家可按需加配置
universalJump(config) {
  let {
    title = '', jumpKey = '', param = '', subTitle = ''
  } = config
  try {
    if (param !== '') {
      param = JSON.parse(param)
    }
  } catch (error) {
    console.log('param参数非json字符串')
  }
  // 从万能跳转参数中寻找相关的字段值
  let findParamValue = (arr = [], key = 'targetUrl') => {
    let value = ''
    arr.map(item => {
      if (item.key === key) {
        value = item.value
      }
    })
    return value
  }
  // jumpKey为服务端约定的跳转方法名 
  switch (jumpKey) {
    case "USER_BENEFIT_LIST":
      // 举个例子:跳转到公益列表
      my.navigateTo({
        url: '/sundry/volunteerTravelList/index'
      })
      break
      // 静态页面
    case "USER_STATIC_PAGE":
      my.navigateTo({
          url: `/pages/webview/webview?targetUrl=${encodeURIComponent(targetUrl)}&shareTitle=${encodeURIComponent(title)}`
        })
      break
      // 跳转三方小程序
    case 'USER_THIRD_ZFB_APP_JUMP_PAGE':
      var appId = findParamValue(param, 'appId')
      var path = findParamValue(param, 'path') || ''
      my.navigateToMiniProgram({
          appId,
          path: decodeURIComponent(path)
      })
      break
  }
}

总结:

以上为青团社目前实现的动态生成axml代码,及万能跳转配置的动态化,仅供外部开发者参考。

目录
相关文章
|
1月前
|
开发框架 小程序 JavaScript
小程序代码丢失!反编译找回
小程序源代码的容易获取问题确实存在一些潜在的安全隐患。然而,现在的小程序开发框架采用像 Babel 这样的打包工具,将 JavaScript 逻辑代码混合在一个文件中并进行转编译,使其变得难以理解。
37 0
小程序代码丢失!反编译找回
|
6月前
|
JavaScript Java 测试技术
基于小程序的移动学习平台+springboot+vue.js附带文章和源代码说明文档ppt
基于小程序的移动学习平台+springboot+vue.js附带文章和源代码说明文档ppt
48 0
|
2月前
|
小程序 JavaScript Go
代码总有一个是你想要的分享63个微信小程序源
分享63个微信小程序源代码,包括电商系统、同城拼车、博客等多种应用,涵盖C#、Node.js、Golang等技术栈。每个项目附带源码和示例,适合初学者和开发者参考学习。提取码:8888,代码效果参考:http://www.603393.com/sitemap.xml。
64 2
|
3月前
|
小程序 前端开发 JavaScript
微信小程序实现微信支付(代码和注释很详细)
微信小程序实现微信支付(代码和注释很详细)
|
3月前
|
小程序 JavaScript 前端开发
微信小程序开发必备前置知识:基本代码构成与语法
【8月更文挑战第8天】微信小程序的基本代码构成与语法
102 0
微信小程序开发必备前置知识:基本代码构成与语法
|
3月前
|
小程序 JavaScript 安全
微信小程序实现云闪付支付(代码和注释很详细)
微信小程序实现云闪付支付(代码和注释很详细)
|
5月前
|
XML 小程序 Java
java小程序代码详细展示
java小程序代码详细展示
41 0
|
6月前
|
JavaScript Java 测试技术
基于小程序的汽车保养系统+springboot+vue.js附带文章和源代码说明文档ppt
基于小程序的汽车保养系统+springboot+vue.js附带文章和源代码说明文档ppt
38 0
|
6月前
|
JavaScript Java 测试技术
基于小程序的童装商城+springboot+vue.js附带文章和源代码说明文档ppt
基于小程序的童装商城+springboot+vue.js附带文章和源代码说明文档ppt
40 0
|
6月前
|
JavaScript Java 测试技术
基于小程序的个人行政复议在线预约系统+springboot+vue.js附带文章和源代码说明文档ppt
基于小程序的个人行政复议在线预约系统+springboot+vue.js附带文章和源代码说明文档ppt
37 0