首页 微信小程序
文章
取消

微信小程序

实现原理

之前一直猜测微信小程序的实现是类似于 react-native 的技术,但事实上生成的并不是 native 的视图,而是 Html + CSS 的形式,最终呈现给用户就是 WebView。不过页面跳转还是基于 native 做的,拿 iOS 来说也就是一个 ViewController 包含了一个 WebView,然后通过 UINavigationController 来做页面的跳转,当然页面的切换用的是UITabBarController 。下图是京东购物的小程序的视图结构,可以看到导航栏用的是 UINavigationBar、内容的呈现用的是 WKWebView,还有底部的用于切换视图的控件 UITabBar。这样的 natvie + webview 的实现形式确实做到了让开发变得简单又有相对好的用户体验。

image

如何上手

小程序的开发可以说是比较简单的,首先要掌握 JS、CSS 和 Html 基本知识,其次是必须认真的看开发文档,还有就是官方的演示DEMO

显示一个列表

小程序没有类似于 iOS 上的 UITablView 的控件,想要显示列表必须在组件上用 wx:for来绑定一个数组然后渲染。在 .js 文件中定义一个数组 items

1
2
3
4
5
Page({
  data: {
    items:[],
  },
 })

请求接口获取数据并赋值给 items

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Page({
  data: {
    items:[],
  },
  onLoad: function() {
    var that = this;
    wx.request({
      url: Url,
      method: 'GET',
      success: function(res){
        that.setData({
          items: res.data.result,
        })
      },
    })
  },
 })

到这里数据就准备好了,接下来就是如何把数据显示到列表上,在 .wxml 中例如:

1
2
3
4
5
6
<view class="contain">
    <view wx:for="{{items}}" wx:key="{{item.id}}">
     <text>{{item.text}}</text>
     <text>{{index}}</text>
    </view>
</view>

需要注意的是:<view wx:for="{{items}}"> 这里的 view 事实上相当于 Cell,并不是包裹所有 Cell 的视图。item 是默认数组元素,index 是默认是索引,当然默认值是可以修改的,具体可以参考官方文档列表渲染wx:key 是用于标识 Cell 的唯一性的,可以提高列表的渲染性能。

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

点击Cell

一般情况下点击事件我们使用 bintap ,所以在 Cell 上绑定一个点击事件就是这么写:

1
2
3
4
5
6
<view class="contain">
    <view wx:for="{{items}}" wx:key="{{item.id}}" bindtap="cellAction">
     <text>{{item.text}}</text>
     <text>{{index}}</text>
    </view>
</view>

然后在 .js 实现相应的方法:

1
2
3
4
5
Page({
  cellAction(){
    console.log('action')
  }
})

这时候点击 Cell 就会在控制台打印出 action

页面跳转,传参

比如点击 Cell 要跳转到详情页 Detail(不要忘记在app.json中配置页面),cellAction 这么写:

1
2
3
4
5
6
7
Page({
  cellAction(){
    wx.navigateTo({
      url: './detail',
    })
  }
})

这个例子显然不够典型,因为没有传参,在小程序里页面之前的传参可以说有三种方式:

  1. 路由形式
  2. 全局变量
  3. 本地缓存
  • 路由形式:
1
2
3
4
5
6
7
8
9
10
Page({
  cellAction(object){
    var id = this.data.items[0].id;
    var text = this.data.items[0].text;
    console.log(id);
    wx.navigateTo({
      url: './detail?id=' + id + '&text=' + text,
    })
  },
})

比如最终 url = ./detail?id=1&text=测试,相当于传了两个参数过去,一个id 一个text,这时候在下一个页面获取数据:

1
2
3
4
5
6
7
8
9
// detail.js
Page({
  onLoad:function(options){
    var id = options.id;
    var text = options.text;
    console.log(id);
    console.log(text);
  },
})

注意:必须在onLoad才可以获取到参数。

  • 全局变量:

首先必须在app.js定义一个全局的变量,比如:globalData,然后定义一个parameter属性用于储存参数。

1
2
3
4
5
6
7
8
9
//app.js
App({
  onLaunch: function () {

  },
  globalData:{
    parameter:null
  }
})

然后设置参数,别忘记var app = getApp()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var app = getApp()

Page({
  cellAction(object){
    var id = this.data.items[0].id;
    var text = this.data.items[0].text;
    app.globalData.parameter = {
      "id" : id,
      "text" : text
    }
    wx.navigateTo({
      url: './detail',
    })
  },
})

获取参数,同样的需要获取app对象

1
2
3
4
5
6
7
8
9
10
// detail.js
var app = getApp()
Page({
  onLoad:function(options){
    var id = app.globalData.parameter.id;
    var text = app.globalData.parameter.text;
    console.log(id);
    console.log(text);
  },
})
  • 本地缓存:
1
2
3
4
5
6
7
8
9
cellAction(object){
    var id = this.data.items[0].id;
    var text = this.data.items[0].text;
    wx.setStorageSync("id",id);
    wx.setStorageSync("text",text);
    wx.navigateTo({
      url: './detail',
    })
  },

获取数据:

1
2
3
4
5
6
7
8
9
10
// detail.js
var app = getApp()
Page({
  onLoad:function(options){
    var id = wx.getStorageSync("id");
    var text = wx.getStorageSync("text");
    console.log(id);
    console.log(text);
  },
})

上面的例子传入都是数组中第一条元素的数据,那么如何传入对应的数据呢?我们需要用 dataset,官方文档对其定义:

在组件中可以定义数据,这些数据将会通过事件传递给 SERVICE。 书写方式: 以data-开头,多个单词由连字符-链接,不能有大写(大写会自动转成小写)如data-element-type,最终在 event.target.dataset 中会将连字符转成驼峰elementType

回到之前的例子,我们添加一个 data-index="{{index}}"

1
2
3
4
5
6
<view class="contain">
    <view wx:for="{{items}}" wx:key="{{item.id}}" bindtap="cellAction" data-index="{{index}}">
     <text>{{item.text}}</text>
     <text>{{index}}</text>
    </view>
</view>

之前说过了,index 是默认的索引对象,这时候在cellAction方法里就可以获取到 index 了:

1
2
3
4
5
6
7
8
9
10
Page({
  cellAction(object){
    var index = object.currentTarget.dataset.index;
    var id = this.data.items[index].id;
    var text = this.data.items[index].text;
    wx.navigateTo({
      url: './payFail?id=' + id + '&text=' + text,
    })
  },
})

获取方法

1
var index = object.currentTarget.dataset.index;

动态改变样式

简单粗暴的方式是通过条件渲染来显示不用的组件,这样从视觉上来讲也能达到改变样式的效果:

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

这显然不够优雅,官方文档中提到样式还可以通过 sytle 来控制,而且style可以接收动态样式。比如点击之后改变字体颜色:

定义一个字体颜色的变量

1
2
3
4
5
Page({
  data: {
    textColor: "red"
  },
 })

视图这边,当然要指定 textColor 用于显示字体颜色

1
<text bindtap="change" style="color: {{textColor}}" >12321</text>

点击执行change方法

1
2
3
4
5
6
change(){
    var color = "green"
    this.setData({
      textColor : color
    })
  },
本文由作者按照 CC BY 4.0 进行授权

新大陆:Texture

Framer Cheat Sheets: States