微信小程序(解密构架)

最近小程序被炒的火热。很多人应该已经尝试了微信小程序,我也抱着学习的态度,准备研究一下。研究之后感觉还可以,如果有h5和angular(或vue)基础的话,入门还是比较容易的。

小程序是一种不需要下载安装即可使用的应用,他实现了应用触手可及的梦想,用户扫一扫或者搜一下就可以打开应用。也提现了“用完即走”的里面,用户不用关心安装了太多了应用。应用将无处不在,随即使用,但又无需安装卸载。

小程序的特点

1.随后可得 用完即走
2.拥有离线能力
3.一次开发,多端兼容
4.操作体验好

安装环境、

首先需要先安装发开环境。
下载地址https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=20161122
选择对应的系统(win32,win64,mac)安装

小程序框架解密

下载环境,我们只需要默认安装即可,然后用手机微信扫描环境安装成功之后弹出的二维码,新建一个项目,(没有AppID可以不填,只是有些功能会受限)就能进入到微信小程序开发的安装环境。就是如图所示。

开发者工具.jpg

小程序基本架构解密

点击开发者工具左侧导航的“编辑”,我们可以看到这个项目,已经初始化并包含了一些简单的代码文件。最关键也是必不可少的,是 app.js、app.json、app.wxss 这三个。其中,.js后缀的是脚本文件,.json后缀的文件是配置文件,.wxss后缀的是样式表文件。微信小程序会读取这些文件,并生成小程序实例


小程序基本构架.png

app.json解析

app.json 是对整个小程序的全局配置。我们可以在这个文件中配置小程序是由哪些页面组成,配置小程序的窗口背景色,配置导航条样式,配置默认标题。注意该文件不可添加任何注释。


app.json.png

app.js解析

app.js是小程序的脚本代码。我们可以在这个文件中监听并处理小程序的生命周期函数、声明全局变量。

//app.js
App({
  onLaunch: function () {
    //调用API从本地缓存中获取数据
    var logs = wx.getStorageSync('logs') || []
    logs.unshift(Date.now())
    wx.setStorageSync('logs', logs)
  },
  getUserInfo:function(cb){
    var that = this
    if(this.globalData.userInfo){
      typeof cb == "function" && cb(this.globalData.userInfo)
    }else{
      //调用登录接口
      wx.login({
        success: function () {
          wx.getUserInfo({
            success: function (res) {
              that.globalData.userInfo = res.userInfo
              typeof cb == "function" && cb(that.globalData.userInfo)
            }
          })
        }
      })
    }
  },
  globalData:{
    userInfo:null
  }
})

app.wxss解析

app.wxss 是整个小程序的公共样式表。我们可以在页面组件的 class 属性上直接使用 app.wxss 中声明的样式规则。

/**app.wxss**/
.container {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: 200rpx 0;
  box-sizing: border-box;
}

创建页面

小程序中所有的页面都在Pages中,在新建项目的初始化代码中,有两个页面,一个是index,表示首页,一个是logs,表示日志页,我们可以用过新建来创建页面,但是一定要让这个页面的文件夹在Pages文件夹中,且这个页面的文件也要含有.wxml (表示页面结构的文件) .js(页面的 脚本文件) .wxss(页面的样式表)。

例如,下图新建了一个test页面,架构如图所示


1.jpg

解密框架

2.jpg

显示我们创建的页面(逻辑层)

刚才创建了一个text页面,那么如何让我们创建的页面显示在小程序中。(我们先简单在text中写点东西)
当我们新建了一个text文件时,首先需要在app.json文件的pages下配置页面。注意,页面的配置是有顺序的,此案例中我们把text配置在了最前面,那么此时启动小程序先看到的就是text页面

3.jpg

小程序的模块化(逻辑层)

文件作用域
在 JavaScript 文件中声明的变量和函数只在该文件中有效;不同的文件中可以声明相同名字的变量和函数,不会互相影响。
通过全局函数 getApp()可以获取全局的应用实例,如果需要全局的数据可以在 App()中设置
这里举例子使用官方文档中的例子

4.jpg

模块化

我们可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口。

需要注意的是:

exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造成未知的错误。所以我们更推荐开发者采用 module.exports 来暴露模块接口,除非你已经清晰知道这两者的关系。
小程序目前不支持直接引入 node_modules , 开发者需要使用到 node_modules 时候建议拷贝出相关的代码到小程序的目录中。

官方案例

5.jpg

数据绑定(视图层)

内容
WXML 中的动态数据均来自对应 Page 的 data。
数据绑定使用 {{ }}(双大括号)将变量包起来

<!--text.wxml-->
<view class="text">{{msg}}</view>
//text.js
Page({
    data:{
        msg:"通过数据绑定显示在页面上"
    }
})

在视图中的运行结果

6.jpg

组件属性

<!--text.wxml-->
<view id="item-{{id}}"> </view>
//text.js
Page({
  data: {
    id: 0
  }
})

属性控制

<!--text.wxml-->
<view wx:if="{{condition}}"> </view>
//text.js
Page({
  data: {
    condition: true
  }
})

布尔类型

<!--text.wxml-->
<checkbox checked="{{false}}"> </checkbox>

特别注意:不要直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值。

运算
可以在 {{}} 内进行简单的运算,比如三目运算,和算术运算

三目运算

<!--text.wxml-->
<view hidden="{{flag ? true : false}}"> Hidden </view>

算术运算

<!--text.wxml-->
<view> {{a + b}} + {{c}} + d </view>
//text.js
Page({
  data: {
    a: 1,
    b: 2,
    c: 3
  }
})

view中的内容为 3 + 3 + d

数据路径运算

<!--text.wxml-->
<view>{{object.key}} {{array[0]}}</view>
//text.js
Page({
  data: {
    object: {
      key: 'Hello '
    },
    array: ['MINA']
  }
})

组合

<!--text.wxml-->
<view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
//text.js
Page({
  data: {
    zero: 0
  }
})

对象

<!--text.wxml-->
<template is="objectCombine" data="{{foo, bar}}"></template>
//text.js
Page({
  data: {
    foo: 'my-foo',
    bar: 'my-bar'
  }
}

最终组合成的对象是 {foo: 'my-foo', bar:'my-bar'}。
注意:上述方式可以随意组合,但是如有存在变量名相同的情况,后边的会覆盖前面

条件渲染

wx:if

用wx:if来判断是否需要渲染这段代码,如果满足条件,即可渲染该段代码,类似于js中的if语句。

下面这段代码,如果condition为true,则渲染这段代码
<view wx:if="{{condition}}"> True </view>

wx:elif 和 wx:else
类似于js中的if-else语句

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

block wx:if
因为 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 较好。

列表循环渲染

wx:for
在组件上使用wx:for控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。

item代表list中的每一项

<!--text.wxml-->
<view wx:for="{{list}}">
    {{item.name}}-----{{item.singer}}
</view>
//text.js
Page({
    data:{
        list:[
            {name:"《说走就走》",singer:"周杰伦"},
            {name:"《倒带》",singer:"蔡依林"},
            {name:"《单车恋人》",singer:"后弦"},
            {name:"《给我一首歌的时间》",singer:"周杰伦"},
            {name:"《演员》",singer:"薛之谦"}
        ]
    }
})

运行结果

7.jpg

如果你想给页面加点样式,可以写在text.exss中
先给text.wxml添加一个class名称,比如叫abc ,然后用过class选择器在text.exss中书写样式

.abc{
    padding: 10px;
    margin-bottom: 10px;
    border-bottom: 1px solid #ccc;
}

此时页面效果(index表示数组的下标,下标是从0开始的,也可以更改默认的item的名称,如下图所示)

8.jpg

block wx:for
类似block wx:if,也可以将wx:for用在<block/>标签上,以渲染一个包含多节点的结构块

<block wx:for="{{[1, 2, 3]}}">
  <view> {{index}}: </view>
  <view> {{item}} </view>
</block>

wx:key
如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如 <input/> 中的输入内容,<switch/> 的选中状态),需要使用 wx:key 来指定列表中项目的唯一的标识符。

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

1.字符串,代表在 for 循环的 array 中 item 的某个 属性,该 属性 的值需要是列表中唯一的字符串或数字,且不能动态改变。

<!--text.wxml-->
<view class="abc" wx:key="{{name}}" wx:for="{{list}}" wx:for-item="newName">
   {{index+1}}. {{newName.name}}-----{{newName.singer}}
</view>

2.保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字,如:
当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

//text.js
Page({
    data:{
        array:[1,2,3,4,5,6,7,8]
    }
    
})
<view wx:for="{{array}}" wx:key="*this">
    {{item}}
</view>

模板

WXML提供模板(template),可以在模板中定义代码片段,然后在不同的地方调用。

定义模板

使用name属性,作为模板的名字。然后在<template/>内定义代码片段

<!--text.wxml-->
<template name="info">
    <view>
        <text>{{name}}</text>
        <text>{{singer}}</text>     
    </view>
</template>

使用模板

使用 is 属性,声明需要的使用的模板,然后将模板所需要的 data 传入

<!--text.wxml-->
<template name="info">
    <view>
        <text>{{name}}</text>
        <text>{{singer}}</text>     
    </view>
</template>

<template is="info" data="{{...item}}"></template>
//text.js
Page({
    data:{
        item:{name:"《说走就走》",singer:"周杰伦"}
    }  
})

也可以把模板单独放在一个文件里。需要时使用import或者include引用。

事件

什么事件?

事件是视图层到逻辑层的通讯方式。
事件可以将用户的行为反馈到逻辑层进行处理。
事件可以绑定在组件上,当达到触发事件,就会执行逻辑层中对应的事件处理函数。
事件对象可以携带额外信息,如 id, dataset, touches。

事件的使用方式

在数组中绑定一个事件处理函数
如bindtap,当用户点击该组件的时候会在该页面对应的Page中找到相应的事件处理函数。
<view id="tapTest" data-hi="WeChat" bindtap="tapName"> Click me! </view>

在相应的Page定义中写上相应的事件处理函数,参数是event

Page({
  tapName: function(event) {
    console.log(event)
  }
})

可以看到log出来的信息大致如下

{
"type":"tap",
"timeStamp":895,
"target": {
  "id": "tapTest",
  "dataset":  {
    "hi":"WeChat"
  }
},
"currentTarget":  {
  "id": "tapTest",
  "dataset": {
    "hi":"WeChat"
  }
},
"detail": {
  "x":53,
  "y":14
},
"touches":[{
  "identifier":0,
  "pageX":53,
  "pageY":14,
  "clientX":53,
  "clientY":14
}],
"changedTouches":[{
  "identifier":0,
  "pageX":53,
  "pageY":14,
  "clientX":53,
  "clientY":14
}]
}

在打印的结果中,我们可以看到事件对象,上述事件与js中的点击事件类似。

其他的事件,如果想学的读者老爷可以在官方文档中查看。

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

推荐阅读更多精彩内容