Skip to content
On this page

让人无奈的微信小程序组件

本文相关代码地址:github


最近开发微信小程序碰到了蛮多问题,尤其是小程序里面的一些组件,实在是让人感觉即满心欢喜又无奈无语。

web-view

这个是首当其冲的组件了,业务部分场景中是使用的 H5 页面,尤其是活动页面是变化最频繁的,所以查看小程序文档,有这个组件真是让人欣喜;不过高兴太早了。

其通信机制真是让人无可奈何:

image.png可以看到组件限制有三点:

  • 自动铺满整个小程序页面
  • 导航栏不可以自定义
  • 两边通信需要特定的场景


小程序给 H5 发送消息容易实现,可以直接在访问链接上带上我们需要的参数消息

javascript
<web-view src="test.html?id=2"></web-view>

但是H5给小程序发送消息则需要在特定的场景:后退、销毁、分享三个场景页面才能与小程序通信。意思就是没有发生上面三个场景的情况下,小程序是无法通过 bindmessage 这个事件获取到页面消息。

我们大部分场景下是需要实时通信,这里使用后退这个场景来实现实时通信,但是这个其实是牺牲了用户体验:

image.png

中间页面 middle


利用中间页面 onLoad 中接收参数 options ,再根据 getCurrentPages 获取到需要返回到页面,设置需要的消息

javascript
onLoad(options) {

    const pages = getCurrentPages();
    console.log(`middle消息:`, options)

    const webviewPage = pages[pages.length - 2];

    webviewPage.setData(
      {
        options: options
      },
      () => {
        wx.navigateBack({
          delta: 0,
        });
      }
    );
  }

目标页面获取消息

由于通过 middle 页面设置了 data 数据 options 所以可以在程序内访问到实时的通信消息

javascript
onShow() {
    this.setData({
      src: 'https://imondo.cn/files/web.html'
    }, () => {
      console.log(`web页:`, this.data.options)
      if (this.data.options) {
        wx.showModal({
          title: this.data.options.msg
        });
      }
    })
  }

我们可以看到实际效果:
view.gif

scroll-view

这个滚动区域组件,应该是我们真常用的组件,但是它竖向滚动的时候,一定要给它设一个固定高度值,这也是一个奇葩的设定。
幸好小程序有 wx.createSelectorQuery 这个 API 来动态解决它的高度:

javascript
// view
<view>
  <view class="head">Head</view>
  <scroll-view scroll-y="true" style="height: {{scollHeight}}px">
    <block wx:for="{{20}}" wx:key="index">
      <view class="scroll-item">item</view>
    </block>
  </scroll-view>
</view>

// js
onShow() {
  const system = wx.getSystemInfoSync(); // 系统高度
  const height = system.windowHeight;
  this.queryEl(['.head']).then(rect => {
    const [{ height: ht }] = rect
    this.setData({
      scollHeight: (height - ht).toFixed(0)
    })
  })
},
queryEl(selector) {
  return new Promise(resolve => {
    const query = wx.createSelectorQuery(); // 如果是在 component 内需要使用 .in(this)
    if (Array.isArray(selector)) {
      selector.forEach(el => {
        query.select(el).boundingClientRect();
      })
    } else {
      query.select(selector).boundingClientRect();
    }
    query.exec(res => {
      resolve(res);
    })
  })
 }

实际效果如下:
scroll.gif

总结

小程序的组件使用过程中其实文档中都提到了相关的注意地方,但是我们的业务需求实在是多变,对于部分组件的不确定性需要好好的调研总结,希望小程序组件越来越完善吧~ 🤣