阅读 357

微信小程序踩坑小结

去除 image 标签自带的 margin-bottom 值

小程序 image 标签,html img 自带 margin-bottom 值,会导致和下边元素产生距离

  • 方案一: 设置包裹 image 标签的容器css font-size: 0
  • 方案二: 设置 image 标签的 display:block

1rpx border ios真机显示不全问题

blog.csdn.net/c5211314963…

满足以下一种条件就出现bug

  1. 当标签的父容器宽度(单位rpx)÷2的值为 偶数或偶数.5 的时候会出现该bug,那么我们可以推到出用200.52=401,3022=604等等都会重现这个bug 导致左右边框可能显示不全 上下边框同理由于高度
  2. 当标签自身宽度(单位rpx)÷2的值为 偶数或偶数.5 的时候会出现该bug,那么我们可以推到出用200.52=401,3022=604等等都会重现这个bug 导致左右边框可能显示不全 上下边框同理由于高度

解决方案

  1. 改变宽高同时避免这两种情况出现,并且开发时 设置标签的宽高尽量 为 偶数
  2. 建议采用 transform: scale 实现 1px 边框
.border-1px {
  width: 200px;
  height: 50px;
  position: relative;
}
.border-1px::after {
  position: absolute;
  content: '';
  width: 200%;
  height: 200%;
  left: 0;
  top: 0;
  border-radius: 100px;
  border: 1px solid red;
  transform: scale(0.5);
  transform-origin: left top;
}
复制代码

iphone 上某些情况文字不能垂直居中

例如 设置 height28rpx,font-size18rpx时文字始终无法在 border 内垂直居中对齐

解决方案:

将字体大小改为16rpx或者以下。

暂时还没找到具体的规律,设计不同意将字体改下,最后解决是分andirod和ios分别设置不同的样式

iphone 上 textarea 设置padding值无效导致文字间距无法和andirod展示一致

解决方案:区分 andirod 和 ios 系统设置不同的样式使得展示一致,例: andirod 的情况下可设置 pading 值,ios 下设置 positon:raletive 位移

动画设置技巧

当动画需要在动画完成前或者后不出现在页面内,可将动画初始位置置于视野外

强制开启同层渲染

使原生组件也可同层渲染,通过z-index控制层级

"window": {
    "renderingMode": "mixed"
  },
复制代码

性能篇

  1. 简化需要展示的dom结构,例如长列表隐藏不在视窗内的元素
  2. 简化数据setData操作
  3. 拆分组件复用,图片资源压缩上cdn,小程序分包预加载

性能体验

  1. 不使用:active伪类,并使用hover-class替换:active

  2. iPhone X 兼容

padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
复制代码

惰性函数的使用

获取某些耗时且不会更改的信息的时候可考虑使用惰性函数进行封装避免多次耗时操作

例:获取系统信息等

简易版

let systemInfo = null
function getInfo() {
    if (!systemInfo) {
      systemInfo = wx.getSystemInfoSync()
    }
    return systemInfo
}
复制代码

惰性函数版:推荐

export let systemInfo = function() {
  const res = wx.getSystemInfoSync()
  systemInfo = function() {
    return res
  }
  return systemInfo()
}
复制代码

setData 数据量过大

当 setData 过大时会提示错误

vdSyncBatch 数据传输长度为 2260792 已经超过最大长度 1048576
复制代码

因为setData设置的数据量是有限制的,单次设置的数据大小不得超过1024kb,否则就会出现如上错误

解决方案:将数组转成二维数组后进行setData,并且需要修改wxml的循环结构,多套一层循环。

伪代码

data:{
  // 当前页数
  pageNo:0,
  // 数据源
  list:[]
},

getListData:function(){
  // 本次加载的数据
  let _list = [];
  ...
  setData({
       ['list[' + pageNo + ']']: _list,
  });
}
复制代码

超长滚动列表,上拉加载过多后内存溢出性能优化

当列表页面上拉加载数据到一定量时,占内存过高,导致小程序卡顿甚至黑屏关闭。

解决思路:让不在当前窗口区域内的内容wxml结构移除。

操作思路:封装一个列表item的容器组件,利用 createIntersectionObserverrelativeToViewportobserve 方法监听当前 item 所在位置,进行移除或者插入

核心代码

组件skeleton.wxml

<view class="list-item" id="list-item-{{uniqueId}}" style="min-height: {{height}}px;">
	<block wx:if="{{showSlot}}">
		<slot></slot>
	</block>
</view>
复制代码

组件skeleton.js

...

ready() {
    // 修改了监听是否显示内容的方法,改为前后showNum屏高度渲染
    // 监听进入屏幕的范围relativeToViewport({top: xxx, bottom: xxx})
    const { windowHeight = 667 } = systemInfo()
    const showNum = this.data.showNum //超过屏幕的数量,目前这个设置是上下2屏
    try {
      this.IntersectionObserver = this.createIntersectionObserver()
      this.IntersectionObserver.relativeToViewport({
        top: showNum * windowHeight,
        bottom: showNum * windowHeight
      }).observe(`#list-item-${this.data.uniqueId}`, res => {
        let { intersectionRatio } = res
        if (intersectionRatio === 0) {
          console.log('【卸载】#', this.data.uniqueId, '超过预定范围,从页面卸载')
          this.setData({ showSlot: false })
        } else {
          console.log('【进入】#', this.data.uniqueId, '达到预定范围,渲染进页面')
          this.setData({
            showSlot: true,
            height: res.boundingClientRect.height
          })
        }
      })
    } catch (error) {
      console.log(error)
}
...
复制代码

demo 示例

获取自定组件节点实例

注意使用.in(this)

Component({
  queryMultipleNodes (){
    const query = wx.createSelectorQuery().in(this)
    query.select('#the-id').boundingClientRect(function(res){
      res.top // 这个组件内 #the-id 节点的上边界坐标
    }).exec()
  }
})
复制代码

不常用参数

  1. EventChannel 页面间事件通信通道

只有 wx.navigateTo() 中可使用

示例代码

wx.navigateTo({
  url: 'test?id=1',
  events: {
    // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
    acceptDataFromOpenedPage: function(data) {
      console.log(data)
    },
    someEvent: function(data) {
      console.log(data)
    }
    ...
  },
  success: function(res) {
    // 通过eventChannel向被打开页面传送数据
    res.eventChannel.emit('acceptDataFromOpenerPage', { data: 'test' })
  }
})
复制代码
//test.js
Page({
  onLoad: function(option){
    console.log(option.query)
    const eventChannel = this.getOpenerEventChannel()
    eventChannel.emit('acceptDataFromOpenedPage', {data: 'test'});
    eventChannel.emit('someEvent', {data: 'test'});
    // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
    eventChannel.on('acceptDataFromOpenerPage', function(data) {
      console.log(data)
    })
  }
})
复制代码
关注下面的标签,发现更多相似文章
评论