微信小程序实践记录

56 阅读2分钟

小程序页面配置

配置文档

单位尺寸设置问题

  • 绝大多数情况都可以用rpx
  • 绝大多数的border可以用rpx
  • 针对字体大小 当不需要根据分辨率的大小更改字体大小时可以选择使用px
  • 使用vscode > 首选项 > 设置 > 搜索rpx 进行插件配置

css选择器相关

文档中说明的可支持的选择器

也有部分选择形式的选择器文档没有说明但也可以使用——实际开发中尝试。。。

字体设置

text {
  font-family: "PingFangSC-Thin";
}

全局字体设置

在全局的样式文件中—— 原生项目是app.wxss

page {
  font-family: "PingFangSC-Thin";
}

自定义组件相关——样式、通信、生命周期等

微信文档

hover-class配合hover-stop-propagation使用阻止冒泡

hover-start-time & hover-stay-time

button主要属性

  • size 大小
  • type 颜色
  • plain 镂空
  • disabled 禁用启用
  • loading 正在加载图标

下拉刷新onPullDownRefresh

  • 触发下拉刷新的方式:
  1. 全局配置文件pages.json中配置(具有全局性):

    "globalStyle": {
      "enablePullDownRefresh": true
    }
    
  2. 特定页面配置,pages.json文件中:

    "pages": [
      {
        "path": 'pages/list/index',
        "style": {
          "enablePullDownRefresh": true
        }
      }
    ]
    
  • 页面中监听方法并做逻辑处理

    <script>
      export default {
        data() {
          return {}
        }
        onPullDownRefresh() {
          // 相关逻辑
          // uni.stopPullDownRefresh() // 关闭下拉刷新状态
          // uni.startPullDownRefresh() // 用于手动开启下拉刷新
        }
      }
    </script>
    

上拉加载onReachBottom

可配合onReachBottomDistance使用

<script>
  export default {
    data() {
      return {}
    }
    onReachBottom() {
      // 相关逻辑
    }
  }
</script>

uni.request 发送请求

uni.setStorage 做数据缓存( uni.setStorageSync同步设置)

图片的上传和预览

  • uni.chooseImage 上传图片
  • uni.previewImage 预览图片

条件编译

条件编译是用特殊的注释作为标记,在编译时根据这些特殊的注释,将注释里面的代码编译到不同平台。

视图层面 和 js逻辑层面 以及 css样式层面 都可以使用条件编译

条件编译文档

导航跳转和传参

有编程式导航(js API)和 声明式导航(组件形式)

路由相关文档

通过onLoad(options){}的options接收路由参数

uni-app中组件的创建使用和生命周期

  • 创建:同vue
  • 使用:同vue
  • 组件的生命周期同vue

组件之间的通信方式

  • 父传子:同vue props
  • 子传父:自定义事件 this.$emit('eventName')——@eventName=""; 同vue
  • 相邻的兄弟组件:uni.emit()uni.emit()、uni.on()

hidden 和 wx:if

原生小程序组件的hidden属性和wx:if属性都可以用来控制组件的显示和隐藏。如果频繁切换用hidden否则用wx:if。hidden不会触发组件的detached,但wx:if会。

小程序实现动画效果的两种方式

  1. 小程序提供的动画API
  2. css3、canvas

input标签有placeholder-style、placeholder-class、auto-focus等属性

小程序历史搜索记录与热门搜索功能

  • 编写标签组件 用于展示
  • 历史搜索 可以存到缓存中从缓存获取 限制历史搜索记录的数组长度 优化界面(添加新的历史记录时 删除历史记录数组的末尾元素)
  • 热门搜索 来自于服务端需要请求接口
  • 对搜索结果进行下拉加载更多数据的两种方式:1: 用scroll-view组件 2: 用onReachBottom
  • 如果下拉请求返回的没有更多数据了 就不需要继续请求加载接口了,这个需要优化:(判断已加载数据和总数据量是否相等来判断是否已经加载完,或者判断接口请求回来的数据是否是空数组但是不够严谨,优选第一种方式)
  • 下拉操作过快,请求发送过快导致出现重复数据:(通过锁的概念,设置一个loading属性,发送请求时判断loading状态,请求时和请求结束更新loading状态)

跳h5

  1. 微信小程序开发配置后台>开发管理>开发设置>业务域名: 下载校验文件上传到h5域名下的服务器上的根目录里,业务域名中添加h5链接的域名
  2. 用web-view组件 web-view文档

实现录音功能

下面是以uni.getRecorderManager()为例的大概实现

<view class="record">
  <view @touchend="handleTouchend" @longpress="hanldeLongPress">
    <text v-if="!recordUrl">{{recordText}}</text>
    <view class="play-btn" v-if="recordUrl" @click="handleClickPlay"> 
      <iconfont class="bf-icon" name="bf" color="#fff" size="50"/>
      <text >{{recordText}}</text>
    </view>
  </view>
  <text @click="handleResetRecord">重录</text>
</view>
methods: {
  computeSignature(accessKeySecret, canonicalString) {
    return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret));
  },
  // 长按开始录音
   hanldeLongPress() {
    this.recorderManager = uni.getRecorderManager();
    this.recorderManager.start();
    this.recordText = '录音中...';
  },
  // 结束长按,结束录音并将录音上传
  handleTouchend() {
    this.recorderManager.stop();
    this.recorderManager.onStop( (res) => {
      this.pressRecord = false;
      const { host, file_name, credentials } = this.ossData; // 调oss接口取到的验证信息等
      const { AccessKeySecret, AccessKeyId, SecurityToken, Expiration } = credentials;
      const policyText = {
        expiration: Expiration,
        conditions: [
          // 限制上传大小。
          ["content-length-range", 0, 1024 * 1024 * 1024],
        ]
      }
      const policy = Base64.encode(JSON.stringify(policyText));
      const signature = this.computeSignature(credentials.AccessKeySecret, policy)
      uni.uploadFile({
        url: `https://${host}`,
        filePath: res.tempFilePath,
        name: 'file',
        header: { Authorization: `Bearer ${uni.getStorageSync('token')}` },
        formData: {
          key: this.ossData.file_name,
          policy: policy,
          OSSAccessKeyId: AccessKeyId,
          signature: signature,
          'x-oss-security-token': SecurityToken // 使用STS签名时必传。
        },
        success: (uploadFileRes) => {
          this.recordUrl = this.ossData.file_uri;
          this.recordText = '点击播放'
        },
        fail: (error) => {
          this.recordText = '长按录音(选填)'
          uni.showToast({
            title: '录音上传失败',
            icon: 'none',
            duration: 2000
          });
        }
      });
    });
  },
  // 播放
  handleClickPlay() {
    const innerAudioContext = uni.createInnerAudioContext();
    innerAudioContext.src = this.recordUrl;
    if(!this.recordUrl) {
      innerAudioContext.stop();
    }else {
      innerAudioContext.play();
    }
  },
  // 重录
  handleResetRecord() {
    this.recordUrl = ''
    this.recordText = '长按录音(选填)';
  }, 
}

实现签字版签字功能

打开签字版 (由canvas渲染)手写签名并提交

<view class="sign-canvas">
  <view class="sign-close">
    <view class="close-icon" @click="handleCloseSign">
      <iconfont name="qx" size="52"></iconfont>
    </view>       
  </view>
  <view class="reset-box">
    <view class="reset-sign" @click="clearClick">
      <iconfont name="sx1" size="72"></iconfont>
    </view>
  </view>
  <canvas class="sign-box" canvas-id="sign" @touchmove="move" @touchstart="start" @touchend="end" @touchcancel="cancel" @longpress="tap" disable-scroll="true" @error="error"></canvas>
</view>
// 页面加载完成后获取并设置canvas上下文及其基础配置
//获得Canvas的上下文
this.content = wx.createCanvasContext('sign');
//设置线的颜色
this.content.setStrokeStyle("#000");
//设置线的宽度
this.content.setLineWidth(3);
//设置线两端端点样式更加圆润
this.content.setLineCap('round');
//设置两条线连接处更加圆润
this.content.setLineJoin('round');
​
// 画布的触摸移动开始手势响应
start(event) {
  //获取触摸开始的 x,y
  let point = { x: event.changedTouches[0].x, y: event.changedTouches[0].y }
  this.touchs.push(point);
},
// 画布的触摸移动手势响应
move(e) {
  let point = { x: e.touches[0].x, y: e.touches[0].y }
  this.touchs.push(point);
  if (this.touchs.length >= 2) {
    this.draw(this.touchs);
  }
},
// 画布的触摸移动结束手势响应
end(e) {
  console.log("触摸结束" + e);
  //清空轨迹数组
  for (let i = 0; i < this.touchs.length; i++) {
    this.touchs.pop();
  }
},
// 画布的触摸取消响应
cancel(e) {
  console.log("触摸取消" + e);
},
// 画布的长按手势响应
tap(e) {
  console.log("长按手势" + e);
},
error(e) {
  console.log("画布触摸错误" + e);
},
//绘制
draw(touchs) {
  let point1 = touchs[0];
  let point2 = touchs[1];
  touchs.shift();
  this.content.moveTo(point1.x, point1.y);
  this.content.lineTo(point2.x, point2.y);
  this.content.stroke();
  this.content.draw(true);
}
//清除操作
clearClick() {
  //清除画布
  this.content.clearRect(0, 0, 750, 700);
  this.content.draw(true);
},
//保存canvas绘图
saveClick() {
  const { host, file_name, credentials } = this.signOssData;
  const { AccessKeySecret, AccessKeyId, SecurityToken, Expiration } = credentials;
  const policyText = {
    expiration: Expiration,
    conditions: [
      // 限制上传大小。
      ["content-length-range", 0, 1024 * 1024 * 1024],
    ]
  }
  const policy = Base64.encode(JSON.stringify(policyText));
  const signature = this.computeSignature(credentials.AccessKeySecret, policy);
  uni.canvasToTempFilePath({
    canvasId: 'sign',
    success: res => {
      // 在H5平台下,tempFilePath 为 base64
      this.canvasUrl = res.tempFilePath;
      uni.uploadFile({
        url: `https://${host}`,
        filePath: this.canvasUrl,
        name: 'file',
        header: { Authorization: `Bearer ${uni.getStorageSync('token')}` },
        formData: {
          key: this.signOssData.file_name,
          policy: policy,
          OSSAccessKeyId: AccessKeyId,
          signature: signature,
          'x-oss-security-token': SecurityToken // 使用STS签名时必传。
        },
        success: (uploadFileRes) => {
          // ...
        },
        fail: (error) => {
          // ...
        }
      });
    },
    fail: err => {
      // ...
    }
  })
}