微信小程序入门

1,971 阅读11分钟

本文是微信开放文档中一些入门知识点的整理和练习,如果要详细了解小程序开发,请细看微信开放文档小程序开发指南

准备工作

  1. 申请账号

    • 小程序注册
    • 小程序后台设置小程序的名称等信息,在设置->基本设置中,找到小程序的AppID, 这个id在开发过程中会用到。
  2. 下载开发者工具

    根据自己的需要选择开发者工具,普通小程序开发者工具。我选择了稳定版。

  3. 创建一个项目

    打开开发者工具,点击界面中的加号,进入创建项目界面,可以自己设置项目名称以及项目代码放置的目录位置。在AppID输入框中填入上文说到的AppID,创建一个小程序项目。如果只是为了练习,不用发布,也可以直接点击测试号填入一个测试AppID, 创建一个项目。

  4. 详细步骤参考:普通小程序入门介绍

基础知识

打开上文创建的小程序代码,我们发现微信小程序主要由.json文件(配置文件)、.wxml文件(类似HTML)、.wxss文件(类似css)、.js文件组成。

WXML

标签

.wxml中填入的内容主要是组件,其中比较常用的是viewtextbuttoninput等,view类似于HTML中的divtext类似于HTML中的span,除此之外,微信小程序还提供了一些常用功能的组件,比如rich-text富文本组件,以及一些媒体组件,比如camera组件能够调用系统相机。小程序组件

在wxml中,block不是一个组件,它是一个包装元素,不会在页面中做任何渲染,只接受控制属性,比如wx:ifwx:for。在block上添加比如classhidden之类的属性是不会生效的。

wxml中可以使用模板(template),使用方式如下:

定义模版和使用模板:

<template name="A">
  <text>123</text>
</template>
<template is="A"></template>

引用模板文件:

<!--方法1-->
<import src="test.wxml" />
<!--方法2-->
<include src="test.wxml" />

可以通过data属性向模版中传入数据:

<!-- 其中test是一个对象 -->
<include src="test.wxml" data="{{...test}}"/> 

小程序模板

控制

wxml中可以使用wx:ifhidden来控制内容的显示隐藏,其中hidden属性值为true时会渲染出组件内容,带有样式display:none;wx:if为的属性值为false时,组件内容不会渲染。

wxml中通过wx:for来遍历数组数据,渲染出相应内容。例如想要输出一个1-5的数字列表,可以现在js文件中定义好数组数据

data: {
  testArr: [1, 2, 3, 4, 5]
}

然后在wxml文件中利用数组渲染出内容:

<block wx:for="{{testArr}}" wx:key="index">
  <text>{{item}}</text>
</block>

其中wx:key用于提高渲染效率。添加这个属性之后,假如现在要倒序排这个列表,那么组件不会重新创建,而是会将已创建的组件重新排序。数组的索引值默认为index,数组元素默认为item,如果要自定义这两个值,需要使用到wx:for-indexwx:for-item属性。

wx:key` 的值以两种形式提供:

  1. 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
  2. 保留关键字 this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

最好使用类似id这样独一无二的值作为key值,而不是使用index

条件逻辑和列表渲染

事件

wxml中通过事件属性绑定事件触发时调用的函数。

<view>
  <text>{{test}}</text>
  <button bindtap="testTap">改变test值</button>
</view>

在js中定义事件。

Page({
  data: {
    test: 123
  },
  testTap: function () {
    this.setData({
      test: 666
    })
  }
})

微信小程序事件

WXSS

微信小程序提供了rpx单位,这是一个相对单位,微信小程序规定屏幕宽度为750rpx,当手机屏幕宽度改变时,1rpx所代表的像素值也不同。

在写手机浏览器的页面时,如果用rem来做自适应,就需要先获取屏幕宽度,选择某个比例,设置根元素的字体大小,再使用rem相对单位来定义元素的尺寸。

而在微信小程序中,只需要使用rpx单位就能简单地完成屏幕自适应了。

详情参考:微信WXSS

在小程序中使用flex布局能够很快地布局页面,关于flex布局部分可以专门详细了解一下。微信小程序文档中也给出了对flex布局的说明,参考地址:flex布局

APP

在微信小程序项目的根目录下,有app.jsapp.jsonapp.wxss文件,其中app.wxss文件中可以定义全局样式,app.json中是配置文件,app.js用于定义App。

  1. app.json

app.json用于进行全局配置,在pages中定义页面路径,在tabBar中定义标签栏的各个标签的路径,图标等。使用开发者工具在pages中添加一个不存在的页面路径,比如:

  "pages": [
    "pages/example/example"
  ],

就会在项目的pages文件目录下创建一个包含.js.json.wxml.wxss文件的文件夹,这个文件夹中的文件就是新创建的页面。

tabBar中添加路径,就能创建出标签栏,还可以定义标签栏的图标,样式等。以下代码配置了一个只有文字的标签栏:

  "tabBar": {
    "list": [
      {
        "pagePath": "pages/example/example",
        "text": "示例"
      },
      {
        "pagePath": "pages/example1/example1",
        "text": "示例1"     
      }
    ]
  },

详情参考:小程序全局配置

  1. app.js

app.js中,通过调用App()来注册小程序,App()的参数是一个对象,这个对象用于定义App的生命周期,监听函数,方法,全局数据。

App({
  // 生命周期
  onLaunch: function () {
    this.testFunc()
  },
  // 监听函数
  onError: function () {
    console.log('错误发生了')  
  },
  // 方法
  testFunc: function () {
    let test = this.globalData.test
    console.log(test)
    this.globalData.test = 'bbb' // 修改全局数据
    console.log(this.globalData.test)
  },
  // 全局数据
  globalData: {
    test: 'aaa'
  }
})

如果要在别处(app.js文件之外的地方)使用全局数据,需要先通过getApp()方法得到App的实例。例如:

let app = getApp()
let testData = app.globalData.test

详情参考:微信小程序App。有其他的监听函数比如页面不存在的监听函数onPageNotFound也挺有用的。不过有个坑是微信开发者工具中,onPageNotFound不会触发, 这个回答说开发版的微信开发者工具处理了这个问题,但我并没有因为这个问题去下载一个非稳定的开发版工具,直接在真机上测试了,但是很奇怪的是,用着用着,在开发者工具上又没有这个问题了。如果遇到这个onPageNotFound不会触发的问题,可以尝试更新微信开发者工具到最新稳定版试试。

Page

每个页面一般也会包含.json.js.wxss.wxml几个文件,在.json文件中可以配置引入的组件,小程序的样式等。如果要在页面A中引入组件ab.json文件为:

{
  "usingComponents": {
    "a-component": "/components/a/a",
    "b-component": "/components/b/b"
  }
}

详情参考:小程序页面配置

定义

注册页面使用Page()方法,Page()中也是一个对象,此对象与App()方法中传入的对象类似,也包含生命周期,监听函数,数据,但是具体的属性不同。

Page({
  // 页面初始数据
  data: {
    test: 'aaa'
  },
  // 生命周期
  onLoad: function () {
    this.testFunc()
    console.log(this.data.test)
  },
  // 监听函数
  onPageScroll: function () {
    console.log('页面滚动了')
  },
  // 方法
  testFunc: function () {
    this.setData({
      test: 'bbb'
    })
  }
})

页面中需要使用this.setData()来改变数据(组件中也是一样)。 Page的生命周期

路由

使用wx.navigateTo()跳转到一个新的页面,并且新页面会添加进页面栈中。

使用wx.redirectTo()跳转到新的页面,当前页面出栈,新页面会添加进页面栈中。

以上两个方法都只能跳转非tab的页面,标签栏上的页面之间的跳转,需要使用wx.switchTab()

wx.navigateBack()函数用于页面返回。

getCurrentPages()函数能够获得当前的页面栈。

用一个简单的数组stackArr假设为页面栈,假设初始的stackArr[x, y, z]xyz分别代表三个页面,以下的路径分别代表abcde页面。

wx.navigateTo({
  url: "/pages/a/a"
})
// stackArr: [x, y, z, a]

wx.navigateTo({
  url: "/pages/b/b"
}) 
// stackArr: [x, y, z, a, b]

wx.redirectTo(){
  url: "/pages/c/c"
}
// stackArr: [x, y, z, a, c]

wx.navigateBack({
  delta: 2  // 返回前2页,这个数字代表返回的页数
})
// stackArr: [x, y, z],当前的页面是页面z
wx.switchTab({
  url: '/pages/d/d'
})

// stackArr: [d],因为d是tab页,所以之前栈中的页面会全部出栈,只留下d页面

详情参考:小程序页面路由

Component

这里的组件主要说的是自定义组件。为了便于说明,假设当前场景为a组件中包含了b组件,并且a是一个列表,每个列表项是b组件,点击b组件删除按钮能够删除该列表项。

定义

b.json

{
  "component": true
}

配置当前模块为组件。

b.js

Component({
  // 组件代码共享的特性
  behaviors: [],
  // 属性
  properties: {
    itemData: String,
    itemIndex: Number
  },
  // 数据
  data: {
    test: 'aaa'
  },
  // 生命周期
  lifetimes: {
    attached: function () {
      this.testFunc()
    }
  },
  // 方法
  methods: {
    testFunc: function () {
      this.setData({
        test: 'bbb'
      })
    },
    deleteItem: function () {
      let itemIndex = this.properties.itemIndex
      this.triggerEvent('deleteItem', { itemIndex })
    }
  }
})

如上代码所示,组件的properties中定义了组件属性,data中定义了组件的数据,组件的生命周期和方法与AppPage不同,是提取出来分别放在lifetimesmethods属性下的。(老版本的生命周期没有放在lifetimes属性中)。 b.wxml

<view>
  <text>{{itemData}}</text>
  <text style="display: inline-block; margin-left: 20px;"
  bindtap="deleteItem">X</text>
</view>

这是b组件代表的列表项的内容,包含文本和一个删除按钮。用style稍微加了点样式。

使用

a组件中引入b组件(当然最终需要将a组件引入页面中进行展示,引入的方法与a组件引入b组件的方法相同)。

a.json

{
  "component": true,
  "usingComponents": {
    "b-component": "../b/b"
  }
}

定义当前模块为组件,并且使用了b组件。

a.wxml

<view>
  <block wx:for="{{listArr}}" wx:key="{{index}}">
    <b-component itemData="{{item}}" itemIndex="{{index}}" bind:deleteItem="deleteItem"/>
  </block>
</view>

a组件中的listArr数组,使用wx:for将数组内容渲染出来。将每个数组项的数据通过属性传递给子组件:itemData="{{item}}"itemIndex="{{index}}"。给子组件绑定了事件:bind:deleteItem="deleteItem

a.js

Component({
  data: {
    listArr: ['第一行的数据', '第二行的数据', '第三行的数据']
  },
  methods: {
    deleteItem: function (event) {
      let { itemIndex } = event.detail
      let copyArr = this.data.listArr.slice()
      copyArr.splice(itemIndex, 1)
      this.setData({
        listArr: copyArr
      })
    }
  }
})

定义组件中的数据和方法。

父子组件通信

如上面组件部分的代码所示,父组件通过给子组件的属性赋值来给子组件传值,子组件通过触发绑定的函数来改变父组件的数据。

  1. 父组件传值给子组件

父组件通过给子组件的属性赋值来给子组件传值:

<b-component itemData="{{item}}" itemIndex="{{index}}" bind:deleteItem="deleteItem"/>

这里要注意,在父组件中绑定事件的时候bind:和自定义事件名deleteItem之间是没有空格的。

子组件通过定义的properties属性能够获取到父组件传来的值:

  properties: {
    itemData: String,
    itemIndex: Number
  },

通过this.properties.itemIndex获取到属性的值。

  1. 子组件触发父组件的事件

父组件中定义绑定的函数: wxml中:

bind:deleteItem="deleteItem"

js中:

  deleteItem: function (event) {
    let { itemIndex } = event.detail
    ...
  }
}

函数的实参是从子组件中传入的。在子组件中调用this.triggerEvent触发自定义的事件,this.triggerEvent()函数的第一个参数是自定义事件名称,第二个参数是detail对象,第三个参数是对事件的设置对象(用于设置事件是否冒泡之类的)。 在父组件中通过获取参数的detail属性,得到的就是在子组件中定义的detail对象。

在子组件中触发事件:

<text bindtap="deleteItem">X</text>
methods: {
  deleteItem: function () {
    let itemIndex = this.properties.itemIndex
    this.triggerEvent('deleteItem', { itemIndex })
  }
}

详情参考:小程序组件

监听属性值的变化

使用properties中的属性对象的observer属性可以监听传入组件的属性的值的变化。

Component({
  properties: {
    contactInfo: {
      type: Object,
      value: null,
      observer(newVal, oldVal) {
        ...传入的属性值变化的时候进行的处理
      },
    },
  },
  data: {
  ...

API

微信小程序提供了很多API,前文提到的路由跳转方法只是所有API中的一小部分,可以根据需求在 微信小程序API 中去查找相应的API。

发布上线

  • 在开发者工具的界面的右上角有一个上传按钮,点击上传按钮,设置上传版本后进行上传。上传成功之后小程序后台的管理->版本管理中,开发版本部分会多出一个开发版本,开发版本可以在页面中设置为体验版。
  • 体验版(或某开发版)测试通过,没有问题之后就能提交审核了,这时候审核版本部分就会出现你提交审核的版本。
  • 在审核版本审核通过之后,就能点击发布按钮进行发布了。

其他

  • 微信小程序入门练习-过程条(看了知识点后在本地写的一个入门小组件)。
  • 上文引用的小程序开发指南的链接,只能链接到章节,不能链接到具体的小节,所以参考的时候如果跳转过去没有直接看见相应的内容,往下翻翻就好了。