Skip to main content

uniapp和wepy踩坑记录

· 11 min read
LIU

uni-app

  • uni-app 中 css 关于 calc()函数计算无效问题

    原本以为uni-app不支持calc计算,后来发现:

    计算符:+ - * /

    计算符前后都需要空格,否则计算无效

.tets{
height: calc(var(--status-bar-height) + 10px);
}
  • 获取系统状态栏的高度

    let systemInfo = uni.getSystemInfoSync();

    (systemInfo.statusBarHeight) + (systemInfo.platform == "ios" ? 44 : 48)

    uni.upx2px(this.titleWidth))

  • swiper组件 如果有轮播图的组件名叫swiper.vue 或者 Swiper.vue 的时候,那么在使用swiper组件的时候会报 “找不到事件处理程序”,因此组件名不能叫swiper/Swiper。
  • <swiper>一定要给高度才会生效,一般是动态获取里面的元素或列表高度再赋值给<swiper>
  • 出现遮罩后阻止页面滚动,可以在遮罩的touchmove事件中阻止默认事件。@touchmove.prevent=""
  • 在使用picker的时候 值只能使用 - 的形式隔开 不然在ios上会从第一年第一月开始 ,事件是绑定在{{data}}上的,具体可查看uniapp文档
  • 阻止事件,冒泡时要在外层加一层标签<view @tap.stop="xx"></view>,直接在需要使用的方法上加.stop无效
  • 在{{}}中使用toFixed会报错,可以单独写个变量进行处理后再赋值
  • H5 io操作文件 获取不到信息 注意异步方法
    • 通过路径获取操作目录或文件对象 resolveLocalFileSystemURL()
    • 获取当前目录中的所有文件和子目录 readEntries()
  • canvas绘制问题

    setTimeout(function(){  //延迟执行 否则H5不显示
    ctx.stroke();
    ctx.draw()
    },500)
  • 进入页面调用方法生命周期用mounted
  • map组件添加callout属性在模拟器可以展示,但在真机属性失效,比如边框颜色,样式 取消callout属性,目前只能使用title方法 没有什么很好的办法
  • uniapp在ios端每个页面都可以上下拉,阻止方法

    pages.json内设置:

    {  
    "path": "pages/personal/index",
    "style": {
    "app-plus": {
    "bounce": "none"
    }
    }
    }
  • 修改input的值v-model不生效

    this.$nextTick(() => {
    this.value= val;
    });
  • rpx不支持动态横竖屏切换计算,使用rpx时建议锁定屏幕方向
  • uni-app官方不支持动态组件,目前用v-if判断
  • uni-app实现在小程序和h5中在线预览pdf功能

    • 在小程序中预览

      先调用 downloadFile 获取到本地文件路径tempFilePath 再调用 openDocument 就可以在新页面中预览文件,这个API还可以给参数fileType赋值,比如pdf,就会指定类型打开pdf文件

      uni.downloadFile({ 
      url: 'https://xxx.com/abc.pdf',
      success: function (res) {
      var filePath = res.tempFilePath;
      uni.openDocument({
      filePath: filePath,
      success: function (res) {
      console.log('打开文档成功');
      }
      });
      }
      });
    • 在h5中预览

      按照正常的逻辑,说到浏览器预览文件,可能首先想到的就是嵌一个a链接,但是这个对于苹果的手机浏览器来说是可以用的,然而安卓手机点击a链接之后则是会将文件直接下载下来,但是用户肯定不满意,这时候就可以把pdf.js插件安排上了,可以去官网下载zip文件,或者上网百度一下,参考解决方案

          <template>
      <view>
      <web-view :src="pdfUrl"></web-view>
      </view>
      </template>

      <script>
      export default {
      data() {
      return {
      pdfUrl:'',
      from:''
      }
      },
      onLoad() {
      this.pdfUrl = '/hybrid/html/web/viewer.html?file='+encodeURIComponent(pdfUrl)
      },
      }
      </script>

wepy

  • npm install -g wepy-cli@1.7.0
  • wepy小程序的scroll-view 需要加高度,scroll-top和scroll才会生效,而且高度不能大于内容高度,否则不起效!
<scroll-view style="height: 1000px;" scroll-top="{{scrollTop}}" @scroll="scroll" scroll-with-animation="true" scroll-y="true" 
</scroll-view>
  • 数据修改,需要调用this.$apply() ,视图才会更新
  • 操作方法用 @tap=function 的形式进行绑定。基本上所有微信原生的方法 bindFn=fn 都可以直接写成 @Fn=fn.

    // Template
    // 原生的 bindtap=fn
    <view @tap="fn"></view>

    // Script
    class Foo extends wepy.page {
    methods = {
    fn: () => {},
    }
    }
  • 模板事件提供了“方法后缀”作为语法糖以代替原生写法,有.default, .stop.user 后缀,比较常用的是 .stop

    // .default 可不写
    <view @tap="fn"></view>
    // .stop 相当于 catch, 点击事件到此结束,不会向上层组件冒泡
    <view @tap.stop="fn"></view>
  • mixin 可以将通用方法提供给不同地方使用。在这里它能直接读取共有的数据(比如说从Redux 里读取的内容等)但使用时要注意当mixin 中用到了来自Redux 中的数据时,数据本身的connect 要在其具体引用到的页面里面定义,貌似Mixin 本身并不能将Redux 中的数据connect 进来。
  • mixin 中的methods 中不能直接使用 this.foo = bar 去设置页面中的值,因为上下文不一致了不会生效。
  • 对于原生及非原生组件,它的模板逻辑也总是“看上去不那么固定”的

    // 正确 - 省略为 true
    <scroll-view scroll-y></scroll-view>

    // 错误 - 布尔值不能带括号
    <scroll-view scroll-y="{{true}}"></scroll-view>

    // 正确 - 估计这里实际上可能 "true" 是被忽略了的
    <scroll-view scroll-y="true"></scroll-view>

    // 正确 - 但此时这个方法接受到的第一个参数为当前Class的实例,坑爹啊
    <view @tap="toggleSomeThing"></view>

    // 错误 - 布尔值要带括号
    <view @tap="toggleSomeThing(true)"></view>

    // 正确
    <view @tap="toggleSomeThing({{true}})"></view>
  • canvas 签名

    <template>
    <div class="wrapper">
    <div class="left-btn-area">
    <button @tap="clearClick" class="clean-btn">清除</button>
    <button @tap="saveClick" class="save-btn">完成</button>
    <span class="left-tips"></span>
    </div>
    <div class="center-sign-area">
    <canvas class='firstCanvas'
    canvas-id="firstCanvas"
    @touchmove='move'
    @touchend='end'
    @error="error"
    disable-scroll='true'>
    </canvas>
    <canvas class='twoCanvas'
    canvas-id="twoCanvas"

    disable-scroll='true'>
    </canvas>

    </div>
    <div class="right-title-area">
    <div class="right-title">签字板</div>
    </div>

    </div>
    </template>

    <script lang="typescript">
    import wepy from 'wepy';
    import Global from '@U/tools';
    import ajax from '@U/ajax';
    import API from '@S/api';
    import http from '@U/ajax';

    var content = null;
    var contentCopy = null;

    export default class Register extends wepy.page {
    config = {
    navigationBarTitleText: '电子签名',
    enablePullDownRefresh: false,
    };
    props = {
    show: {
    type: Boolean,
    twoWay: true,
    },
    };
    onunload() {
    this.heartTimer && clearInterval(this.heartTimer);
    this.methods.closePendingInquiryWS();
    clearInterval(this.listTimer);
    this.listTimer = null;
    }
    data = {
    touchs: [],
    signImage: '',
    windowWidth: wx.getSystemInfoSync().windowWidth,
    windowHeight: wx.getSystemInfoSync().windowHeight,
    };
    methods = {
    move(e) {
    let point = { x: e.touches[0].x, y: e.touches[0].y };
    this.touchs.push(point);
    if (this.touchs.length >= 2) {
    this.methods.draw(this.touchs);
    }
    },
    end(e) {
    for (let i = 0; i < this.touchs.length; i++) {
    this.touchs.pop();
    }
    },
    clearClick() {
    console.log(999)
    content.clearRect(0, 0, this.windowWidth, this.windowHeight);
    content.draw(true);
    if(contentCopy){
    contentCopy.clearRect(0, 0, this.windowHeight, this.windowWidth);
    contentCopy.draw(true);
    }
    },
    close() {
    this.$emit('closeRegister');
    },
    saveClick() {
    let _this = this;
    wx.canvasToTempFilePath(
    {
    canvasId: 'firstCanvas',
    success: (res) => {
    let temp_path = res.tempFilePath;
    // 小程序读取文件管理器 api
    let fileSystemManager = wx.getFileSystemManager();
    fileSystemManager.readFile({
    filePath: temp_path,
    encoding: 'base64',
    success: (data) => {
    let base64 = 'data:image/png;base64,' + data.data;
    if (base64.length / wx.getSystemInfoSync().pixelRatio < 6000) {
    wx.showModal({
    showCancel: false,
    title: '签名不完整,请重签',
    });
    _this.methods.clearClick();
    } else {
    _this.methods.drowImage(temp_path);
    }
    },
    });
    },
    },
    this
    );
    },
    drowImage(path) {
    //这个path是第一个canvas的临时路径,带过来
    contentCopy = wx.createCanvasContext('twoCanvas'); //第二个canvas的唯一标识
    contentCopy.scale(0.5, 0.5); //把第一个canvas的缩小一倍,因为我的第一个比较大,可以自己调整,太大显示不全
    contentCopy.translate(0, 300); //这个是原点偏移(第二个canvas的高度是300,宽度是600)
    contentCopy.rotate((-90 * Math.PI) / 180); //逆时针旋转90°,拿到横向的签名
    contentCopy.drawImage(path, 0, 0, 300, 600); //把第一个画在第二个上
    contentCopy.draw(true); ////注意这地方绘制需要时间,需要把下面获取临时图片延迟一下,不然有可能获取到的是空白就因为draw()方法没有执行完成
    wx.showLoading({
    title: '加载中...',
    icon: 'none',
    });
    setTimeout(() => {
    wx.canvasToTempFilePath(
    {
    canvasId: 'twoCanvas',
    success: (res) => {
    let temp_path = res.tempFilePath;
    console.log(res.tempFilePath);
    this.upLoad(res.tempFilePath);
    // 小程序读取文件管理器 api
    },
    },
    this
    );
    }, 500);
    },
    async upLoad(img) {
    let res = await http.POST(`${prefix}/***/agencyLogin/xxx`, {});
    if (!res.err) {
    this.ossInfo = res.data;
    let key = this.ossInfo.dir + '/' + this.UUID();
    wx.uploadFile({
    url: this.ossInfo.host,
    filePath: img,
    name: 'file',
    formData: {
    name: img,
    key: key,
    policy: this.ossInfo.policy,
    OSSAccessKeyId: this.ossInfo.accessId,
    success_action_status: '200',
    signature: this.ossInfo.signature,
    },
    success: (res) => {
    wx.setStorageSync('regImg', this.ossInfo.host + '/' + key);
    wx.navigateBack();

    },
    fail: (res) => {
    wx.showModal({
    title: '提示',
    content: '上传失败,请重试',
    showCancel: false,
    });
    },
    complete: () => {
    wx.hideToast();
    },
    });
    }
    },
    UUID() {
    let s = [];
    let hexDigits = '0123456789abcdef';
    for (let i = 0; i < 36; i++) {
    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = '4';
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
    s[8] = s[13] = s[18] = s[23] = '-';
    let uuid = s.join('');
    return uuid;
    },
    draw(touchs) {
    let point1 = touchs[0];
    let point2 = touchs[1];
    touchs.shift();
    content.moveTo(point1.x, point1.y);
    content.lineTo(point2.x, point2.y);
    content.stroke();
    content.draw(true);
    },
    };
    onLoad() {
    content = wx.createCanvasContext('firstCanvas', this);
    content.setStrokeStyle('#000000');
    content.lineWidth = 3;
    content.setLineCap('round');
    content.setLineJoin('round');
    }
    }
    </script>

    <style lang="scss">
    .wrapper {
    width: 100%;
    height: 94vh;
    margin-top: 1.5vh;
    display: flex;
    align-content: center;
    flex-direction: row;
    justify-content: center;
    font-size: 28rpx;
    }

    .right-title-area {
    display: inline-flex;
    align-items: center;
    }

    .center-sign-area {
    border: 4rpx dashed #e9e9e9;
    flex: 5;
    overflow: hidden;
    box-sizing: border-box;
    }
    .firstCanvas {
    background-color: #fff;
    width: 100%;
    height: 100%;
    }

    .right-title {
    transform: rotate(90deg);
    flex: 1;
    color: #666;
    }

    .left-btn-area button {
    font-size: 28rpx;
    }

    .left-btn-area {
    height: 95vh;
    display: inline-flex;
    flex-direction: column;
    justify-content: space-between;
    align-content: space-between;
    flex: 1;
    }

    .clean-btn {
    position: absolute;
    top: 50rpx;
    left: 0rpx;
    transform: rotate(90deg);
    color: #fff;
    background-color: rgb(255, 103, 103);
    }

    .left-tips {
    position: absolute;
    align-items: center;
    color: red;
    display: inline-flex;
    transform: rotate(90deg);
    left: -320rpx;
    width: 100%;
    top: 55%;
    }

    .clean-btn image {
    position: absolute;
    top: 13rpx;
    left: 25rpx;
    }

    .save-btn {
    position: absolute;
    bottom: 52rpx;
    display: inline-flex;
    transform: rotate(90deg);
    background: #008ef6;
    color: #fff;
    margin-bottom: 30rpx;
    text-align: center;
    justify-content: center;
    }
    </style>