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

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

江海入海,知识涌动,这是我参与江海计划的第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代码,及万能跳转配置的动态化,仅供外部开发者参考。

目录
相关文章
|
5天前
|
存储 小程序 UED
微信小程序代码包限制2M 怎么解决?
微信小程序代码包限制2M 怎么解决?
|
6月前
|
小程序 JavaScript API
小程序云开发实战三:编写云函数代码
小程序云开发实战三:编写云函数代码
48 0
|
5天前
|
小程序
外卖小程序-购物车模块表结构设计和后端代码
外卖小程序-购物车模块表结构设计和后端代码
14 0
|
5天前
|
小程序 开发者
微信小程序“Error: xxx.js 已被代码依赖分析忽略,无法被其他模块引用”报错?
微信小程序“Error: xxx.js 已被代码依赖分析忽略,无法被其他模块引用”报错?
|
5天前
|
存储 小程序 前端开发
Java代码能搭建小程序
Java代码能搭建小程序
21 0
|
5天前
|
小程序
微信小程序下载代码
微信小程序下载代码
|
5天前
|
JavaScript 小程序
微信小程序的双向数据绑定和vue的哪里不一样?下拉刷新的方式代码示例
微信小程序的双向数据绑定和vue的哪里不一样?下拉刷新的方式代码示例
|
5天前
|
小程序 前端开发 IDE
【经验分享】支付宝小程序订阅消息功能实操(前端篇)|江海计划
【经验分享】支付宝小程序订阅消息功能实操(前端篇)|江海计划
166 7
|
5天前
|
小程序 JavaScript IDE
【社区每周】如何实现小程序代码热更新?芝麻工作证新增“企业员工”职业身份验证(1月第四期)
【社区每周】如何实现小程序代码热更新?芝麻工作证新增“企业员工”职业身份验证(1月第四期)
19 0
|
5天前
|
小程序 API
微信小程序飞机大战游戏步骤及代码
微信小程序飞机大战游戏步骤及代码
100 0

热门文章

最新文章