概述
简介
小程序是一种不需要下载的安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打开应用。也体现了“用完即走”的理念。用户不用关心是否安装太多应用的问题。应用无处不在,随时可用,但又无需安装卸载。——Allenzhang
特点:
- 速度快:无需下载安装,加载速度快于HTML5,微信登录,随时可用
- 无需适配:一次开发。多端兼容,免除了对各种手机型的适配
- 社交分享:支持直接或App分享给微信好友和群聊
- 出色体验:可以达到近乎原生App的操作体验和流畅度,在离线状态亦可使用
- 用完即走:通过扫码、长按、微信搜索、公众号、好友推荐等方式快速获取服务,用完即走
- 低门槛:已有公众号的组织可以快速注册、可快速生成门店小程序
开发流程
小程序的技术模型:
小程序的程序语言:
- 渲染层:WXML + WXSS(类似HTML + CSS)
- 逻辑层:JavaScript
- 配置:JSON
设计规范
- 友好:重点突出;流程明确
- 清晰:导航明确;减少等待;异常反馈
- 便捷:减少输入;避免误操作;操作流畅
- 统一:视觉统一;WeUI
运营规范
开发项目
小程序根目录下的 app.json
文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。
以下是一个包含了部分常用配置选项的 app.json
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| { "pages": [ "pages/index/index", "pages/logs/index" ], "window": { "navigationBarTitleText": "Demo" }, "tabBar": { "list": [{ "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/logs/index", "text": "日志" }] }, "networkTimeout": { "request": 10000, "downloadFile": 10000 }, "debug": true }
|
每一个小程序页面也可以使用同名 .json
文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json
的 window
中相同的配置项。
1 2 3 4 5 6 7
| { "navigationBarBackgroundColor": "#ffffff", "navigationBarTextStyle": "black", "navigationBarTitleText": "微信接口功能演示", "backgroundColor": "#eeeeee", "backgroundTextStyle": "light" }
|
图片标记:路径可以使用http或相对路径
作为容器元素
应用弹性盒子布局
- 传统方式布局
- 目标的实现属性赋值非常分散
- 严重依赖于页面结构与内容的实际大小
弹性盒子布局(统一,灵活)
盒子属性:
1 2 3 4
| display:flex; flex-direction:column; //垂直布局 justify-content:space-around; //自上而下放置时素材均匀分布 align-items:center; //元素在水平方向上居中显示
|
响应式长度单位rpx
让元素大小适配不同宽度屏幕
1 2 3 4 5
| .images { width:375rpx; height:375rpx; border-radius:50%; //圆形图片 }
|
导航链接
navigator组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <navigator style="display:inline" open-type="redirect" url="/pages/logs/logs" hover-class="nav-hover" class="nav-default"> 启动日志 </navigator>
//style="display:inline" 设置为内联元素 //open-type="redirect" 重定向,不可返回;默认为navigate .nav-hover { color:red; } //点击态
.nav-default { color:blue; } //显示态 //交换两者才可实现点击态
|
配置tabBar(底部标签栏)
app.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| "tabBar": { "list": [ { "text": "启动日志", "pagePath": "pages/logs/logs", "iconPath": "images/icons/person.jpg", "selectedIconPath": "images/icons/iperson.jpg" }, { "text": "主页", "pagePath": "pages/index/index", "iconPath": "images/icons/home.jpg", "selectedIconPath": "images/icons/ihome.jpg" } ], "color":"#000", "selectedColor":"#00f" },
|
此时navigate失效,需要修改。
1
| <navigator url="/pages/logs/logs" open-type="switchTab">启动日志</navigator>
|
配置全局导航栏样式
app.json
1 2 3 4 5 6 7
| "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "关于", "navigationBarTextStyle": "black", "enablePullDownRefresh": true },
|
数据绑定
weather.js
1 2 3 4 5 6 7 8 9
| Page({ data: { todayweather:{ city:"武汉", weather:"晴", temperature:"2℃" } } })
|
小程序的运行环境与基本架构
每个小程序都是运行在它的微信客户端上的,通过微信客户端给它提供的运行环境,小程序可以直接获取微信客户端的原生体验和原生能力。
条件渲染
在框架中,使用 wx:if=""
来判断是否需要渲染该代码块:
1
| <view wx:if="{{condition}}"> True </view>
|
也可以用 wx:elif
和 wx:else
来添加一个 else 块:
1 2 3
| <view wx:if="{{length > 5}}"> 1 </view> <view wx:elif="{{length > 2}}"> 2 </view> <view wx:else> 3 </view>
|
因为 wx:if
是一个控制属性,需要将它添加到一个标签上。如果要一次性判断多个组件标签,可以使用一个 <block/>
标签将多个组件包装起来,并在上边使用 wx:if
控制属性。
1 2 3 4
| <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
较好。
列表渲染
swiper组件
幻灯片轮播展示
页面的生命周期函数
<swiper></swiper>
添加属性
1 2
| current="{{ array.length - 1 }}" //切换到最后一张幻灯片(有缺陷)
|
js文件
1 2 3 4 5 6 7 8 9 10
| current="{{ currentIndex }}"
//初始化数据 //生命周期函数 onload:function(options) { this.setData({ currentIndex:this.data.array.length - 1 }) } //还包括其他的生命周期函数
|
更新数据
1 2 3 4 5 6 7 8 9 10 11
| <button bindtap="f0">按钮<button>
//更新数据不能直接赋值 f0:function(event){ console.log(this.data.count) //读取 this.setData({ count:this.data.count + 1 }) }
//this.serData可以动态设置变量
|
事件机制
1 2 3
| <button bindtap="f0">按钮<button> //会向上冒泡传递,父元素函数会被调用
<button catchtap="f1">按钮<button> //不会向上冒泡传递,父元素函数不会被调用
|
组件自定义数据属性
1 2 3 4 5 6 7 8 9 10 11
| f1:function(event){ wx.navigateTo({ url:'/pages/index/index' }) } //点击页面相同
f1:function(event){ wx.navigateTo({ url:'/pages/index/index?id=77' }) } //点击页面相同
|
动态导航栏
index.js
1 2 3 4 5
| onShareAppMessage: function(){ return { title:"向你推荐" + this.data.movie.title } }
|
组件化开发
自定义组件item.js
item.json
将组件属性设置true
item.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| Component({ options: { addGlobalClass: true, pureDataPattern: /^_/, multipleSlots: true }, properties: { vtabs: {type: Array, value: []}, }, data: { currentView: 0, }, observers: { activeTab: function(activeTab) { this.scrollTabBar(activeTab); } }, relations: { '../vtabs-content/index': { type: 'child', linked: function(target) { this.calcVtabsCotentHeight(target); }, unlinked: function(target) { delete this.data._contentHeight[target.data.tabIndex]; } } }, lifetimes: { created: function() { }, attached: function() { }, detached: function() { }, }, methods: { calcVtabsCotentHeight(target) {} } });
|