微信小程序原生自定义组件开发实战

2017.11月初期待已久的原生小程序自定义组件功能已经发布,此次发布版本为 1.6.3,尽管此前有模板<template>和开源 wx-parse 工具也可以一定程度上复用代码,但相比此次原生小程序推出的组件化编程,都略有不足。话不多说,通过动手写一个组件来熟悉组件化编程带来的便利。

写在前面的话:

微信官网虽然提供了许多组件,但实际应用时仍感觉稍显疲软,如消息提示框只提供了成功与加载两种状态,那么如果失败了如何提示?还有模态框只有简单的 title 和 content 属性,内部并不支持自定义 wxml,等等,作者将工作中用到的微信组件文档中没有的 UI 自定义封装了一些,有需要的可以看下:wx-ui (持续补充中)

一、开发前准备

  1. 目前自定义组件相关特性处于公测阶段。如果需要使用相关特性,请确认在项目选项中已勾选“预览/上传时使用新特性”;
  2. 小程序基础库从 1.6.3才开始支持组件化编程,在此之前先升级开发工具,选择高于1.6.3版本的基础库来体验组件化编程。
  3. 微信小程序官方组件文档。 建议先看一遍,在跑一遍下方的示例代码。
image.png

二、概述

1. 目标组件

常见的价格加减组件,当设置值小于最小值时,减号 - 不可点击,当设置值大于最大值时,加好不可点击,效果如下:

price组件.gif

2. 组件化开发需要注意两点

  • 页面如何往组件传值?
  • 组件如何将自身值反馈给页面?

tips: 第一遍看可能有点绕,建议将代码 copy 到开发工具跑一遍,在对照着下方的解释去理解会事半功倍。

三、价格组件实例

写一个组件,在页面中使用它。

1. 书写价格组件 price

  • 组件不需要在 app.json 中的 pages 属性中进行配置,因为它不是一个页面;
  • 组件和普通页面一样,有 .wxml、.wxss、*js 和 *.json 四个文件;
  • 组件必须要在 *.json 文件中进行申明这是一个组件,具体代码见 price.json 文件;
  • 组件的 *wxml 和 *.wxss 和页面的书写没有任何区别,这里不多说;
  • 组件的 *.js 文件使用了新的构造函数 Component 代替了页面构造函数 Page,用来管理属性和事件。官方文档:Component 构造器, *.js 文件是组件中最重要的文件,在页面中使用组件时再介绍它。

1)组件页面 price.wxml

price 组件的页面显示。

<view class="quantityViewStyle">
  <view class="minusStyle" bindtap="minus" style="color:{{num==min?'#DADADA':white}}">-</view>
  <view class="inputViewStyle">
    <input class="inputStyle" value="{{num}}" type="number" bindblur="onInputBlur"/>
  </view>
  <view class="plusStyle" bindtap="plus" style="color:{{num==max?'#DADADA':white}}">+</view>
</view>

2)组件样式 price.wxss

price 组件的样式文件。

.quantityViewStyle {
  display:flex;
  border:0rpx solid #DADADA;
  border-radius:6rpx;
  width: 220rpx;
}
.minusStyle {
  height:58rpx;
  width:60rpx;
  border-right:0rpx solid #DADADA;
  display:flex;
  justify-content:center;
  align-items:center;
}
.plusStyle {
  height:58rpx;
  width:60rpx;
  display:flex;
  justify-content:center;
  align-items:center;
}
.inputViewStyle {
  height:58rpx;
  width:100rpx;
  border-right:0rpx solid #DADADA;
}
.inputStyle {
  width:80rpx;
  height:54rpx;
  text-align:center;
  font-size:26rpx;
  background:white;
}

3)组件逻辑 price.js

  • Component 是个新的构造器,主要关注其中 properties 和 methods 两个属性;
  • 在 properties 中,如设置 num 字段,用 type 和 value 修饰,type 表示 num 是个数值,而 value 表示 num 的默认值,如果页面调用组件时没有传值,那么 num 就是 5;
  • methods 属性里写组件的相关方法,主要注意 this.triggerEvent('custom', { value: num }) 这行代码,这是子组件往页面传值的唯一方式。
    • 组件往页面传值,通常的写法是在页面调用组件时添加一个事件监听,这样只要组件中值改变时,通过这个事件就可以监听到改变的值;
    • 第一个参数为页面定义的监听事件的事件类型,名称自定义。
      • 事件类型:在 index.wxml 中调用组件 price 时添加了事件监听函数bindcustom="onPageInputChange",其中 bind 是微信小程序绑定事件的一个前缀,后面的 custom 才是具体的事件类型;
      • 要注意第一个参数的值要与事件监听函数事件类型相同;
    • 第二个参数是个对象,表示往使用该组件的页面中传的值,在 index.js 中onPageInputChange: function (e) { // .... } 中的参数 e 就是这地方传递过去的。
Component({
  properties: {
    // 这里定义了innerText属性,属性值可以在组件使用时指定
    num: {
      type: Number,
      value: 5,
    },
    min: {
      type: Number,
      value: 0,
    },
    max: {
      type: Number,
      value: 10
    }
  },
  methods: {
    // 加法
    plus: function () {
      // 加值小于最大值,才允许加法运算
      var num = this.data.num + 1;
      if (num <= this.data.max) {
        this.setData({
          num: num
        })
        this.triggerEvent('custom', { value: num })
      }
    },
    // 减法
    minus: function () {
      // 减值大于最小值,才允许减法运算
      var num = this.data.num - 1;
      if (num >= this.data.min) {
        this.setData({
          num: num
        })
        this.triggerEvent('custom', { value: num })
      }
    },
    // 文本框失去焦点事件,判断输入值是否为数字
    onInputBlur: function (e) {
      var value = e.detail.value;
      if (isNaN(value)) {
        // 不是数字,直接置为最小值
        this.setData({num: this.data.min})
      } else {
        // 是数字,输入值大于最大值,置为最大值,同理最小值
        if (value > this.data.max) {
          this.setData({ num: this.data.max })
        } else if (value < this.data.min) {
          this.setData({ num: this.data.min })
        }
      }
    }
  }
})

4)组件配置 price.json

声明 price 是个组件。

{
  "component": true
}

2. 在页面中使用组件

  • 在页面中使用组件,需要先在 *.json 文件中进行配置,格式如下;
    • component-tag-name 为组件在页面(*.wxml)中使用的名称,这里可以自定义,可以叫 price,也可以叫 my-price,但不可有数字,否则会报错;
    • path/to/the/custom/component 为组件的路径,这里写相对路径,也就是 ../ 开头的路径,不要有后缀,具体见下方 index.json 文件。
{
  "usingComponents": {
    "component-tag-name": "path/to/the/custom/component"
  }
}
  • 页面需要在 app.json 中配置,别忘记了。

1)页面 index.wxml

<view style="display: flex;flex-direction: row;justify-content: space-between;padding: 0 20rpx;">
  <view>¥26.3</view>
  <!-- 以下是对一个自定义组件的引用 price -->
  <price  num="{{price}}" bindcustom="onPageInputChange"/> 
  <view>{{price}}</view>
</view>
  • 这里调用组件的代码为 <price num="{{price}}" bindcustom="onPageInputChange"/>
  • num 字段为设置价格组件的默认值,在 price.js 中可以在 properties 属性中找到它;
  • bindcustom="onPageInputChange" 为自定义事件监听函数,用法为监听价格组件文本框中数值变化。在下方的 index.js 中可以看到事件处理函数 onPageInputChange 有个参数 e,这个参数需要在组件中进行传递。通过 e.detail.value 可以获取文本框中的值。

2)页面逻辑 index.js

Page({
  data: {
    price: 5
  },
 
  onPageInputChange: function (e) {
    this.setData({ price: e.detail.value})
  }
})

3)配置文件 index.json

声明使用组件 price。

{
  "usingComponents": {
    "price": "../price/price"
  }
}

4)app.json

配置 index 页面。

{
  "pages":[
    "pages/index/index"
  ],
  "window":{
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle":"black"
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345