# 小程序常见问题

# 用户登录

小程序有自己的登录方法 wx.login(),可以用来获取微信用户的信息,做一下简单的处理,但只有这是不够的,我们需要配合后台实现自己的登录,用来做鉴权验证。

实现自己的登录流程大概分为下面几步:

  1. 调用wx.login()方法获取微信登录凭证(code)

  2. 通过wx.getUserInfo()方法获取加密数据和加密算法

  3. 把获取的code和加密数据、加密算法通过登录接口传给后端进行验证登录

  4. 登录成功后返回token、用户信息、openid等信息

  5. 把token缓存起来,调用接口传入进行鉴权

  6. 没有token或者token过期则跳转到登录页重新登录

  7. 结合权限设置进行其他判断处理

// empower/index.js
import { miniLoginApi } from '../../api/login'
Page({
  data: {
    code: '' // 登录凭证
  },
  
  onLoad: function () {
    const that = this
    // 获取登录凭证
    wx.login({
      success(res) {
        const { code } = res
        console.log(code)
        that.setData({
          code
        }, () => {
          that.getAuthSetting()
        })
      }
    })
  },


  /**
   * 获取用户的当前授权设置。
   * 返回值中只会出现小程序已经向用户请求过的权限。
   * */ 
  getAuthSetting() {
    const that = this;
    wx.getSetting({
      success(res) {
        console.log(res)
        const { authSetting } = res
        if (authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称
          wx.getUserInfo({
            success: function(res) {
              console.log(res)
              // 获取加密算法和加密数据
              const { encryptedData, iv } = res
              that.userLogin(encryptedData, iv)
            }
          })
        } else {
          
        }
      }
    })
  },


  // 登录
  userLogin(encryptedData, iv) {
    const that = this
    const { code } = this.data
    const params = {
      code,
      encryptedData,
      iv
    }
    miniLoginApi(params)
      .then((res) => {
        if (res.code !== 200) {
          wx.showToast({
            title: res.msg,
            icon: 'none',
            duration: 2000
          })
          return
        }
        console.log(res)
        const { data, token } = res
        wx.setStorageSync('token', token)
        wx.setStorageSync('userInfo', data)
        // 登录成功跳转到首页
        wx.navigateTo({
          url: '/pages/index/index'
        })
      }).catch((err) => {
        console.log(err)
        wx.showToast({
          title: err.errMsg,
          icon: 'none',
          duration: 2000
        })
      })
  }
})

# data数据修改

通过[]中括号包裹起来,里面要改变的字段通过模板字符串拼接起来。

// 对象修改
this.setData({
  [`userBaseInfo.${field}`]: e.detail.value
})


// 数组修改
this.setData({
  [`resourceList.[${index}].value`]: e.detail.value
})


// 或者直接修改数据本身再赋值
const resourceList = this.data.resourceList
resourceList[index].value = e.detail.value
this.setData({
  resourceList: resourceList
})

# 函数绑定参数

绑定事件参数数据通过data-="{{}}" 来传,然后通过事件event来获取。

<view 
  class="title-name" 
  wx:for="{{resourceList}}" 
  wx:key="index" 
  data-index="{{index}}" 
  bindtap="openSinSelect"
></view>


openSinSelect(e) {
  const { index } = e.currentTarget.dataset;
  console.log(index)
}

# 页面跳转

// tabbar跳转
wx.switchTab({
  url: '/pages/index/index'
})


// 正常页面跳转
wx.navigateTo({
  url: `/pages/my/index?id=${id}&title=${title}`,
})

# 双层for循环渲染

<view class="wrap-step" wx:for="{{flowList}}" wx:key="index">
  <view class="step-user">
    <view class="user-item" wx:for="{{item.userList}}" wx:for-index="idx" wx:for-item="user" wx:key="idx">
      <view class="item-role">{{user.name}}</view>
    </view>
  </view>
</view>

# globalData对象的获取

在app.js中globalData对象中的值可以在全局所有页面中进行获取和设置,一些基础的数据或配置如请求地址等可以放在此处。

// app.js
// 在app.js中调用方法要注意是否异步,如果是异步,其他页面无法保证调取后获取。




// 其他方法
getUseInfo() {},


globalData: {
  baseUrl: 'http://xxxx.xx'
}

获取与调用方法

const appInstance = getApp();
const { baseUrl } = appInstance.globalData;


Page({
  onLoad: function () {
    console.log(baseUrl);
    
    // 调用app全局方法
    appInstance.getUseInfo();
  }
})

# onShow里获取参数options

onShow() {
  const pages = getCurrentPages()
  const currentPage = pages[pages.length - 1]
  const options = currentPage.options
  console.log(options);
}

# 动态设置标题

默认标题可以在.json中的navigationBarTitleText设置。

 wx.setNavigationBarTitle({
  title: '首页'
})

# 页面周期函数与组件周期函数

//index.js
Page({
  data: {
    text: "This is page data."
  },
  onLoad: function(options) {
    // Do some initialize when page load.
  },
  onShow: function() {
    // Do something when page show.
  },
  onReady: function() {
    // Do something when page ready.
  },
  onHide: function() {
    // Do something when page hide.
  },
  onUnload: function() {
    // Do something when page close.
  },
  onPullDownRefresh: function() {
    // Do something when pull down.
  },
  onReachBottom: function() {
    // Do something when page reach bottom.
  },
  onShareAppMessage: function () {
    // return custom share data when user share.
  },
  onPageScroll: function() {
    // Do something when page scroll
  },
  onResize: function() {
    // Do something when page resize
  }
})

# 下拉刷新与滑动加载更多

上拉和下拉滑动我们可以借助容器组件 scroll-view

可滚动视图区域。使用竖向滚动时,需要给一个固定高度,通过wxss 设置。 我们把要滚动的内容放到scroll-view容器中,然后给这个容器设置高度,就可以在这个高度内进行监听上拉或下拉了。

<view class="main">
  <scroll-view 
    class="main-wrap" 
    scroll-y 
    scroll-with-animation 
    enable-back-to-top 
    scroll-top="{{0}}" 
    refresher-enabled="{{true}}" 
    refresher-triggered="{{isFefresher}}" 
    bindscrolltolower="pullUpLoadMore" 
    bindrefresherrefresh="pullDownRefresh"
  >
    <view class="wrap-list" wx:if="{{userList.length}}">
      <view class="list-item" wx:for="{{userList}}" wx:key="index">
        <view class="item-detail"></view>
      </view>
    </view>
    <block wx:else>
      <van-empty description="暂无数据" />
    </block>
  </scroll-view>
</view>

CSS设置

.main {
  width: 100%;
  height: 100%;
  .main-wrap {
    width: 100%;
    height: 100%;
    .wrap-list {
      width: 100%;
    }
  }
}

通过总数和已加载数判断是否加装完成。

const app = getApp()
const { interfaceUrl } = app.globalData;


Page({
  data: {
    pagination: {
      page: 1,
      limit: 20,
      total: 0,
      flag: false
    },
    userList: [],
    isFefresher: false, // 下拉刷新
  },


  onLoad (option) {
    this.getApprovalList()
  },




  // 获取列表
  getUserList() {
    const that = this;
    const { userList, pagination } = this.data;
    const { page, limit } = pagination;
    const params = {
      page,
      limit
    }
    wx.showLoading({
      title: '加载中...',
    })
    wx.request({
      url: `${interfaceUrl}/api/xxx`,
      method: 'GET',
      data: params,
      header: {
        'Authorization': wx.getStorageSync('token'),
      },
      success(res) {
        wx.hideLoading();
        if (res.data.code != 200) {
          Dialog.alert({
            title: '提示',
            message: res.data.msg
          })
          return
        }
        const { data, total } = res.data.data;
        that.setData({
          isFefresher: false,
          userList: that.data.isFefresher ? data : userList.concat(data),
          ['pagination.total']: total
        })
      },
      fail(err) {
        wx.hideLoading()
        Dialog.alert({
          title: '错误',
          message: err.response.data.msg,
        })
      }
    })
  },


  // 上划加载更多
  pullUpLoadMore() {
    let { flag, page, limit, total } = this.data.pagination;
    if (flag) return
    if (page >= total / limit) {
      Notify({ type: 'warning', message: '已经全部加载', duration: 1000 });
      this.setData({
        ['pagination.flag']: true
      })
      return
    }
    this.setData({
      ['pagination.page']: page += 1
    })
    this.getUserList();
  },


  // 下拉刷新
  pullDownRefresh(e) {
    this.setData({
      ['pagination.page']: 1,
      ['pagination.flag']: false,
      isFefresher: true
    })
    this.getUserList()
  },
})

另一种方法,使用自带的周期函数。

onPullDownRefresh() {}


监听用户下拉刷新事件。
需要在app.json的window选项中或页面配置中开启enablePullDownRefresh。
可以通过wx.startPullDownRefresh触发下拉刷新,调用后触发下拉刷新动画,效果与用户手动下拉刷新一致。
当处理完数据刷新后,wx.stopPullDownRefresh可以停止当前页面的下拉刷新。


onReachBottom() {}
监听用户上拉触底事件。
可以在app.json的window选项中或页面配置中设置触发距离onReachBottomDistance。
在触发距离内滑动期间,本事件只会被触发一次。


onPageScroll(Object object) {}
监听用户滑动页面事件。

# 获取当前页面路由信息

const pages = getCurrentPages();
const currentPage = pages[pages.length - 1];
// 当前页面路由
console.log(currentPage.route); // pages/index/index

# 背景图片使用问题

小程序使用CSS设置背景无法直接使用本地图片。只能使用base64图片地址,或者使用网络地址图片。

解决方案:

  • 使用image在布局下面覆盖一张图片。推荐使用

  • 将图片通过在线转化网站,转化成base64格式。

  • 直接使用网络图片。

# 自定义用户分享内容

小程序分享功能通过添加生命周期函数onShareAppMessage来实现,自定义分享内容主要通过该函数返回一个对象来定义,自定义的图片不论多大都需要保持 5:4 的比例在分享的时候才不会变形。

//index.js
Page({
  data: {
    text: "This is page data."
  },
  onLoad: function(options) {
    // Do some initialize when page load.
  },
  // 分享到用户
  onShareAppMessage: function () {
    // 不写默认分享当前页面
    return {
      title: '分享标题',
      path: '/page/user?id=123', // 页面地址
      imageUrl: '../../assets/images/defaultAvatar.png',
      // promise, 这可以是一个promise对象,通过接口返回return对应内容,会直接替换上面的自定义
    }
  },
  // 分享到朋友圈
  onShareTimeline: function() {
    // Do something when page scroll
  }
})

# wxml转图片实现分享图片

小程序分享图片功能一般通过dom转canvas来生成图片实现,dom转canvas简单的可以自己手写来实现,和实现手写签名类似,也可以通过现有插件来实现,目前找到好用插件只有Painter (opens new window) 其他几款插件都不太行,我们可以直接使用Painter来实现转canvas生成对应图片进行分享。

# 获取微信授权信息

获取微信授权,在获取之前要先判断用户有没有开启授权,没有开启,需要先跳转到授权权限设置页提示用户先把授权权限打开,然后再调用授权接口让用户同意授权,同意授权后再我们获取授权后的信息进行设置,没有就继续提示用户授权。

目前基础信息授权模块已经不需要用户进行设置,默认开启,像获取地理位置、定位、摄像头等都需要用户先进行授权才能使用。

获取授权我们调用接口就可以直接在用户打开页面之前自动提示要用户授权,不需要其他操作。

// 获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限。
wx.getSetting()


// 调起客户端小程序设置界面,返回用户设置的操作结果。
// 如果用户关闭授权权限,手动打开提示用户选择授权,然后再获取授权信息
wx.openSetting()


// 获取精确地理位置,使用此方法需要在app.json进行设置才能使用
// https://developers.weixin.qq.com/community/develop/doc/000a02f2c5026891650e7f40351c01
wx.getLocation()


// 用户信息(小程序已回收,请使用头像昵称填写,小游戏可继续调用)
wx.getUserInfo()

# 公众号链接跳转到详情页

小程序在管理后台配置好公众号后就可以在公众号发起消息,然后通过公众号跳转到小程序页面,这个发起消息和配置主要是后端进行配置,我们只需要告诉后端要跳转的地址页面和传的参数就行了,跳转和我们自己进行页面跳转一样,然后在周期函数中接收参数。

跳转进来一定要先判断登录是否过期,要么在接口中统一判断,要么在当前页面接口判断。

// 给后端的跳转地址
'/pages/approvalDetail/index?approval_id=123'


// 在页面中接收
onLoad(option) {
  const { approval_id } = option
  console.log(approval_id)
},

从不同地方跳转这也涉及到了小程序场景中的判断,微信提供了不同地方跳转进来的场景中,我们可以根据此值进行相应的操作。

场景值-列表 (opens new window)

# 图片上传

小程序上传文件通过 wx.uploadFile() 方法调用后端的上传接口进行上传,而不是直接使用 wx.request() 上传。

我们借助vant 的上传组件进行上传图片。

<van-uploader 
  accept="image" 
  file-list="{{ remarkData.fileList }}" 
  preview-size="60" 
  deletable="{{ true }}" 
  bind:after-read="changeTranImage" 
  bind:delete="deleteTranImage"
>
</van-uploader>
data: {
  fileList: []
}




// 附件上传,获取文件内容
changeTranImage(e) {
  const { file } = e.detail;
  this.uploadImages(file);
  return false;
},


// 上传图片
uploadImages(file) {
  const that = this;
  const { url } = file;
  const userInfo = wx.getStorageSync('user_info')
  
  // 签名验证,看接口是否需要,使用md5进行加密
  let timestamp = (new Date()).getTime()
  let sign = hexMD5(`secret=9njfyfnew1p&timestamp=${timestamp}`)
 
  wx.showLoading({
    title: '上传中...',
  })
  wx.uploadFile({
    url: `${interfaceUrl}/api/v2/common/uploadFile`, // 后端接口地址
    header: {
      'Authorization': wx.getStorageSync('token'),
    },
    filePath: url, // 文件内容
    name: 'file', // 上传接口字段
    formData: { // 其他参数
      'category': 'approval',
      'source': 'miniprogram',
      'store_id': userInfo.store_id,
      'sign': sign,
      'timestamp': timestamp
    },
    success(res) {
      wx.hideLoading();
      const data = res.data
      const result = JSON.parse(data);
      const { fileList } = that.data
      fileList.push(result.data)
      // 添加到fileList自动回显,如果不显示可能是后端返回结构或自动不对
      that.setData({
        fileList
      })
    },
    fail(err) {
      wx.hideLoading();
      Dialog.alert({
        title: '错误',
        message: err.response.data.msg
      })
    }
  })


},
// 删除图片
deleteTranImage(e) {
  const that = this;
  const { index } = e.detail;
  const { fileList } = that.data
  fileList.splice(index, 1);
  that.setData({
    fileList
  })
}

# 项目分包减少体积

小程序所有文件默认体积大小就2M,如果整个包的内容超出就无法上传和发布,所以所有文件必须精简,图片尽量减少体积,插件也尽量少用。如果内容实在太多,则需要对代码进行分包,分成不同的模块进行加载就可以通过上传。分包后最好把相关的静态文件放到包的文件夹下,如果放在外层还是占主包的体积。

我们默认的页面内容是放在pages文件下的,分包就是再创建一个和pages文件同级的文件,在里面创建页面就行了。

├── pages                    # 页面目录
│   ├── index                # index页面
│   │   ├── index.js         # 页面逻辑处理
│   │   ├── index.json       # 页面配置
│   │   ├── index.wxml       # html
│   │   ├── index.wxss       # css
│   │   └── index.less       # less/sass
├── packageA                 # A包
│   ├── assets               # A包的静态资源
│   ├── components           # A的业务公共组件
│   ├── my                   # my页面
│   │   ├── index.js         
│   │   ├── index.json       
│   │   ├── index.wxml       
│   │   ├── index.wxss       
│   │   └── index.less       
├── packageB                 # B包
│   ├── assets               # B包的静态资源
│   ├── components           # B的业务公共组件
│   ├── empower              # empower页面
│   │   ├── index.js         
│   │   ├── index.json       
│   │   ├── index.wxml       
│   │   ├── index.wxss  
│   │   └── index.less 

页面包分好了,然后在app.json进行分包配置就可以了。

// app.json
{
  "pages": [
    "pages/index/index"
  ],
  "subpackages": [{
    "root": "packageA",
    "name": "A业务",
    "pages": [
      "pages/my/index"
    ]
  },{
    "root": "packageB",
    "name": "B业务",
    "pages": [
      "pages/empower/index"
    ]
  }],
  "window": {}
}

分包后页面地址也就跟着改变了,跳转时要带上包名才行。不同的包直接可以直接相互跳转。

wx.navigateTo({
  url: `/packageA/pages/my/index`
})

# 版本更新提升

每次更新小程序后我们可以在app.js进行设置提示用户版本更新。

//app.js
App({
  onLaunch: function (dataInfo) {
    //启动时更新
    const updateManager = wx.getUpdateManager()
    updateManager.onCheckForUpdate(function (res) {
      // 请求完新版本信息的回调
      console.log(res.hasUpdate)
    })


    updateManager.onUpdateReady(function () {
      wx.showModal({
        title: '更新提示',
        content: '新版本已经准备好了,请点击确定重启应用',
        showCancel:false,
        success(res) {
          if (res.confirm) {
            // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
            updateManager.applyUpdate()
          }
        }
      })
    })


    updateManager.onUpdateFailed(function () {
      // 新版本下载失败
    })
  },
  globalData: {}
})

# 线上调试

生产版本的小程序如果出现问题,可以调试一下正式版看看,调试方式如下:

1、在项目中添加调试代码,把调试打开。这个设不设置好像都行。

2、先在开发版或体验版点击右上角三个点打开调试,再切到正式版就能看到vConsole

# 自定义tabbar

解决微信小程序自定义底部tabbar需要点击两次跳转问题: 自定义tabbar出现的问题 (opens new window)

# 修改checkbox默认样式

主要通过 .wx-checkbox-input 、.wx-checkbox-input-checked 以及 .wx-checkbox-input-checked::before 三个类名来设置 checkbox 的样式。

checkbox .wx-checkbox-input {
  width: 32rpx; 
  height: 32rpx;
  border-color: #aaa;
  background-color: transparent;
  transition: background-color .2s;
}
checkbox .wx-checkbox-input-checked {
  color: #fff; /* 这里也可以设置对钩的颜色 */
  background-color: #409eff;
  border-color: #409eff;
}

# IOS边框显示不完整

ios上1px边框有的机型上显示不完整,缺一条边不显示,这是因为1rpx在不同的分辨率上转换会有问题,有的转化成0.5导致边框不显示。

我们可以使用伪类来模拟实现边框:

.box {
  position: relative;
  height: 80rpx;
  padding: 0 46rpx;
  font-weight: 400;
  font-size: 24rpx;
  line-height: 80rpx;
  border-radius: 8rpx;
  box-sizing: border-box;


  &::after {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 0;
    display: block;
    content: "";
    width: 200%;
    height: 200%;
    box-sizing: border-box;
    border-radius: 16rpx;
    border: 1px solid #000;
    transform: scale(0.5);
    transform-origin: 0 0;
  }
}

还有一种方法比较简单,直接给元素样式加上:transform: rotateZ(360deg)

.box {
  height: 80rpx;
  padding: 0 46rpx;
  font-weight: 400;
  font-size: 24rpx;
  line-height: 80rpx;
  border-radius: 8rpx;
  box-sizing: border-box;


  transform: rotateZ(360deg);
}

# 自定义标题&获取顶部高度

自定义标题需要在当前页面.json里设置 "navigationStyle": "custom" ,设置这个属性后默认的标题状态就没有了,页面顶到手机最顶部,我们自定义一个标题固定在页面最顶部就可以了。

为了统一,我们需要先获取默认的标题栏安全高度。

获取标题栏高度:需要计算状态栏高度和胶囊所占高度

在app.js中进行获取标题栏高度

//app.js
App({
  globalData: {
    statusBarHeight: 0, // 状态栏的高度
    navHeight: 0// 顶部高度
  },
  onLaunch: function () {
    // 获取标题栏高度
    this.getSystemTitlebarHeight()
  },


  // 获取标题栏高度
  getSystemTitlebarHeight() {
    const menuinformation = wx.getMenuButtonBoundingClientRect();
    const statusBarHeight = wx.getSystemInfoSync()['statusBarHeight'] // 顶部状态栏高度
    const { top, height } = menuinformation
    const navHeight = (top - statusBarHeight) * 2 + statusBarHeight + height // 整个顶部的高 = (距顶部的高-状态栏高)*2 + 状态栏高 + 胶囊自身高
    this.globalData.statusBarHeight = statusBarHeight;
    this.globalData.navHeight = navHeight;
  }
})

js中引入

const app = getApp()
const { statusBarHeight, navHeight } = app.globalData;


Page({
  data: {
    loading: false,
    statusBarHeight, // 导航栏高度
    navHeight
  }
})

自定义标题

<view class="index" style="padding-top: {{navHeight - statusBarHeight}}px">
  <!-- 自定义标题 -->
  ​​<view class="index-title" style="height: {{navHeight}}px; padding-top: {{statusBarHeight}}px">
    <view class="title-text">标题</view>
  </view>
</view>
.index {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100vh;
  background-color: #F7F8FA;
  .index-title {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 999;
    width: 100%;
    padding: 0 30rpx;
    font-size: 17px;
    color: #333;
    background-color: #fff;
    .title-text {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      width: 100%;
      height: 100%;
    }
  }
}

# 文件预览

打开文档需要先通过wx.downloadFile方法下载文件流,然后通过返回的地址在使用wx.openDocument方法打开预览文件。

// 打开文件
openDoc(){
  wx.showLoading({
    title: '打开文档中...',
  })
  wx.downloadFile({
    url: `/api/audit/showPdf?id=1`,,
    success: function (res) {
      const filePath = res.tempFilePath
      wx.hideLoading();
      wx.openDocument({
        filePath: res.savedFilePath,
        showMenu: true
      })
    }
  })
}

正常情况下,手机端和开发工具里预览都是可以打开的,但是在PC端微信里打开的小程序就无法支持wx.openDocument方法打开预览文件。解决办法是,需要先通过微信的文件管理系统FileSystemManager里的saveFile方法把文件保存,生成一个保存地址,然后通过这个地址再打开就可以在PC端进行预览了。

// 打开文件
openDoc(e){
  wx.showLoading({
    title: '打开文档中...',
  })
  wx.downloadFile({
    url: `/api/audit/showPdf?id=1`,
    success: function (res) {
      const filePath = res.tempFilePath
      wx.hideLoading();
      // 调用文件管理器保存文件
      const fileManager = wx.getFileSystemManager();
      fileManager.saveFile({
        tempFilePath: filePath,
        success: (res) => {
          wx.openDocument({
            filePath: res.savedFilePath,
            showMenu: true
          })
        }
      })
    }
  })
}

这种方法有的系统还是无法打开,我们需要换种思路,因为是在PC端操作,所以可以先下载到本地在打开查看,手机端还是继续打开查看。 wx.downloadFile下载文件时需要确保保存的路径与文件的名一样,通过传入filePath的名称,这样保存到桌面的地址就是filePath地址上的名称。

// 打开文件
openDoc(e){
  const { file } = e.currentTarget.dataset;
  wx.getSystemInfo({
    success (res) {
      // pc端下载查看,手机端直接打开
      if (res.platform == 'windows' || res.platform == 'mac') {
        wx.downloadFile({
          url: file.url,
          filePath: `${wx.env.USER_DATA_PATH}/${file.name}`,
          success: function (res) {
            const filePath = res.filePath
            // 保存到桌面
            wx.saveFileToDisk({
              filePath: filePath, // 指定存储位置及文件名
              success(res) {
                console.log(res);
              },
              fail(err) {
                console.log(err);
              }
            })
          }
        })
      } else {
        wx.showLoading({
          title: '打开文档中...',
        })
        wx.downloadFile({
          url: file.url,
          success: function (res) {
            const filePath = res.tempFilePath
            wx.hideLoading();
            wx.openDocument({
              filePath: filePath,
              fail(err){
                Dialog.alert({
                  title: '提示',
                  message: "文档打开失败",
                })
              }
            })
          }
        })
      }
    }
  })
},

# 跳转到指定位置

首先要获取页面元素距离顶部的位置,微信小程序通过 wx.createSelectorQuery() 来获取元素的相关信息。

wx.createSelectorQuery().select('.box').boundingClientRect(res => {
  console.log(res.top)
}).exec()

跳转到指定位置有两种情况,一个是页面滚动一个是scroll-view容器滚动,页面滚动不能设置 voerflow必须是整个页面滚动才有效果,scroll-view直接在上面设置scroll-top属性就可以了。

页面滚动:

data: {
  scrollTop: 0
}




wx.pageScrollTo({
 scrollTop: scrollTop, // 滚动到的位置
 duration: 0 // 滚动所需时间
})

scroll-view滚动:

<scroll-view class="scroll" scroll-y scroll-top="{{scrollTop}}">
</scroll-view>


this.setData({
  scrollTop: 100
})

# 实现瀑布流效果

waterfall-layout (opens new window) 支持下拉加载动画和自动计算内容高度,不需要手动添加图片的高度,只关心列表内容渲染,使用简单直接引入组件,在里面渲染内容就可以。

mp-waterfall (opens new window) 相比较waterfall-layout使用麻烦一点,每次都要为组件单独创建一个列表项渲染组件,把要渲染的项放到mp-waterfall上才行。

# 微信图片无法打开

线上图片地址或者cdn图片地址在微信小程序无法打开,在浏览器中却能打开,很大程度是因为在线地址开启了防盗链,禁止嵌套在其他网页,解决办法就是让后端去把静态资源服务器防盗链给关了,要么就是前端自己在图片上加no-referrer进行处理。

<image src="" referrerPolicy="no-referrer" />

# onShow获取页面传参

onShow生命周期里无法直接通过options参数获取传参,只能通过getCurrentPages方法进行获取。在onShow方法中使用要注意这个参数会一直存在,调用不会根据页面内容而改变。

onShow() {
  const pages = getCurrentPages()
  const currentPage = pages[pages.length - 1]
  const options = currentPage.options


  console.log('分享参数', options)
  const { id } = options
  console.log(id)
}