zoukankan      html  css  js  c++  java
  • 小程序开发中的一些坑和技巧

    前言

    最近公司要开发一款电商小程序,匆忙看了一遍文档就开始干活了。整体开发体验个人感觉不太好,特别是如果之前习惯了Vue开发,突然去开发小程序,感觉很鸡肋。以下是我在开发中遇到的一些问题以及解决方法的总结,仅供参考

    引入iconfont

    在小程序中引入字体图标要比web麻烦一些,简单说需要三步:

    1. 下载iconfont,把iconfont.css复制到iconfont.wxss,在app.wxss中引入

    2. 查看iconfont在unicode模式下的在线链接,替换iconfont.wxss中的链接为远程链接

    1. 在wxml文件中引入对应的icon class
    <icon class="iconfont icon-pay"></icon>
    

    使用less

    vscode有一个easy less插件,是我感觉使用less最简单的方式

    1. vscode安装easy less插件

    2. 创建一个less目录,用于存放less文件

    3. 文件头部添加编译注释 // out: ../pages/index/index.wxss, compress: true, sourceMap: false

    4. ctrl + s保存后自动编译

    编译后的结果

    按钮重置

    小程序中的按钮功能强大,很多功能必须要用按钮,比如弹出用户授权,调用客服功能。默认的样式一般无法满足需求,可以把按钮样式统一重置,然后自己写样式

    button {
      padding: 0;
      background: #fff;
      line-height: 0;
      &::after {
        border-color: transparent;
      }
    }
    .button-hover {
      background: #fff;
    }
    

    支持async-await

    async-await是ES7的语法,截止我写这篇文章为止,小程序还是不支持async-await语法的,所以需要使用regenerator-runtime这个库

    1. 下载regenerator-runtime并放到utils目录下

    2. 在util.js引入import regeneratorRuntime from './regenerator-runtime/runtime-module'

    3. 封装wxRequest,让它支持async-await

    const wxRequest = async (url, params = {}) => {
      Object.assign(params, {
        token: wx.getStorageSync('token')
      })
      // 所有的请求,header默认携带token
      let header = params.header || {
        'Content-Type': 'application/json',
        'token': params.token || ''
      }
      let data = params.data || {}
      let method = params.method || 'GET'
      // hideLoading可以控制是否显示加载状态
      if (!params.hideLoading) {
       wx.showLoading({
         title: '加载中...',
       })
      }
      let res = await new Promise((resolve, reject) => {
        wx.request({
          url: url,
          method: method,
          data: data,
          header: header,
          success: (res) => {
            if (res && res.statusCode == 200) {
              resolve(res.data)
            } else {
              reject(res)
            }
          },
          fail: (err) => {
            reject(err)
          },
          complete: (e) => {
            wx.hideLoading()
          }
        })
      })
      return res
    }
    
    export {
      wxRequest
    }
    

    使用方法:

    import regeneratorRuntime from '../../utils/regenerator-runtime/runtime-module.js'
    import {
      wxRequest
    } from '../../utils/util.js'
    
    Page({
      data: {
       list:[],
       count: 0,
       page: 1,
       limit: 10
      },
      onLoad: function() {
        this.getList()
        // 请求已经结束 做其他事
      },
      getList: async function() {
        await wxRequest(app.globalData.baseUrl + '/test',{
          hideLoading: true,
          data: {
            limit: this.data.limit,
            page: this.data.page
          }
        }).then((ret) => {
          this.setData({
            list: ret.data.data,
            count: ret.data.num
          })
        })
      }
    })
    

    封装之后用起来还是很爽的,扩展起来也方便

    动态设置data中某个值

    应用场景:循环出来的列表,需要根据点击项,动态改变列表中对应id的数据

    // 动态传递id
    <view catch:tap="onChangeName" data-id="1"></view>
    
    Page({
      data: {
        list:[{
          id: 0,
          name: 'wang'
        },{
          id: 1,
          name: 'li'
        }]
      },
      onChangeName: function(event){
        // 拿到id
       let id = event.target.dataset.id
       let key = `list[${id}].name`, val = 'zhang'
       // 设置值
       this.setData({
        [key]: val
       })
      }
    })
    

    flex布局,溢出省略号无效

    订单列表一般都是左边一个图片,右边是标题或描述。这时候图片宽度是固定的,标题长度自适应

    .wrap {
      display: flex;
    }
    .sub {
      flex: 1;
       0; // 宽度设为0
    }
    .sub text {
      display: block; // 一定要设置成block
    }
    
    <view calss="wrap">
      <image src="i.png"/>
      <view class="sub">
        <text>一段文本一段文本一段文本一段文本一段文本一段文本</text>
        <view>其他</view>
      </view>
    </view>
    

    组件事件传递

    任务:父组件向子组件传递初始数据,当子组件点击以后可以triggerEvent自定义事件,父组件执行自定义事件,重新请求数据并传给子组件

    /* 子组件 */
    <view>
      <view bind:tap="setId" data-id="1"></view>
    </view>
    
    properties: {
      list: {
        type: Array,
        default: []
      }
    },
    
    methods: {
      setId(e) {
        let id = e.currentTarget.dataset.id
        this.triggerEvent('deleteFav', id)
      }
    }
    
    /* 父页面 */
    <child bind:customEvent="deleteFav"></child>
    
    data: {
      list: []
    },
    deleteFav(e) {
      let id = e.detail // 获取传递过来的数据
      // 根据id请求数据,然后重新setData
      let newData = [1,2,3]
      this.setData({
        list: newData
      })
    }
    

    使用wxParse解析HTML

    1. 下载wxParse,放到utils目录下
    2. 在JS页面引入:import WxParse from '../../utils/wxParse/wxParse'
    Page({
      data:{
        contentHTML:'' // 解析后的HTML
      },
      onLoad: function() {
        // 请求到的HTML数据
        let content = '<div>我是HTML代码</div>', that = this;
        WxParse.wxParse('contentHTML', 'html', content, that, 0);
      }
    })
    
    
    1. 显示解析内容
    <import src="../../utils/wxParse/wxParse.wxml"/>
    <view>
      <!-- 显示内容 -->
      <template is="wxParse" data="{{wxParseData:contentHTML.nodes}}" />
    </view>
    

    图片等比例

    image标签有个mode属性,可以设置图片如何显示,如果文档看的不仔细还真容易发现

    <image src="test.png" mode="widthFix"/>
    

    上拉加载和下拉刷新

    {
      "onReachBottomDistance": 0,
      "enablePullDownRefresh": true
    }
    
    data: {
      limit: 30,
      page: 1,
      list:[],
      count:0
    },
    // 下拉
    onPullDownRefresh: function () {
      this.setData({
        page: 1,
        list:[]
      })
      this.getData()
    },
    // 上拉
    onReachBottom: function () {
      if(this.data.list.length >= this.data.count) {
        return false
      }
      this.setData({
        page: this.data.page + 1
      })
      this.getData()
      wx.stopPullDownRefresh()
    },
    getData: async function () {
      await wxRequest(app.globalData.baseUrl + '/test', {
        data: {
          page: this.data.page,
          limit: this.data.limit,
        }
      }).then((ret) => {
        let list = this.data.list.concat(ret.data.list)
        this.setData({
          list: list,
          count: ret.data.count
        })
      })
    }
    

    上传图片

    任务:小程序上传图片到服务器,最多上传三张,前端可以删除图片

    效果图如下

    使用到的API有两个:wx.uploadFile wx.chooseImage

    示例WXML:

    <view class="sale after-pic">
      <block wx:for="{{imgList}}" wx:key="{{index}}">
        <view class="pic">
          <image src="{{item}}" />
          <icon type="clear" size="20" catchtap="clearImg" data-id="{{index}}"/>
        </view>
      </block>
      <image src="../../images/upload.png" catchtap="chooseImage" />
    </view>
    <button catchtap="onSub">提交</button>
    

    imgList是wx.chooseImage成功后返回的图片临时地址

    示例JS

    Page({
      data: {
        imgList:[]
      },
      // 使用async await是因为图片上传是异步的
      onSub: async function() {
        // 点击提交后,开始上传图片
         let imgUrls = []
         for (let index = 0; index < this.data.imgList.length; index++) {
           await this.uploadFile(this.data.imgList[index]).then((res) => {
             // 这里要注意把res.data parse一下,默认是字符串
             let parseData = JSON.parse(res.data)
             imgUrls.push(parseData.data) // 图片地址
           })
         }
         console.log(imgUrls) // 3张图片上传成功后,执行其他操作
      },
      // 删除某张图片
      clearImg: function (params) {
        let imgList = this.data.imgList
        let id = params.currentTarget.dataset.id // 图片索引
        imgList.splice(id, 1) // 删除
        this.setData({
          imgList: imgList
        })
      },
      chooseImage: function (params) {
        wx.chooseImage({
          count: 3, // 做多3张
          sizeType: ['original', 'compressed'],
          sourceType: ['album', 'camera'],
          success: (res) => {
            // 存储临时地址
            this.setData({
              imgList: res.tempFilePaths
            })
          }
        })
      },
      uploadFile: function (filePath) {
        // 返回Promise是为了解决图片上传的异步问题
        return new Promise( (resolve, reject) => {
          wx.uploadFile({
            url: app.globalData.baseUrl + '/file/upload', // 上传地址
            filePath: filePath,
            name: 'file', // 这里的具体值,问后端人员
            formData: {},
            header: {
              "Content-Type": "multipart/form-data"
            },
            success: (res) =>{
              // 图片上传成功后,后端会返回一个地址,可以把它存到imgUrls
              this.imgUrls.push(res.data.data)
            },
            fail:(err) => {
              console.log(err)
            }
          })
        })
      }
    })
    

    动态标题

    onLoad的时候动态设置标题

    wx.setNavigationBarTitle({
      title: '新标题'
    })
    

    结语

    以上是仅为我个人在开发过程中遇到的一些问题,若有错误还请批评指正,感谢阅读

  • 相关阅读:
    以流的形式将文件写入页面,直接下载
    多线程异步处理示例
    windows端口占用查看
    Spring MVC中默认的ResponseBody为String的乱码问
    inode安装
    uploadfy使用
    动态时间工具类
    常量设置
    项目配置热部署
    springboot异常:yml文件无法识别
  • 原文地址:https://www.cnblogs.com/yesyes/p/9330864.html
Copyright © 2011-2022 走看看