资讯专栏INFORMATION COLUMN

2019,帮助你更好的开发小程序

DevTalking / 1542人阅读

摘要:前言原生开发小程序有了两个项目,在原生开发小程序经验技巧方面有一些自己的总结,此篇文章做原创分享本文适合老手查看,新手请参阅官方文档,同步至。

前言

原生开发小程序有了两个项目,在原生开发小程序经验技巧方面有一些自己的总结,此篇文章做原创分享!

本文适合老手查看,新手请参阅官方文档,同步至github。

1.发布订阅处理复杂逻辑
支持先订阅后发布,以及先发布后订阅

方法源码

var Event = (function() {
  var clientList = {},
    pub,
    sub,
    remove;

  var cached = {};

  sub = function(key, fn) {
    if (!clientList[key]) {
      clientList[key] = [];
    }
    // 使用缓存执行的订阅不用多次调用执行
    cached[key + "time"] == undefined ? clientList[key].push(fn) : "";
    if (cached[key] instanceof Array && cached[key].length > 0) {
      //说明有缓存的 可以执行
      fn.apply(null, cached[key]);
      cached[key + "time"] = 1;
    }
  };
  pub = function() {
    var key = Array.prototype.shift.call(arguments),
      fns = clientList[key];
    if (!fns || fns.length === 0) {
      //初始默认缓存
      cached[key] = Array.prototype.slice.call(arguments, 0);
      return false;
    }

    for (var i = 0, fn; (fn = fns[i++]); ) {
      // 再次发布更新缓存中的 data 参数
      cached[key + "time"] != undefined
        ? (cached[key] = Array.prototype.slice.call(arguments, 0))
        : "";
      fn.apply(this, arguments);
    }
  };
  remove = function(key, fn) {
    var fns = clientList[key];
    // 缓存订阅一并删除
    var cachedFn = cached[key];
    if (!fns && !cachedFn) {
      return false;
    }
    if (!fn) {
      fns && (fns.length = 0);
      cachedFn && (cachedFn.length = 0);
    } else {
      if (cachedFn) {
        for (var m = cachedFn.length - 1; m >= 0; m--) {
          var _fn_temp = cachedFn[m];
          if (_fn_temp === fn) {
            cachedFn.splice(m, 1);
          }
        }
      }
      for (var n = fns.length - 1; n >= 0; n--) {
        var _fn = fns[n];
        if (_fn === fn) {
          fns.splice(n, 1);
        }
      }
    }
  };
  return {
    pub: pub,
    sub: sub,
    remove: remove
  };
})();

全局挂载使用

// app.js
App({
  onLaunch: function(e) {
    // 注册 storage,这是第二条
    wx.Storage = Storage;
    // 注册发布订阅模式
    wx.yue = Event;
  }
});

使用实例

// 添加收货地址页面订阅
 onLoad: function (options) {
        wx.yue.sub("addAddress", function (data) {
            y.setData({
                addAddress: data
            })
        })
 }
/**
 * 生命周期函数--监听页面隐藏
 */
 onHide: function () {
    // 取消多余的事件订阅
    wx.Storage.removeItem("addAddress");
},
 onUnload: function () {
    // 取消多余的事件订阅
    wx.yue.remove("addAddress");
}
// 传递地址页面获取好数据传递
wx.yue.pub("addAddress", data.info);
// 补充跳转返回
注意:使用完成数据后要注意卸载,在页面被关闭时操作
2.Storage
storage 管理封装,用法和上面的一致,挂载在全局对象上调用,使用介绍就不列了
const Storage = {
  //  第一个 key 参数可以省略,直接传递 obj 对象,支持 callback
  setItem: function(key, obj, callback) {
    const getType = function(a) {
      var typeArray = Object.prototype.toString.call(a).split(" ");
      return typeArray[1].slice(0, -1);
    };
    var firstParamType = getType(arguments[0]);
    if (firstParamType === "Object") {
      var keyArrayLength = Object.keys(arguments[0]).length;
      var index = 0;
      for (var keyName in arguments[0]) {
        index++;
        wx.setStorage({
          key: keyName,
          data: arguments[0][keyName],
          success: index == keyArrayLength ? arguments[1] : function() {}
        });
      }
    }
    if (firstParamType === "String") {
      wx.setStorage({
        key: key,
        data: obj,
        success: callback || function() {}
      });
    }
  },
  getItem: function(key) {
    return wx.getStorageSync(key);
  },
  removeItem: function(key) {
    wx.removeStorage({
      key: key
    });
  }
};
例子
wx.Storage.setItem(
  {
    class_pid: that.data.class_pid,
    class_id: that.data.class_id,
    is_import: that.data.is_import,
    shop_type: 1
  },
  function() {
    console.log("Storage 已设置完毕!");
  }
);
3.filter 计算属性
小程序也有计算属性,你知道吗?
// 文件名称为 :filter.wxs
// 不支持es6,Date,Number
function filterOrderTitleName(status) {
  switch (status) {
    case "1":
      return "待支付";
    case "2":
      return "待配送";
    case "3":
      return "配送中";
    case "4":
      return "已完成";
  }
}
function filterPrice(str) {
  // 四舍五入 格式化数字
  // toFix(8440.55,1) => 8440.6
  var times = Math.pow(10, 2);
  var roundNum = Math.round(str * times) / times;
  return roundNum.toFixed(2);
}

module.exports = {
  filterOrderTitleName: filterOrderTitleName,
  filterPrice: filterPrice
};

使用实例,过滤处理打折后的金额小数位数

// 当前文件名:shoppingCart.wxml
// wxs 文件顶部导入

 ¥{{filter.filterPrice(item.plus*100*item.price/1000)}}
    
        会员{{item.dazhe}}折
    
 
4.flex Style
分享我常使用的自定义的一套 flex 样式,快速实现布局
/* -------------------------------------------------------------flex------------------------------------------------------- */

.center {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 单行水平垂直 */

.oneLineCenter {
  display: flex;
  display: -webkit-flex;
  justify-content: center;
  align-items: center;
}

/* 单行垂直居中,水平向左 */

.oneLineStart {
  display: flex;
  display: -webkit-flex;
  justify-content: flex-start;
  align-items: center;
}

/* 单行垂直居中,水平向右 */

.oneLineEnd {
  display: flex;
  display: -webkit-flex;
  justify-content: flex-end;
  align-items: center;
}

/* 单行垂直居中,水平保持间距 */

.oneLineAround {
  display: flex;
  display: -webkit-flex;
  justify-content: space-around;
  align-items: center;
}

/* 单行垂直居中,两端对齐 */

.oneLineBetween {
  display: flex;
  display: -webkit-flex;
  justify-content: space-between;
  align-items: center;
}

/* 超过单行设置的最大宽度,允许换行显示 */

.f-wrap {
  flex-wrap: wrap;
}

/* 多轴线方向,一般配合  wrap 使用 */

/* 宽度不足换行后,垂直方向靠上排列 */

.mulitLineStart {
  display: flex;
  display: -webkit-flex;
  flex-wrap: wrap;
  align-content: flex-start;
}

/* 宽度不足换行后,垂直方向居中排列 */

.mulitLineCenter {
  display: flex;
  display: -webkit-flex;
  flex-wrap: wrap;
  align-content: center;
}

/* 宽度不足换行后,垂直方向靠下排列 */

.mulitLineEnd {
  display: flex;
  display: -webkit-flex;
  flex-wrap: wrap;
  align-content: flex-end;
}

/* 宽度不足换行后,垂直方向上保持间隔排列 */

.mulitLineAround {
  display: flex;
  display: -webkit-flex;
  flex-wrap: wrap;
  align-content: space-around;
}

/* 宽度不足换行后,垂直方向上靠两侧最顶开始间隔排列 */

.mulitLineBetween {
  display: flex;
  display: -webkit-flex;
  flex-wrap: wrap;
  align-content: space-between;
}

/* 纵轴变主轴,垂直靠上,水平居中 */

.columnStart {
  display: flex;
  display: -webkit-flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: center;
}

/* 纵轴变主轴,垂直靠下,水平居中 */

.columnEnd {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
}

/* 纵轴变主轴,垂直居中,水平居中 */

.columnCenter {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

/* 纵轴变主轴,垂直间隔排列,水平居中 */

.columnAround {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
}

/* 纵轴变主轴,垂直上下两侧按间隔排列,水平居中 */

.columnBetween {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
}
/* 纵轴变主轴,垂直上下两侧按间隔排列,水平靠左 */

.columnBetweenStart {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
}
/* 纵轴变主轴,垂直上下两侧按间隔排列,水平靠右 */

.columnBetweenEnd {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-end;
}
5.async await

使用runtime.js,使小程序支持 async await,拷贝文件至项目目录下。

实例用法

const regeneratorRuntime = require("../../utils/runtime.js");
Page({
  shopCartInit() {
    var y = this;
    // 拿到商铺位置信息再去渲染购物计算当前的address符合不符合规定
    var showCartList = function() {
      // 显示全局的地址信息
      var globalAddress = wx.Storage.getItem("globalAddress");
      if (globalAddress) {
        y.setData({
          globalAddress: globalAddress,
          addr_id: globalAddress.id
        });
        y.calculateDistance(
          qqmapsdk,
          globalAddress.latitude,
          globalAddress.longitude
        );
      } else {
        y.setData({
          globalAddress: {}
        });
      }
    };
    // await 等待获取商铺位置信息
    async function getShopPosTionMsg() {
      await util.promiseRequest(api.merchant_addr, {}).then(res => {
        var data = res.data.response_data.lists[0];
        y.setData({
          shop_lat: data.latitude, // 商铺纬度
          shop_lng: data.longitude, // 商铺经度
          peiSongFanWei: data.scope // 配送范围
        });
      });
    }

    async function initData() {
      await getShopPosTionMsg();
      await showCartList();
      util.closeLoading();
      y.setData({
        loading: false
      });
    }
    // 开始执行
    initData();
  }
});
6.addKey Api
使用自定义属性的方法辅助完成业务逻辑,已发布至 addKey
/**
 * 为数组添加新的自定义键值以及过滤每个子项的方法
 *
 * @param {*} arr
 * @param {*} obj { isShow:false,isStar:false}
 * @param {*} filterFn
 * @returns
 */
function addKey(sourceArray, extendObj, filterFn) {
  var getType = function(a) {
    var typeArray = Object.prototype.toString.call(a).split(" ");
    return typeArray[1].slice(0, -1);
  };
  var secondParamType = getType(arguments[1]);

  if (!getType(sourceArray) == "Array") {
    throw new Error("The first argument must be an array type");
  }
  if (secondParamType === "Object") {
    return sourceArray.forEach((v, index, sourceArray) => {
      for (var key in extendObj) {
        v[key] = extendObj[key];
      }
      typeof filterFn === "function" ? filterFn(v, index, sourceArray) : "";
    });
  } else if (secondParamType === "Function") {
    return sourceArray.forEach((v, index, sourceArray) => {
      arguments[1](v, index, sourceArray);
    });
  } else {
    return sourceArray;
  }
}

使用实例

util.addKey(data, { y_isCheck: false }, function(v) {
  v.dazhe = Number(v.plus);
});
this.setData({
  cartList: data
});
7. 组件化复用开发实践
组件化解构项目元件,提高开发效率,可参照官方介绍起步 !

这里介绍一个自定义的跑马灯的轮播图组件实例

(1) 第一步,查看目录结构划分,主要为 Carousel 组件 在 index 页面的使用
│
├───component
│   └───Carousel
│           Carousel.js
│           Carousel.json
│           Carousel.wxml
│           Carousel.wxss
│
├───filter
│       filter.wxs
│
├───pages
│   └───index
│           index.js
│           index.json
│           index.wxml
│           index.wxss
│
└───utils
        api.js
        runtime.js
        util.js
(2) 第二步我们分析看如何使用,设计 组件需要的 props

数据项,必须 bannerList

轮播图的固定高度 swiperHeight

自定义轮播按钮小点,宽与高一致,圆形 dotWidthAndHeight

轮播按钮盒子距离顶部的高度 dotTop

最终在 index.wxml 的实际使用


  
(3).业务代码编写

Carousel.json
开启自定义组件模式

{
  "component": true
}

Carousel.wxml


  
  
    
      
    
  
  
  
    
      
    
  

Carousel.js

Component({
  /**
   * 组件的属性列表 必须
   */
  properties: {
    bannerList: {
      // 属性名
      type: Array, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
      value: [], // 属性初始值(可选),如果未指定则会根据类型选择一个
      observer: function(newVal, oldVal) {} // 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:"_propertyChange"
    },
    dotWidthAndHeight: String,
    swiperHeight: String, // swiper 高度
    dotTop: String // 小点距离顶部高度
  },

  /**
   * 组件的初始数据
   */
  data: {
    swiperCurrentIndex: 0,
    indicatorDots: false // 自定义轮播按钮
  },
  /**
   * 组件的方法列表
   */
  methods: {
    swiperChange: function(e) {
      var source = e.detail.source;
      if (source === "autoplay" || source === "touch") {
        this.setData({
          swiperCurrentIndex: e.detail.current
        });
      }
    },
    selectCarouselByIndex: function(e) {
      this.setData({
        swiperCurrentIndex: Number(e.currentTarget.id)
      });
    },
    // 轮播图跳转至内部页面
    toHref(e) {
      const data = e.currentTarget.dataset;
      // type = 2,根据 goods_id 展示商品详情
      // type = 3, 展示富文本的活动详情页面
      if (data.type === "2") {
        wx.navigateTo({
          url: `../sort_detail/sort_detail?id=${data.id}`
        });
      } else if (data.type === "3") {
        wx.yue.pub("renderData", data.content);
        wx.navigateTo({
          url: `../activity_detail/activity_detail`
        });
      }
    }
  }
});
更多

wxapp-rainbow 安利一下自己写的小程序组件库(偏功能性)

uploadImg 上传图片

carousel 轮播图

authorization 授权登录

loading 加载中

参考

https://juejin.im/post/5c14b2...

微信小程序自定义组件VS vue组件实践与理解

生态圈

ColorUI 鲜亮的高饱和色彩,专注视觉的小程序组件库

taro 多端统一开发框架,支持用 React 的开发方式编写一次代码,生成能运行在微信小程序、H5 、 React Native 等的应用

uni-app 使用 Vue.js 开发跨平台应用的前端框架

微信小程序开发资源汇总

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102816.html

相关文章

  • 2019 年了,为什么我还在用 jQuery?

    摘要:无论是还是,对许多应用来说,这个大小都是完全可以接受的。但是为了不用,放弃向后兼容那我觉得还是用得了。自从年双十一正式上线,累计处理了亿错误事件,付费客户有金山软件百姓网等众多品牌企业。 译者按: 看来 jQuery 还是有一些用武之地的。 原文: Why Im Still Using jQuery in 2019 译者: Fundebug 为了保证可读性,本文采用意译而非直译...

    aikin 评论0 收藏0
  • 2019 年值得学习顶级 JavaScript 框架与主题

    摘要:我们的目标是找出最有职业投资回报率的主题和技术。比特币在几年内增长了若干个量级。比特币倍拐点在这个图表中,每个箭头始于倍点,指向价格修正后的最低点。 showImg(https://segmentfault.com/img/remote/1460000017919159); 图:Jon Glittenberg Happy New Year 2019 (CC BY 2.0) 又到了一年的...

    legendaryedu 评论0 收藏0
  • 2019年云架构和云计算趋势

    摘要:云计算技术完全依赖于硬件和软件的虚拟化及其面向服务的架构和其他一些增值服务。其次,一些政府赞成取消有利于网络中立和促进竞争的法规。因此,云计算成为可行的选择。尽管如此,云基础架构必须与适当的安全和备份解决方案相辅相成,以确保数据安全。 随着互联网的高速发展,计算和软件开发的进步,任何人都可以坐在他/她的厨房桌旁享受世界上最好的技术。几乎所有小型或大型企业都无所谓,似乎已将注意力转移到考...

    snowLu 评论0 收藏0
  • 2019年云架构和云计算趋势

    摘要:云计算技术完全依赖于硬件和软件的虚拟化及其面向服务的架构和其他一些增值服务。其次,一些政府赞成取消有利于网络中立和促进竞争的法规。因此,云计算成为可行的选择。尽管如此,云基础架构必须与适当的安全和备份解决方案相辅相成,以确保数据安全。 随着互联网的高速发展,计算和软件开发的进步,任何人都可以坐在他/她的厨房桌旁享受世界上最好的技术。几乎所有小型或大型企业都无所谓,似乎已将注意力转移到考...

    qpwoeiru96 评论0 收藏0
  • 阿里20亿程序繁星计划最需要知道几个问题(0325更新)

    摘要:月日,在阿里云峰会北京站上,阿里巴巴旗下的阿里云支付宝淘宝钉钉高德等联合发布阿里巴巴小程序繁星计划提供亿元补贴,扶持万小程序开发者万商家。会上,阿里云正式发布了小程序云。看到繁星计划已上热搜。通过小程序云服务可以极大的降低交付部署成本。3月21日,在2019阿里云峰会·北京站上,阿里巴巴旗下的阿里云、支付宝、淘宝、钉钉、高德等联合发布阿里巴巴小程序繁星计划:提供20亿元补贴,扶持200万+小...

    lansheng228 评论0 收藏0

发表评论

0条评论

DevTalking

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<