微信小程序开发入门
微信小程序
首先说下结构吧,看看小程序到底长什么样子
这是一个微信提供的自己的开发工具,相当于xcode吧,由此也可以看出腾讯的野心并不小啊,左边的就是编辑调试什么的,往右就是一个模拟器,你可以选择iPhone各种型号或者安卓各种型号,在往后这就是目录结构了。
先说一下小程序的代码结构吧,首先他的app service 至少由这三个文件组成,app.js,这个是脚本代码,App()函数就在这里面实现,可以监听处理小程序的生命周期函数,声明全局变量。app.json json文件这个一般都是对程序进行配置的,这里面一般都是放pages页面组成啊,还有window或者其他页面的样式 颜色等。app.wxss,这个就是一个style sheet,样式表,你如果不想在自己的pages中单独的声明一些样式,可以直接使用这里的。
然后除了系统提供的,我们要想开发小程序肯定要创建自己的页面,每个自己的页面都有四个文件index.js index.json index.wxml ,index.wxss。
那这些文件里到底都有些什么呢 ,下面看图:
index.wxss 就想成css吧,其实就是样式表 什么color marin padding width height 这些
这个就是index.json 没什么太大的作用 就是一些配置信息
这个就比较重要了 index.js 就是一些监听函数或者自定义函数 和page 的注册等
这个就是index.wxml 就相当于html 看这样子就觉得长得挺像,就负责页面具体长什么样子,由一些控件节点堆成的,里面绑定数据和函数
小程序并不是web view,不是H5的界面,是一种类似react-native 的用JS和类XML结构写的接近于原生的app
小程序的开发框架的目标是通过尽可能简单,高效的方式让开发者可以在微信中开发具有原生APP体验的服务
框架提供了自己的视图层描述语言wxml和wxss ,就类似于HTML 和CSS,以及基于JavaScript的逻辑层框架,并在视图层和逻辑层间提供了数据传输和事件系统,可以让开发者方便的聚焦于数据与逻辑之上。
框架的核心是一个响应的数据绑定,这点和native的MVC MVVM 和react-native的state,props等数据绑定响应绑定一样的,框架都是让数据与视图尽可能简单的保持同步,当数据发生改变时,只需要在逻辑层修改数据,视图层就会自动的响应更新。可以通过下面一个例子来看:
// this is our view
<view> Hello {{name}} </view> // 是不是感觉很像HTML的写法呢,别急下面的更像
<button bindtap=“changeName”>click me </button> 这其实就是一个按钮挂接一个function ,函数名称叫changeName,按钮的标题叫click me
// this is app service
var helloData = {
name:“world”
}
// page 是一个函数,注册一个页面,主要是当前页面的一些方法和数据绑定,接收一个object参数,指定页面的初始数据data,生命周期函数,事件处理函数,生命周期函数有onLoad 页面加载 ,onShow 页面显示,onReady 页面展示完成,onHide 页面隐藏,onUnload 页面卸载
Page({
data:helloData,
changeName:function(e){
this.setData({
name:”bob”
})
} })
app.js 小程序的脚本文件 可以在这个文件中处理小程序的生命周期函数,声明全局变量。调用API
app.json 是对整个小程序的全局配置,可以在这个文件中配置小程序是由哪些页面组成,配置小程序的窗口背景色,配置导航条的样式,配置默认标题,该文件不可添加任何注释
app.wxss 是小程序的公共样式表,我们可以在页面组件的class属性上直接使用app.wxss中声明的样式规则
每一个小程序页面都是由4个不同的后缀文件的组成如:index.js index.wxml index.json index.wxss,微信小程序的每一个页面的【路径+页面名】(page/component/index)都要写在app.json文件中的pages里面,且pages中的第一个页面是小程序的首页
作用域:在JS文件中声明的变量和函数只在该文件中有效,不同文件中可以声明相同名字的变量和函数,不会相互影响
通过全局函数 getApp()可以获取全局的应用实例,如果需要全局的数据可以在app.js的APP()函数中设置如:
App({
globalData:1
}) // app.js
var app = getApp()
app.globalData ++ // a.js
模块化
将一些公共的代码抽离成一个单独的js 文件作为一个模块,模块只有通过module.exports 或者exports才能对外暴露接口,这点很js
// common .js
function sayHello(name){
console.log(‘hello$(name)’)
}
module.exports.sayHello = sayHello
在需要使用这些模块的文件中,使用require(path)将公共代码引入
var common = require(‘common.js’)
Page({
helloCommon:function(){
common.sayHello(‘hello’)
}
})
App() 函数用来注册一个小程序,只能在app.js中注册,且只能注册一次
在App()函数中不要调用getApp(),使用this即可拿到实例
不要在onLaunch的时候调用getCurrentPage()这时候page还没有生成
通过getApp()获取到小程序的实例后不要私自调用生命周期函数
// app.js
App({
onLaunch: function() {
// Do something initial when launch.
},
onShow: function() {
// Do something when show.
},
onHide: function() {
// Do something when hide.
},
onError: function(msg) {
console.log(msg)
},
globalData: \’I am global data\’
})
// other.js
var appInstance = getApp()
console.log(appInstance.globalData)
Page
Page() 函数用来注册一个页面,接受一个object参数,其指定页面的初始数据,生命周期函数,事件处理函数
通常在一个页面的index.js 下
Page({
data: {
text: “This is page data.”
},
onLoad: function(options) {
// Do some initialize when page load.
},
onReady: function() {
// Do something when page ready.
},
onShow: function() {
// Do something when page show.
},
onHide: function() {
// Do something when page hide.
},
onUnload: function() {
// Do something when page close.
},
onPullDownRefresh: function() {
// Do something when pull down.
},
onReachBottom: function() {
// Do something when page reach bottom.
},
onShareAppMessage: function () {
// return custom share data when user share.
},
// Event handler.
viewTap: function() {
this.setData({
text: \’Set some data for updating view.\’
})
},
customData: {
hi: \’MINA\’
}
})
初始化数据
初始化数据将作为页面的第一次渲染,data将会以json 的形式由逻辑层传至渲染层,渲染层可以通过wxml对数据进行绑定
<view>{{text}}</view>
<view>{{array[0].msg}}</view>
Page({
data: {
text: \’init data\’,
array: [{msg: \’1\’}, {msg: \’2\’}]
}
})
setData 函数用于将数据从逻辑层发送到视图层,同时改变对应的this.data 的值
直接修改this.data的值无效,这点有点类似this.setState,无法改变页面的状态,还会造成数据的不一致
index.wxml 是页面的结构文件
<view class=”container”>
<view bindtap=”bindViewTap” class=”userinfo”>
<image class=”userinfo-avatar” src=”{{userInfo.avatarUrl}}” background-size=”cover”></image>
<text class=”userinfo-nickname”>{{userInfo.nickName}}</text>
</view>
<view class=”usermotto”>
<text class=”user-motto”>{{motto}}</text>
</view>
</view>
本例中使用了<view/> <image/><text/>来搭建页面结构,绑定数据和交互处理函数
index.js 是页面的脚本文件,在这个文件中可以监听并处理页面的生命周期函数,获取小程序实例,声明并处理数据,响应页面交互事件等
//获取应用实例
var app = getApp()
Page({
data: {
motto: \’Hello World\’,
userInfo: {}
},
//事件处理函数
bindViewTap: function() {
wx.navigateTo({
url: \’../logs/logs\’
})
},
onLoad: function () {
console.log(\’onLoad\’)
var that = this
//调用应用实例的方法获取全局数据
app.getUserInfo(function(userInfo){
//更新数据
that.setData({
userInfo:userInfo
})
})
}
})
index.wxss 是页面的样式表 采用的是flex布局
.userinfo {
display: flex;
flex-direction: column;
align-items: center;
}
.userinfo-avatar {
width: 128rpx;
height: 128rpx;
margin: 20rpx;
border-radius: 50%;
}
.userinfo-nickname {
color: #aaa;
}
.usermotto {
margin-top: 200px;
}
当页面有自己的样式表时,会覆盖app.wxss中的样式,如果不指定页面的样式表,可以在页面的结构文件中直接使用app.wxss中指定的样式规则
index.json 也是非必要的,当页面有自己的配置文件时会覆盖在app.json中的相同的配置项,如果没有指定的页面配置文件,则在该页面直接使用app.json 中的默认配置
逻辑层
小程序的逻辑层是由JS编写,由于并不是运行在浏览器上,所以在web上的一些能力都无法使用,如document,window等
增加App Page函数,进行程序和页面的注册
增加getApp 和 getCurrentPages方法,分别用来获取当前的APP实例和当前的页面栈
每个页面有独立的作用域,并提供模块化能力
开发者写的所有代码最终会打包成一份javaScript代码,在小程序启动的时候运行,直到小程序销毁
数据绑定
WXML中的动态数据均来自对应page的data
简单绑定 用双大括号将变量括起来 如:<view> {{message}} </view>
Page({
data:{
message:’hello world’
}
})
组件属性 需要在双引号之内
<view id=“item -{{id}}”></view>
Page({
data:{id:0} })
控制属性 需要在双引号之内
<view wx:if=“{{condition}}”> </view>
Page({ data:{condition:true} })
关键字需要写在双引号之间 <checkbox checked=“{{false}}” </checkbox>
运算 可在{{}}内进行简单的运算 三元运算 算数运算 逻辑判断 字符串运算 数据路径计算 数组 对象
条件渲染
在框架中可以用 wx:if=“{condition}” 来判断是否需要渲染该代码块
列表渲染
在组件中使用wx:for 控制属性绑定一个数组,即可使用数组中的各项的数据重复渲染该组件
默认数组的当前项的下标变量名默认为index,数组当前项的变量名默认为item
<view wx:for=“{{}array}”>
{{index}}:{{item.message}}
</view>
Page({
data:{
array:[{
message:’foo’,
}, {
message:’bar’,
}]
}
})
使用wx:for-item可以指定数组当前元素的变量名 使用wx:for-index 可以指定数组当前下标的变量名
模板 template
可以在模板中定义代码片段,然后在不同的地方调用
定义模板 使用name 属性作为模板的名字
<template name=“”msgItem>
<view>
<text>{{index}}:{{msg }}</text>
<text>Time:{{time}}</text>
</view>
</template>
使用is属性,声明需要使用的模板,然后将模板的data传入
<template is=“msgItem” data=“{{…item}}”/>
Page({
data:{
item:{
index:0,
msg:’this is a template’,
time:’2016-06-06’
}
}
})
is 属性可以使用双引号语法来动态决定具体需要渲染哪个模板
<template name=“old”>
<view>odd</view>
</template>
<template name=“even”>
<view>even</view>
</template>
<block wx:for=“{{[1,2,3,4,5]}}”>
<remplate is=“{{item%2 ==0 ? ‘even’ : ‘odd’}}”>
</block>
模板拥有自己的作用域,只能使用data传入的数据
事件
在组件上绑定一个事件处理函数,如bindtap,当用户点击该组件的时候会在该页面对应的page中找到对应的事件处理函数
<view id =“tapTest” data-hi=“wechat” bindtap=“tapName”>click me </view>
在相应的page中定义事件处理函数参数是event
Page({
tapName:function(event){
consol.log(event)
}
})