小程序的总结和一些坑

2020-11-19  本文已影响0人  butters001

持续更新中

1. 解决VS Code中小程序的wxml文件的注释是双斜杠
image-20201021102156036.png

重启vscode就可以了

2. vscode安装easy less
image-20201021102309968.png

在settings.json中添加如下 "less.compile"

image-20201021102439281.png
"less.compile": {
        "compress": false,//是否压缩
        "sourceMap": false,//是否生成map文件,有了这个可以在调试台看到less行数
        "out": true, // 是否输出css文件,false为不输出
        "outExt": ".css", // 输出文件的后缀
       }
3. vscode如何自动格式化代码

安装插件 Prettier -Code formatter

image-20201021103905892.png

在settings.json中添加如下 "editor.formatOnSave": true

image-20201021102813041.png
4. 小程序标签绑定点击事件

.wxml文件

<view bindtap="changeInputSizeUp">123</view>

.wxss文件

changeInputSizeUp: function() {
    do something
}
5. 弹窗时 禁止背景页面滑动操作
弹框标签添加 catchtouchmove="return"
<view wx:if="{{isShowConfirm}}" catchtouchmove="return">
6. 输入框标签聚焦或键盘输入时触发
bindinput 键盘输入时触发 
bindfocus 输入框聚焦时触发
<textarea maxlength="70" bindinput='setValue' data-name='stuEidtName'></textarea>
7.日期选择器
<view class="section">
  <view class="section__title">日期选择器</view>
  <picker mode="date" value="{{date}}" start="2015-09-01" end="2017-09-01" bindchange="bindDateChange">
    <view class="picker">
      当前选择: {{date}}
    </view>
  </picker>
</view>
bindDateChange: function(e) {
    console.log('picker发送选择改变,携带值为', e.detail.value)
    this.setData({
      date: e.detail.value
    })
  },
8. 文本超出显示省略号
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
9. 小程序下拉刷新之后停止下拉框的显示

加载完数据后添加 wx.stopPullDownRefresh()

onPullDownRefresh: function () {
    this.loadTodoList();
    wx.stopPullDownRefresh();
  },
10. 给后端服务器发送http请求 支持es7的async await
  1. 跟目录下创建 request/index.js
// 同时发送异步代码的次数
let ajaxTimes = 0;

export const request = (params) => {
  ajaxTimes++;
  // 显示加载中loading 效果
  wx.showLoading({
    title: "加载中",
    mask: true,
  });

  return new Promise((resolve, reject) => {
    wx.request({
      ...params,
      success: (result) => {
        resolve(result.data);
      },
      fail: (err) => {
        reject(err);
      },
      complete: () => {
        ajaxTimes--;
        if (ajaxTimes === 0) {
          //  关闭正在等待的图标
          wx.hideLoading();
        }
      },
    });
  });
};

  1. 根目录下创建 lib/runtime/runtime.js

    regenerator/packages/regenerator-runtime/runtime.js 的代码拷到自己的 runtime.js里

  2. 需要使用async语法的页面js导入 哪个页面使用就哪个页面导入

 import { request } from "../../request/index.js";
 import regeneratorRuntime from "../../lib/runtime/runtime";
 
 async loadTodoList() {
     var that = this;
     var url = "http://127.0.0.1:8000/api/add"
     const result = await request({
       url: url,
       data: this.SubmitParams,
       method: "post",
       header: {
         "Content-Type": "application/x-www-form-urlencoded",
       },
     });
 
     if (result.code == 0) {
       pass
     } else {
       pass
     }
   },
11. 监听用户下拉操作
// 监听用户下拉操作
  onPullDownRefresh: function () {
    // 1 重置数组
    this.setData({
      todo_show: [],
    });
    // 2 重置页码
    this.SubmitParams.page_num = 1;
    // 3 发送请求
    this.loadTodoList();
    wx.stopPullDownRefresh();
  },
12. 页面上拉触底事件的处理函数 如加载下一页
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
    //  1 判断还有没有下一页数据
    // console.log(this.SubmitParams.page_num, this.totalPages);
    if (this.SubmitParams.page_num >= this.totalPages) {
      // 没有下一页数据
      //  console.log('%c'+"没有下一页数据","color:red;font-size:100px;background-image:linear-gradient(to right,#0094ff,pink)");
      wx.showToast({ title: "没有下一页数据" });
    } else {
      // 还有下一页数据
      //  console.log('%c'+"有下一页数据","color:red;font-size:100px;background-image:linear-gradient(to right,#0094ff,pink)");
      this.SubmitParams.page_num++;
      this.loadTodoList();
    }
  }
13. 出现遮罩层后禁止背景页面上下拉动
image-20201023165326893.png

在遮罩层的标签中添加 catchtouchmove="noneEnoughPeople" 注意:在开发平台上可能不起效果 在手机上测试会起作用

image-20201023165431724.png
14. button透明 放到图片或view等标签下面

.login_btn 就是button按钮 放到了.user_icon标签下面了

 .user_icon {
        position: relative;
        width: 120rpx;
        height: 120rpx;
        border-radius: 50%;
        .login_btn {
          position: absolute;
          top: 0;
          left: 0;
          width: 120rpx;
          height: 120rpx;
          border-radius: 50%;
          opacity: 0;
        }
15. 下面的标签 部分压住上面的标签效果实现
image-20201024155835179.png
// 下面的白色标签 要绝对定位 然后 top指定为负数
.user_content {
  position: relative;
  .user_business_info_wrap {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: -40rpx;
    width: 94.6%;
    height: 100rpx;
    background-color: #ffffff;
  }
}
16. async a函数 在别的函数b里需要同步调用

给b变成async 然后在调用a前await一下

async a() {
    ......
}

async b() {
  // 如果不添加await a() 和 other执行顺序不定 会出现问题
    await a();
    do other......
}
17. 外部this不能被success内部使用问题
image-20201027101722625.png
18. 小程序登陆功能

小程序调用 wx.login({}) success后请求后端的登陆接口 将wx.login返回的 res.code 传给后端使用

后端服务器的login接口 去请求微信接口(需要code参数),将返回的用户wx_token存储到数据库 用来当作用户的身份验证

​ 可以将wx_token进行编码或加密 md5或base64

image-20201109113006182.png

auth.js

  authLogin(nickName) {
    wx.login({
      success: (res) => {
        if (res.code) {
          //发起网络请求
          var backend_url = app.globalData.backend_url;
          var url = backend_url.base_url + backend_url.login;
          wx.request({
            url: url, //仅为示例,并非真实的接口地址
            data: {
              code: res.code,
              nickName: nickName,
            },
            header: {
              "content-type": "application/json", // 默认值
            },
            success: (res) => {
              if (res.data.code === 0) {
                // 登陆成功
              }
            },
          });
        }
      },
    });
  },

auth.py

def login(request):
    try:
        code = request.GET.get('code')
        nick_name = request.GET.get('nickName')
        url = "https://api.weixin.qq.com/sns/jscode2session?" \
              "appid=%s&secret=%s&js_code=%s&grant_type=authorization_code" % ("xxxxxx",
                                                                               "xxxxxx",
                                                                               code)
        result = requests.get(url)
        result = result.json()
        open_id = result['openid']

        wx_token = "对open_id进行加密"

        session_key = result['session_key']
        user, _ = User.objects.update_or_create(wx_token=wx_token,
                                                defaults={'session_key': session_key,
                                                          'username': wx_token,
                                                          'nick_name': nick_name,
                                                          'open_id': open_id})

    except Exception as e:
        logger.error(e)
        return JsonResponse({'code': 1, 'message': '服务器异常,请联系管理员'})
    return JsonResponse({'code': 0, 'wx_token': wx_token, 'user_id': user.id})
19. 下载excel

小程序发起下载请求,后端服务器生成excel 返回给小程序excel的网络地址

然后小程序请求这个网络地址进行下载 wx.downloadFile( ) +wx.openDocument( )

wx.downloadFile({
  // 示例 url,并非真实存在
  url: 'http://example.com/somefile.pdf',
  success: function (res) {
    const filePath = res.tempFilePath
    wx.openDocument({
      filePath: filePath,
      success: function (res) {
        console.log('打开文档成功')
      }
    })
  }
})
20. 七牛云接口存储图片
from PIL import Image
from qiniu import Auth, put_data
from qiniu import BucketManager

AK = "七牛云 ak"
SK = "七牛云 secret_ky"
# 构建鉴权对象
q = Auth(AK, SK)
# 要上传的空间
bucket_name = 'aaaaa'


# 七牛云上传图片
def upload_file(localfile):
    try:
        m = hashlib.md5()  # 括号内也可以传值,类型也要求是bytes类型
        key = 'df' + str(int(time.time())) + str(random.randint(10000, 100000))
        m.update(key.encode('utf-8'))

        # 上传后保存的文件名
        key = m.hexdigest() + '.jpg'
        # 生成上传 Token,可以指定过期时间等
        token = q.upload_token(bucket_name, key, 3600)
        ret, info = put_data(token, key, localfile)
        if info.status_code == 200:
            sign_url = "http://qjbb5wdkg.hb-bkt.clouddn.com/" + key
            return sign_url
    except Exception as e:
        logger.error(e)


# 七牛云删除图片
def delete_file(key):
  """
  只需要传名字就行xxx.jpg 不需要传域名路径
  """
    try:
        # 初始化BucketManager
        bucket = BucketManager(q)

        # 你要测试的空间, 并且这个key在你空间中存在
        # 删除bucket_name 中的文件 key
        ret, info = bucket.delete(bucket_name, key)

        assert ret == {}
    except Exception as e:
        logger.error(e)

# 视图函数
def upload_view(request):
    sign_pic = request.FILES.get('sign_pic')

    im_pic = Image.open(sign_pic)
    # im_pic = im_pic.transpose(Image.ROTATE_90)  # 引用固定的常量值 旋转90度 非必须
    # 创建一个字节流管道
    img_bytes = io.BytesIO()
    # 将图片数据存入字节流管道, format可以按照具体文件的格式填写
    im_pic.save(img_bytes, format="PNG")
    # 从字节流管道中获取二进制
    image_bytes = img_bytes.getvalue()
    url = upload_file(image_bytes)
    
    delete_file(url.split('/')[-1])
21. 盒子阴影

直接在标签里加入css名 <div class="shadow"></div>

/* 盒子阴影 */
.shadow {
  position: relative;
  max-width: 100%;
  box-shadow: 0px 1.5px 3px rgba(0, 0, 0, 0.3),
    0px 0px 20px rgba(0, 0, 0, 0.1) inset;
}

.shadow::before,
.shadow::after {
  content: "";
  position: absolute;
  z-index: -1;
}

.shadow::before,
.shadow::after {
  content: "";
  position: absolute;
  z-index: -1;
  bottom: 15px;
  left: 10px;
  width: 50%;
  height: 20%;
}

.shadow::before,
.shadow::after {
  content: "";
  position: absolute;
  z-index: -1;
  bottom: 15px;
  left: 10px;
  width: 50%;
  height: 20%;
  box-shadow: 0 10px 7px rgba(0, 0, 0, 0.7);
  transform: rotate(-3deg);
}

.shadow::after {
  right: 10px;
  left: auto;
  transform: rotate(3deg);
}
22. 点击订阅功能
index.wxml
<!-- 订阅开关 -->
<image
  class="sub_status"
  src="xxxxxx"
  mode="widthFix"
  bindtap="subContentBtn"
  data-itemid="{{item.id}}"
  data-userid="{{item.user_id}}"
  data-idx="{{idx}}"
  data-endtime="{{item.end_time}}"
  data-subscribe="{{item.subscribe_status}}"
></image>
index.js

// 点击订阅
subContentBtn(e) {
 wx.showModal({
      title: "提示",
      content: "订阅此条记录?",
      showCancel: true,
      cancelText: "取消",
      cancelColor: "#000000",
      confirmText: "确定",
      confirmColor: "#3CC51F",
      success: (result4) => {
        if (result4.confirm) {
          wx.requestSubscribeMessage({
            tmplIds: ["订阅模版id"],
            success: (res) => {
              if (res["订阅模版id"] ==="accept") {
                // 发送请求
                this.sendSub(
                  url,
                  {
                    id: item_id,
                    subscribe_status: subscribe_status,
                  },
                  index
                );
              }
            },
            fail(err) {
              console.error(err);
            },
          });
        }
      },
    });

  
  // 请求订阅接口
  async sendSub(url, params, index) {
    const result = await request({
      url: url,
      data: params,
    });
    if (result.code == 0) {
      wx.showToast({
        title: "操作成功",
        icon: "success",
        duration: 2000,
        mask: true,
        success: (result) => {},
      });
    } else {
      wx.showToast({
        title: result.message,
      });
    }
  },
23. 保存图片到本地 和 图片预览
//保存到相册
async saveCanvasAsImg() {
  try {
    // 1 获取 权限状态
    const res1 = await getSetting();
    const scopewritePhotosAlbum = res1.authSetting["scope.writePhotosAlbum"];
    // 2 判断 权限状态
    if (scopewritePhotosAlbum === false) {
      await openSetting();
    }

    wx.canvasToTempFilePath({
      canvasId: "handWriting",
      fileType: "png",
      quality: 1, //图片质量
      success(res) {
        // console.log(res.tempFilePath, 'canvas生成图片地址');
        wx.saveImageToPhotosAlbum({
          filePath: res.tempFilePath,
          success(res) {
            wx.showToast({
              title: "已保存到相册",
              duration: 2000,
            });
          },
          fail: function (res) {
            console.log(res);
            if (res.errMsg === "saveImageToPhotosAlbum:fail auth deny") {
              console.log("打开设置窗口");
            }
          },
        });
      },
    });
  } catch (error) {
    console.log(error);
  }
},

  //预览
  previewCanvasImg() {
    wx.canvasToTempFilePath({
      canvasId: "handWriting",
      fileType: "jpg",
      quality: 1, //图片质量
      success(res) {
        // console.log(res.tempFilePath, 'canvas生成图片地址');

        wx.previewImage({
          urls: [res.tempFilePath], //预览图片 数组
        });
      },
    });
  },
24. 长按保存
wxml文件

<image
     wx:if="{{item.status!='审核中'}}"
     data-url="{{item.sign_url}}"
     bindlongpress="saveImage"
     bindtap="imagePreview"
     class="signUrl"
     src="{{item.sign_url}}"
     mode="widthFix"
    />
js文件  

//单击图片预览
imagePreview: function (e) {
  var current = e.target.dataset.url; //这里获取到的是一张本地的图片
  wx.previewImage({
    current: current, //需要预览的图片链接列表
    urls: [current], //当前显示图片的链接
  });
},

  // 长按保存图片
  saveImage(e) {
    let url = e.currentTarget.dataset.url;
    //用户需要授权
    wx.getSetting({
      success: (res) => {
        if (!res.authSetting["scope.writePhotosAlbum"]) {
          wx.authorize({
            scope: "scope.writePhotosAlbum",
            success: () => {
              // 同意授权
              this.saveImg1(url);
            },
            fail: (res) => {
              console.log(res);
            },
          });
        } else {
          // 已经授权了
          this.saveImg1(url);
        }
      },
      fail: (res) => {
        console.log(res);
      },
    });
  },

    saveImg1(url) {
      wx.getImageInfo({
        src: url,
        success: (res) => {
          let path = res.path;
          wx.saveImageToPhotosAlbum({
            filePath: path,
            success: (res) => {
              console.log(res);
              wx.showToast({
                title: "图片保存成功",
                icon: "success",
                duration: 2000,
                mask: true,
              });
            },
            fail: (res) => {
              console.log(res);
            },
          });
        },
        fail: (res) => {
          console.log(res);
        },
      });
    },
25. 获取用户信息

必须指定 open-type="getUserInfo"

wxml文件

<button
  class="login_btn"
  type="primary"
  plain
  open-type="getUserInfo"
  bindgetuserinfo="handleGetUserInfo"
  >
  js文件
  
  handleGetUserInfo(e) {
    // console.log(e);

    const { userInfo } = e.detail;
    wx.setStorageSync("user_info", userInfo);
    this.setData({
      user_info: userInfo,
    });
    this.authLogin(userInfo.nickName);
  },
26. 获取当前页面的route
let pages = getCurrentPages();
let currPage = null;
// console.log(pages) 的到一个数组
if (pages.length) {
// 获取当前页面的对象(上边所获得的数组中最后一项就是当前页面的对象)
 currPage = pages[pages.length - 1];
 }
// 获取当前页面的路由 /pages/index/index
let route = currPage.route;
27. app.js里添加定时任务 在小程序运行期间一直定时执行
onLaunch: function () {
    var that = this;
    setInterval(that.showActionHistory, 5000);
  },
28. 小程序设置tabBar右上角添加文本/移除文本样式
wx.setTabBarBadge({
          index: 2,
          text: '设置文本内容',
        })

//移除taBar右上角的文本
wx.removeTabBarBadge({
          index: 2, //tabBar下标
        })        
29. setTimeout 里无法调用this.setData问题

使用that或箭头函数


var that = this;
setTimeout(function () {
      that.setData({
        is_todo_pk_btn_disabled: false,
        is_todo_pk_img: false,
        is_todo_result: true,
      });
    }, 8000);

// 或者
setTimeout(() => {
      this.setData({
        is_todo_pk_btn_disabled: false,
        is_todo_pk_img: false,
        is_todo_result: true,
      });
    }, 8000);
30. 如果有用户自定义上传文本或图片的地方 需要进行内容的审核 否则上线不通过

请求微信接口对内容进行审核, 但是文档有点坑

  1. 返回值是 errmsg 而不是文档写的 errMsg
  2. 不能直接requests.post(url, data=data) 这样会一直返回ok,要对data进行处理,如下代码可以正常运行
data = {'content': '特3456书yuuo莞6543李zxcz蒜7782法fgnv级'}
requests.post(url, data=json.dumps(data, ensure_ascii=False).encode(), headers={'content-type': 'application/json'})
上一篇 下一篇

猜你喜欢

热点阅读