微信小程序开发

622 阅读20分钟

一. 关于微信小程序

微信小程序是微信里面的小程序,它的开发需要遵守微信的开发规范,开发工具是微信开发者工具,根据版本下载即可。

开发工具地址:微信开发者工具 文档地址:微信小程序开发文档

二. 小程序的结构和配置

1 - 小程序项目结构

官方示例小程序项目结构如下:

项目目录结构如下:

一个小程序主要分为pages,utils,app.js三部分。

  • pages文件夹: 此文件夹里面的每个文件夹都是一个页面,一个页面由四个文件组成(每个页面的名字要保持一致),比如:
    • index.js:首页页面逻辑文件,用于创建页面对象,以及处理页面生命周期控制和数据处理。
    • index.wxml:全称WeiXin Markup Language,用于定义页面中的元素结构,语法遵循XML语法,注意不是HTML语法。
    • index.json(可选):设置当前页面工作时的window的配置,此处会覆盖app.json中的window设置,也就是说只可以设置window中设置的属性。
    • index.wxss(可选):全称Weixin Style Sheet,用于定义界面的样式,语法遵循CSS语法,扩展了CSS基本用法和长度单位,主要就是rpx响应式像素(微信用的是rpx,比CSS更高级一点,比如:width: 10rpx;)。
  • utils文件夹:里面是一些全局的方法,比如日期格式化的方法、网络请求方法等。
  • app.js:小程序的入口文件。
  • app.json:小程序的整体配置(如果在某个页面的.json文件中也做了相同的配置,那么app.json的配置会被覆盖,注意:只会覆盖window里面的配置)。
  • app.wxss:定义全局共享样式。

小程序运行的时候,会先执行app.js文件创建小程序实例对象,然后再把app.json中pages数组的第一个页面作为小程序的默认页面。

2 - 小程序配置

小程序配置分为两部分:全局配置、页面配置。

小程序根目录下的 app.json 文件用来对微信小程序进行全局配置。文件内容为一个 JSON 对象,部分属性如下:

属性类型必填描述
pagesstring[]页面路径列表
windowObject全局的默认窗口表现
tabBarObject底部 tab 栏的表现
networkTimeoutObject网络超时时间
debugboolean是否开启 debug 模式,默认关闭

每一个小程序页面也可以使用 .json 文件来对本页面的窗口表现进行配置。页面中配置项在当前页面会覆盖 app.jsonwindow 中相同的配置项。文件内容为一个 JSON 对象,有以下属性:

属性类型默认值描述
navigationBarBackgroundColorHexColor#000000导航栏背景颜色,如 #000000
navigationBarTextStylestringwhite导航栏标题颜色,仅支持 black / white
navigationBarTitleTextstring导航栏标题文字内容
backgroundColorHexColor#ffffff窗口的背景色
backgroundTextStylestringdark下拉 loading 的样式,仅支持 dark / light
enablePullDownRefreshbooleanfalse是否开启当前页面下拉刷新

小技巧:当我们创建新页面,比如demo1界面时,还要创建demo1文件夹,然后再在demo1文件夹中创建四个文件,这样很麻烦。快捷方式就是,我们直接在app.json的pages数组中添加你将要创建的界面的路径,比如:

"pages": [
    "pages/demo1/demo1"
  ]

这样保存之后,项目的pages文件夹之下就会自动创建同名的demo1界面文件夹,demo1文件夹下面也会自动创建四个同名demo1文件。

3 - tabBar的配置

如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。

属性类型必填默认值描述
colorHexColortab 上的文字默认颜色,仅支持十六进制颜色
selectedColorHexColortab 上的文字选中时的颜色,仅支持十六进制颜色
backgroundColorHexColortab 的背景色,仅支持十六进制颜色
borderStylestringblacktabbar 上边框的颜色, 仅支持 black / white
positionstringbottomtabBar 的位置,仅支持 bottom / top
listArraytab 的列表,详见 list 属性说明,最少 2 个、最多 5 个 tab

其中 list 接受一个数组,只能配置最少 2 个,最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:

属性类型必填说明
pagePathstring页面路径,必须在 pages 中先定义
textstringtab 上按钮文字
iconPathstring图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon。
selectedIconPathstring选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。当 position 为 top 时,不显示 icon。

三. 逻辑层与界面层

1 - 逻辑与界面分离

小程序将我们需要完成的编码划分为两部分:逻辑层、界面层。

逻辑层:是指由javaScript完成业务,将处理完成的数据提供给界面,同时对界面层触发的事件进行处理。 界面层:主要有两部分组成:页面结构(WXML)、页面样式(WXSS),界面层最主要的作用就是展示逻辑层的数据,并且将页面的一些操作(比如点击),通过事件的方式发给逻辑层。

2 - 小程序的逻辑层

小程序的逻辑层主要包括app.js文件,以及每个界面的js文件,小程序的界面层主要包括app.wxss文件,以及每个界面的wxss、wxml文件

  1. 小程序不是运行在浏览器中,所以没有BOM和DOM对象。
  2. 小程序的逻辑层虽然是由javaScript完成业务,但是小程序的js还有一些额外的方法:
App()  // 注册小程序。接受一个 Object 参数,其指定小程序的生命周期回调等。
// App() 必须在 app.js 中调用,必须调用且只能调用一次。不然会出现无法预期的后果。

getApp() // 获取到小程序全局唯一的 App 实例。
// 注意:
// 不要在定义于 App() 内的函数中,或调用 App 前调用 getApp() ,使用 this 就可以拿到 app 实例。
// 通过 getApp() 获取实例之后,不要私自调用生命周期函数。
Page() // 注册小程序中的一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

getCurrentPages() // 获取当前页面栈。数组中第一个元素为首页,最后一个元素为当前页面。
// 注意:
// 不要尝试修改页面栈,会导致路由以及页面状态错误。
// 不要在 App.onLaunch 的时候调用 getCurrentPages(),此时 page 还没有生成。

除此之外,微信小程序还提供很多核心api,所有的api都通过wx对象来调用。

  1. 支持CommonJS规范:小程序的js是支持CommonJS规范的,也就是说可以使用import导入成员,通过export导出成员。
  2. ES6 转 ES5:在 0.10.101000 以及之后版本的开发工具中,会默认使用 babel 将开发者 ES6 语法代码转换为三端都能很好支持的 ES5 的代码,帮助开发者解决环境不同所带来的开发问题。

需要注意的是:为了提高代码质量,在开启 ES6 转换功能的情况下,默认启用 javasctipt 严格模式,请参考 "use strict"

3 - 小程序的界面层

1. 数据绑定

小程序的数据绑定和vue的类似,也是双大括号(因为双大括号像个小胡子,所以这种叫mustache语法),只不过vue的data是个方法,然后返回一个对象,小程序的data是个对象,WXML 中的动态数据均来自对应 Page 的 data属性。

  1. 数据在哪(当前页面对象的data属性中)

index.js文件:

Page({
  // 为页面提供数据的
  // data就是界面和逻辑之间的桥梁
  data: {
    message: 'Hello world',
    person: {
      name: 'zhangsan',
      age: 18
    },
    viewClassName: 'hello',
    todos: [
      { name: 'JavaScript', completed: false },
      { name: 'HTML', completed: true },
      { name: 'CSS', completed: false }
    ],
    item: 'hahaha'
  }
})
  1. 绑定到哪里去(想绑定到哪就在那里用mustache语法输出)

mustache语法可以用在:innerHTML中(类似)、元素的属性值上,如下:

index.wxml文件:

<!-- 这种{{}}的语法叫做mustache -->

<!-- 用在innerHTML中 -->
<text>{{ message }}</text>
<text>{{ person.name }}</text>

<!-- 用在元素的属性值上 -->
<view class="world {{ viewClassName }}"></view>

index.wxss文件:

.hello {
  width: 100px;
  height: 100px;
  background-color: pink;
}
  1. 可以直接使用字面量和简单的逻辑运算符
<text> {{ 'hello' }} </text>
<text> {{ 111 }} </text>
<text> {{ 111 + 999 }} </text>
<text>{{ 100 > 50 ? '你对了' : '你错了' }}</text>
  1. 当语法解析误解了true/false,可以使用{{}}解决
<checkbox checked="{{ false }}"></checkbox>

效果图如下:

2. 列表渲染

  <!--
      基本的循环 wx:for
      1. 明确页面结构中的循环体
      2. 删除多余的重复内容,只保留一个
      3. 在剩下的这个上加上wx:for属性,属性值等于要遍历的数据源,数据源必须是一个数组
      4. 在这个标签(循环体)内部使用item代表当前被遍历的元素,使用index代表当前被遍历的元素的序号
      给被遍历到的对象定义名称 wx:for-item
      给遍历的下标(索引)定义名称 wx:for-index
   -->
    <view wx:for="{{ todos }}" wx:for-item="aaa" wx:for-index="i">
      <text>{{ i }}</text>
      <checkbox checked="{{ aaa.completed }}"></checkbox>
      <text>{{ aaa.name }}</text>
      <!-- 如果全局属性中有item这种关键词, 可以使用wx:for-item去给当前遍历数据起名字 -->
      <text>{{ item }}</text>
    </view>
 

wx:for是可以嵌套的,如下打印99乘法表:

<!--
  循环的嵌套
-->
<view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="i">
  <view wx:for="{{[1, 2, 3, 4, 5, 6, 7, 8, 9]}}" wx:for-item="j">
  <!-- wx:if 是用来根据一个bool值决定显示或隐藏 -->
    <view wx:if="{{i <= j}}">
      {{i}} * {{j}} = {{i * j}}
    </view>
  </view>
</view>

效果图:

3. 关于事件

① 事件处理

在wxml文件中写一个按钮,使用bindtap绑定单击事件。

注意:bindtap不单单能给按钮添加点击事件,bindtap可以给任何组件添加点击事件。

<!-- 就是通过给组件添加一个"bind+事件名"的属性,属性的值指向一个定义在当前页面对象中JS方法 -->
<button bindtap="buttonTapHandle">点我22</button>

在js文件的page方法里面,定义buttonTapHandle处理函数:

Page({
  buttonTapHandle(e) {
    console.log(123)
    // console.dir() 将一个对象以树状形式打印到控制台
    console.dir(e)
  }
})

// 点击按钮打印:
// 123
// >object 

在page中定义处理函数,也可以使用下面这种方式。区别就是上面那种是新的写法,下面这种是旧的写法。

buttonTapHandle: function (e) {
  console.log(123)
  // console.dir() 将一个对象以树状形式打印到控制台
  console.dir(e)
}
② 事件冒泡

事件冒泡就是子元素的事件会传递到父元素上,catch+事件名是阻止冒泡并且绑定事件。

<!-- 事件冒泡 -->
<view bindtap="outterHandle" style="width:200px; height:200px; background-color: red">
	<view catchtap="innerHandle" style="width:100px; height:100px; background-color:blue">
  </view>
</view>
<!-- 如果没阻止事件冒泡,点击子元素会触发子元素的事件和父元素的事件 -->
<!-- 如果阻止事件冒泡,点击子元素会触发子元素的事件,点击父元素会父元素的事件 -->
③ 事件传参

有时候我们会把一个事件处理函数绑定在多个控件上,这样我们在调用事件处理函数的时候就需要传递参数用来区分是哪个控件。

在html中我们是这样做的:

<input type="button" onclick="clickHandle(12)" data-id=""/>

但是在小程序开发中如果按照类似的这样写是不行的,因为小程序会把(12)也当成函数名。

小程序中我们使用data-参数名="参数值"传递参数,然后在事件处理函数中通过e.target.dataset获取传递的参数,如下:

<!-- 事件传参 -->
<button bindtap="tap2Handle" data-name="张三" data-age="13">点我</button>
<button bindtap="tap2Handle" data-hello-world="张三">点我</button> 
Page({
  tap2Handle: function (e) {
    // e.target 拿到的就是点击的元素
    // dataset指的是元素上所有以data-开头的属性集合
    console.dir(e.target.dataset) 
    // console.log(this) // 事件处理函数中的this指向的还是页面对象!!!跟跟HTML不一样
    // 如果e.target.dataset上没有,那就在e.currentTarget.dataset上
  }
})

点击按钮,打印结果如下:

④ 补充:e.target和e.currentTarget的区别

target:是触发事件的源组件(就是你点击的那个组件) currentTarget:是事件绑定的当前组件(就是事件绑定的那个组件

4. 单向数据流

小程序不像Vue有双向数据绑定,小程序只有单向数据流,要么是从逻辑层通过数据绑定将数据显示在界面上,要么是从界面层通过事件将数据传递给逻辑层。

<view class="container">
  <!-- bindinput 绑定输入的事件,用户输入时会触发 -->
  <input value="{{ message }}" bindinput="inputHandle"/>
  <text>{{ message }}</text>
</view>
Page({
    data: {
        message: 'initial'
    },
    inputHandle: function (e) {
        // this.data.message = e.detail.value
        // console.log(this.data.message)
        // 这里的message虽然改变了,但是界面上的数据并没有变化,这是因为小程序的数据绑定是一次的过程,绑定完成之后就没有联系了,如果想要数据绑定之后,数据改变页面上的内容也发生改变需要调用setData来通知框架数据改变了
      	this.setData({
            message: e.detail.value
        })
        console.log(this.data)
        // this.setData 是用来改变data中的数据 
        // 他与直接赋值的区别在于setData可以通知界面做出变化
        // 直接赋值没有办法实现这一点
    }
})

结果如下:

5. 案例:登录界面

方式一:一般方式

代码如下,可根据注释步骤查看代码。

<view class="container">
  <view class="header">
    <image src="../../images/sign.png" mode="aspectFit"/>
  </view>
  <view class="inputs">
    <!-- 2. 通过 {{ }} 将数据绑定到特定的元素上 -->
    <!-- 3. bindinput 监听输入事件的改变 -->
    <input class="username" placeholder="请输入用户名" value="{{ username }}" bindinput="usernameChangeHandle"/>
    <input class="password" type="password" placeholder="请输入密码" value="{{ password }}" bindinput="passwordChangeHandle"/>
  </view>
  <view class="buttons">
    <button type="primary" bindtap="loginHandle">登陆</button>
    <button type="default">注册</button>
  </view>
</view>
Page({
  data: {
    // 1. 准备数据
    username: 'admin',
    password: '123'
  },
  // 4. 通过setData方法将输入的新值同步到data中
  usernameChangeHandle: function (e) {
    // this.data.username = e.detail.value 不要用这种方式,因为界面层无法得知
    this.setData({
      username: e.detail.value
    })
  },
  passwordChangeHandle: function (e) {
    // this.data.password = e.detail.value 不要用这种方式,因为界面层无法得知
    this.setData({
      password: e.detail.value
    })
  },
  // 5. 用于处理登录按钮点击的事件
  loginHandle: function () {
    // TODO: 完成逻辑
    // ① 先需要知道用户输入了什么
    console.log(this.data)
    // ② 根据用户输入的值判断
    // ③ 根据判断的结果做出响应
  }
})

上面的代码,usernameChangeHandlepasswordChangeHandle里面的逻辑基本相似,我们把这两个函数抽离到一个函数。

实现方式比较简单,就是将input添加一个data-属性名="属性值",然后在事件处理函数中,通过e.target.dataset['prop']拿到设置的属性值,根据属性值即可知道是哪个输入框了。

<input 
  class="username" 
  placeholder="请输入用户名" 
  value="{{ username }}" 
  <!-- 2. 绑定同一个事件函数 -->
  bindinput="inputChangeHandle" 
  <!-- 1. 设置data-属性 -->
  data-prop="username"/>
<input 
  class="password" 
  type="password" 
  placeholder="请输入密码" 
  value="{{ password }}" 
  bindinput="inputChangeHandle" 
  data-prop="password"/>
inputChangeHandle: function (e) {
  // 3. 通过e.target.dataset获取prop的值
  var prop = e.target.dataset['prop']
  var changed = {}
  changed[prop] = e.detail.value
  // 4. 将新值通过setData设置到逻辑层
  this.setData(changed)
}
方式二:表单实现

添加一个form表单,然后给form表单添加一个submit事件,并且把input输入框添加一个name属性。

代码如下,可根据注释步骤查看代码。

<!-- 1. 外面包裹一个form表单,并且添加submit事件 -->
<form bindsubmit="loginHandle">
  <view class="container">
    <view class="header">
      <image src="../../images/sign.png" mode="aspectFit"/>
    </view>
    <view class="inputs">
      <input 
        class="username" 
        <!-- 2. input添加name属性用于区分是哪个控件 -->
        name="username"
        placeholder="请输入用户名" 
        value="{{ username }}"/>
      <input 
        class="password" 
        type="password" 
        name="password"
        placeholder="请输入密码" 
        value="{{ password }}"/>
    </view>
    <view class="buttons">
      <!-- 3. 按钮添加form-type="submit",这样点击按钮的时候就会触发表单提交事件 -->
      <button type="primary" form-type="submit">登陆</button>
      <button type="default">注册</button>
    </view>
  </view>
</form>
Page({
  data: {
    username: 'admin',
    password: '123'
  },
  // 4. 用于处理表单提交事件
  loginHandle: function (e) {
    console.log(e) // 获取提交事件对象
    console.log(e.detail.value) // 获取提交的表单值 
    // 打印:{ username: "admin2222", password: "123" }
  }
})

6. 条件渲染

① wx:if

在框架中,使用 wx:if="" 来判断是否需要渲染该代码块:

<view wx:if="{{condition}}"> True </view>

也可以用 wx:elifwx:else 来添加一个 else 块:

<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>

因为 wx:if 是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block/> 标签将多个组件包装起来,并在上边使用 wx:if 控制属性。

<block wx:if="{{true}}">
  <view> view1 </view>
  <view> view2 </view>
</block>

注意: <block/> 并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。

② wx:if vs hidden

因为 wx:if 之中的模板也可能包含数据绑定,所以当 wx:if 的条件值切换时,框架有一个局部渲染的过程,因为它会确保条件块在切换时销毁或重新渲染。同时 wx:if 也是惰性的,如果在初始渲染条件为 false,框架什么也不做,在条件第一次变成真的时候才开始局部渲染。

相比之下,hidden 就简单的多,组件始终会被渲染,只是简单的控制显示与隐藏。

一般来说,wx:if 有更高的切换消耗而 hidden 有更高的初始渲染消耗。因此,如果需要频繁切换的情景下,用 hidden 更好,如果在运行时条件不大可能改变则 wx:if 较好。

7. WXSS vs CSS

WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式,决定 WXML 的组件应该怎么显示。

为了适应广大的前端开发者,WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改,与 CSS 相比,WXSS 扩展的特性如下:

① 尺寸单位

rpx(responsive pixel)可以根据屏幕宽度进行自适应,规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素

开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。如果不使用rpx,使用375px在iPhone6上面也能占满整个宽度,但是如果换到更大宽度的手机就不能占满宽度了,这样就比较麻烦,所以我们使用750rpx表示占满整个宽度,这样所有的设备都会占满整个宽度了。

③ 全局样式与局部样式

定义在 app.wxss 中的样式为全局样式,作用于每一个页面,在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。

小程序的每一个界面都在<page></page>标签里面,可以通过查看Wxml结构得知,如下:

我们不能通过给内置标签添加类名的方式修改<page></page>的样式,但是可以通过标签选择器的方式给它添加样式,如下:

page {
  background-color: #f0f0f0;
}

四. 小程序UI开发

1 - 组件

框架为开发者提供了一系列基础组件,开发者可以通过组合这些基础组件进行快速开发。详细介绍请参考组件文档

什么是组件:

  • 组件是视图层的基本组成单元
  • 组件自带一些功能与微信风格一致的样式
  • 一个组件通常包括 开始标签结束标签属性 用来修饰这个组件,内容 在两个标签之内
<tagname property="value">
	Content goes here ...
</tagname>

所有组件与属性都是小写,以连字符-连接,并且必须有开始标签和结束标签,这是因为微信的UI使用的是严格的XML语法。

2 - 公共属性

所有组件都有以下属性:

属性名类型描述注解
idString组件的唯一标示保持整个页面唯一
classString组件的样式类在对应的 WXSS 中定义的样式类
styleString组件的内联样式可以动态设置的内联样式
hiddenBoolean组件是否显示所有组件默认显示
data-*Any自定义属性组件上触发的事件时,会发送给事件处理函数
bind* / catch*EventHandler组件的事件详见事件

3 - 基础组件

1. icon

图标。 组件属性的长度单位默认为px,2.4.0起支持传入rpx单位。 type用于定义图标类型,只能是规定范围的类型,除了这些内置图标,其他图标必须通过图片方式实现。

属性类型默认值必填说明最低版本
typestringicon的类型,有效值:success, success_no_circle, info, warn, waiting, cancel, download, search, clear1.0.0
sizenumber/string23icon的大小1.0.0
colorstringicon的颜色,同css的color1.0.0
<icon type="success_no_circle"></icon>
<!-- size 组件属性的长度单位默认为px,2.4.0起支持传入rpx单位 -->
<icon type="info" size="375rpx"></icon>
<!-- color 用于指定图标颜色 取值就是CSS颜色取值 -->
<icon type="info" size="60" color="red"></icon>

2. text

文本。 text类似于HTML中的p标签,但是p标签不能嵌套,text可以嵌套,text主要是为了可以很好的控制页面上的内容,text还支持换行。

<text>这是一
段<text>文本</text>内容</text>

这是一段没有被text包裹的文本(不推荐)

3. progress

进度条。 组件属性的长度单位默认为px,2.4.0起支持传入rpx单位。 percent设置进度条的百分比,show-info是用来控制是否显示具体数值的。进度条有动画效果。

<progress percent="20" show-info />
<progress percent="60" active />

更多组件请参考组件文档

4 - 常用组件

<!--index.wxml-->
<view class="container">
  <!-- type是用来控制按钮的类型 只有三种:primary default warn -->
  <button type="primary">这是一个按钮</button>
  <!-- plain 按钮是否镂空,背景色透明 -->
  <!-- loading:名称前是否带loading图标 -->
  <button type="warn" size="mini" plain loading>这是一个按钮</button> 
  <!--hover指的是按下,hover-class指的就是按下过后的作用Class -->
  <button hover-class="btn-active">hover class</button>

  <!-- bindchange:checkbox-group中选中项发生改变时触发change事件 -->
  <checkbox-group bindchange="checkboxChange">
    <label class="checkbox" wx:for="{{items}}">
      <checkbox value="{{item.value}}" checked="{{item.checked}}"/>{{item.name}}
    </label>
  </checkbox-group>

  <input class="input1" placeholder="请输入啥" placeholder-class="input-placeholder"/>
</view>
Page({
  data: {
    items: [
      {value: 'USA', name: '美国'},
      {value: 'CHN', name: '中国', checked: 'true'},
      {value: 'BRA', name: '巴西'},
      {value: 'JPN', name: '日本'},
      {value: 'ENG', name: '英国'},
      {value: 'TUR', name: '法国'},
    ]
  },
  checkboxChange: function(e) {
    console.log('checkbox发生change事件,携带value值为:', e.detail.value)
    // 打印: ["CHN", "BRA"]
  }
})

5 - 操作反馈组件

buttonClicked: function(e) {
  wx.showToast({
    title: '我是toast',
    duration: 8000
  })
  // wx.showLoading({
  //   title: '我是loading',
  // })
  wx.showActionSheet({
    itemList: ['我是第一列', '我是第二列'],
  })
  wx.showModal({
    cancelColor: 'cancelColor',
    title: '我标题',
    content: '我是信息'
  })
}

2016.10.28更新日志:移除组件:toast loading action-sheet modal,可使用更方便的交互反馈 API 替代。

6 - 界面间跳转

1. 基本跳转

界面跳转我们一般使用navigator,使用url指定跳转的界面。 点击go demo2 page就可以跳转到页面2,并且页面2左上角自动有一个返回按钮。

<navigator url="../demo2/demo2">go demo2 page</navigator>

navigator里面可以放任何东西,比如可以放一个图片,这样点击图片的时候也会跳转到页面2,如下:

<navigator url="../demo2/demo2">
	<image src="../../images/poster.jpg"></image>
</navigator>

2. 页面间传值

  1. 传递方:跳转链接上加问号参数

如下,点击小明,传递name=小明&age=18

<navigator url="../demo2/demo2?name=小明&age=18">小明</navigator>
  1. 接受方:通过onload 的第一个参数(对象)获取参数

在界面2的onLoad事件中,接收页面跳转所带来的参数。

onLoad:function(options){
  // 页面初始化
  // options为页面跳转所带来的参数
  console.log(options)
  // {name: "小明", age: "18"}
}

3. navigator的属性

属性类型默认值必填说明
open-typestringnavigateopen-type是跳转方式,默认是navigate,跳转后左上角有返回按钮。如果指定为redirect,跳转后左上角有home按钮。如果指定为switchTab,就可以通过导航的方式跳转到下面的tabbar里面的页面。
hover-classstringnavigator-hoverhover-class是点击时navigator的样式,默认是灰色的框框,也可以指定为其他样式,设置为none则是去掉默认的点击样式。

4. 编程方式跳转

① wx.navigateTo

保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。

// 点击按钮,触发tapHandle点击事件
<button type="primary" bindtap="tapHandle">跳转过去</button>

// 当我们点击按钮 系统会自动执行这里的代码
tapHandle: function () {
    // console.log(1111)
    wx.navigateTo({
      // 跳转并传递参数
      url: '../demo2/demo2?id=123'
    })
}
② wx.redirectTo

关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。

③ wx.navigateBack

关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。

// 点击按钮,触发backHandle点击事件
<button bindtap="backHandle">返回</button>

backHandle: function () {
  // 默认返回到上一页
  // wx.navigateBack()

  // 指定delta 就是返回到指定页面
  // delta 过大(超出历史记录)默认返回最开始的页面
  wx.navigateBack({
    delta: 100
  })
}

五. 小技巧

  1. 输入view.container,可以出现如下代码:
<view class="container"></view>
  1. 输入icon[type="clear"],可以出现如下代码:
<icon type="clear"></icon>
  1. 按住command + d,可以选中页面中所有相同的内容
  2. 如果双标签之间没有内容,可以删除双标签后面的一部分,然后加上闭合/变成单标签,比如:
<icon type="success"></icon>
可以变成:
<icon type="success"/>
  1. 如果批量添加的标签有序号,可以使用$代替,比如:
view.item*9>image[src="/assets/icons/grid-0$.png"]+text

创建的就是类名为item的9个view,每个view里面有一个image和一个text,并且imagesrc属性是"/assets/icons/grid-0$.png",最后一位$代表最后一位数从1开始往下数。

  1. ES5和ES6定义方法的区别

ES5定义方法:

backHandle: function () {}

ES6定义方法:

backHandle() {}

ES6中我们可以简化方法的定义,省略function。

六. TODOS案例

案例地址:github.com/iamkata/TOD…

  1. 搭建骨架 详情见todos.wxml文件
  2. 添加样式 详情见todos.wxss文件
  3. 填充数据 详情见todos.js文件
  4. 界面数据绑定 详情见todos.wxml文件
  5. 界面操作交互 详情见todos.wxmltodos.js文件

七. 本地生活项目

项目地址:github.com/iamkata/wea…

  1. 发送请求不再是Web那一套Ajax
  2. 微信小程序没有跨域的概念,因为微信小程序不是前端,微信小程序就相当于客户端
  3. 请求的地址必须在管理后台添加白名单
  4. 域名必须备案,服务端必须采用HTTPS

对于第3点的说明:

使用wx.request请求接口信息的时候,需要在如下界面配置服务器域名,否则会报错:xxx不在以下request合法域名列表中。我们可以暂时关闭这个校验,关闭方式为:微信开发者工具 - 详情 - 本地设置 - 打开:不校验合法域名、web-view(业务域名)、TLS版本以及HTTPS证书。