框架就是开发作者(个人或团队)约定好的一种规则,如果要使用框架做开发,遵循框架约定好的规则或方式去组建文件和书写业务逻辑代码
框架的主要作用:就是具备有基础的结构,便于他人在这个框架的基础之上进行快速开发,解放开发者的双手,无需从0开始
整个小程序框架系统分为两部分:逻辑层(App Service)
和 视图层(View)
。
小程序提供了自己的视图层描述语言WXML
和 WXSS
,以及基于 JavaScript
的逻辑层框架,并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑。
页面管理 框架 管理了整个小程序的页面路由,可以做到页面间的无缝切换,并给以页面完整的 生命周期。开发者需要做的只是将页面的数据、方法、生命周期函数注册到 框架 中,其他的一切复杂的操作都交由 框架 处理。
基础组件 框架 提供了一套基础的组件,这些组件自带微信风格的样式以及特殊的逻辑,开发者可以通过组合基础组件,创建出强大的微信小程序 。
<navigator></navigator>
<map></map>
<button></button>
......
场景值用来描述用户进入小程序的路径。完整场景值的含义请查看场景值列表。
由于Android系统限制,目前还无法获取到按 Home 键退出到桌面,然后从桌面再次进小程序的场景值,对于这种情况,会保留上一次的场景值。
开发者可以通过下列方式获取场景值,可以在 App
的 onLaunch
和 onShow
或 wx.getLaunchOptionsSync
中获取上述场景值。
部分场景值下还可以获取来源应用、公众号或小程序的appId。获取方式请参考对应API的参考文档。
小程序开发框架的逻辑层使用 JavaScript
引擎为小程序提供开发者 JavaScript
代码的运行环境以及微信小程序的特有功能。
逻辑层将数据进行处理后发送给视图层,同时接受视图层的事件反馈。
开发者写的所有代码最终将会打包成一份 JavaScript
文件,并在小程序启动的时候运行,直到小程序销毁。这一行为类似ServiceWorker
,所以逻辑层也称之为App Service
。
在 JavaScript 的基础上,我们增加了一些功能,以方便小程序的开发:
注意:小程序框架的逻辑层并非运行在浏览器中,因此 JavaScript 在 web 中一些能力都无法使用,如 window,document 等。
所谓的生命周期就是将一个过程划分成很多个阶段,然后在某一个阶段完成过后自动的发送一个信号,通知一下程序当前执行到哪个位置。
// app.js
App({
onLaunch(options) {
// Do something initial when launch.
},
onShow(options) {
// Do something when show.
},
onHide() {
// Do something when hide.
},
onError(msg) {
console.log(msg)
},
globalData: 'I am global data'
})
整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getAp
p 方法获取到全局唯一的 App
实例,获取App上的数据或调用开发者注册在 App 上的函数
// xxx.js
const appInstance = getApp()
console.log(appInstance.globalData) // I am global data
对于小程序中的每个页面,都需要在页面对应的 js 文件中调用 Page 方法注册页面示例,指定页面的初始数据、生命周期回调、事件处理函数等。
详细的参数含义和使用请参考 Page 参考文档 。
// index.js
Page({
data: {
text: 'This is page data.'
},
onLoad(options) {
// Do some initialize when page load.
},
onReady() {
// Do something when page ready.
},
onShow() {
// Do something when page show.
},
onHide() {
// Do something when page hide.
},
onUnload() {
// Do something when page close.
},
onPullDownRefresh() {
// Do something when pull down.
},
onReachBottom() {
// Do something when page reach bottom.
},
onShareAppMessage() {
// return custom share data when user share.
},
onPageScroll() {
// Do something when page scroll
},
onResize() {
// Do something when page resize
},
onTabItemTap(item) {
console.log(item.index)
console.log(item.pagePath)
console.log(item.text)
},
// Event handler.
viewTap() {
this.setData({
text: 'Set some data for updating view.'
}, function () {
// this is setData callback
})
},
customData: {
hi: 'MINA'
}
})
框架的视图层由 WXML 与 WXSS 编写,由组件来进行展示。
将逻辑层的数据反应成视图,同时将视图层的事件发送给逻辑层。
WXML(WeiXin Markup language) 用于描述页面的结构。
WXS(WeiXin Script) 是小程序的一套脚本语言,结合 WXML,可以构建出页面的结构。
WXSS(WeiXin Style Sheet) 用于描述页面的样式。
组件(Component)是视图的基本组成单元。
#####
WXML(WeiXin Markup Language)是框架设计的一套标签语言,用来描述小程序页面的结构。
数据绑定使用 Mustache 语法(双大括号)将变量包起来,可以作用于组件中
<!--page.wxml-->
<view>{{ message }}</view>
// page.js
Page({
data: {
message: 'Hello MINA!'
}
})
true:boolean 类型的 true,代表真值。 false: boolean 类型的 false,代表假值。
<checkbox checked="{{false}}"></checkbox>
特别注意:不要直接写 checked="false",其计算结果是一个字符串,转成 boolean 类型后代表真值。
可以在 {{}} 内进行简单的运算,支持的有如下几种方式:
<view hidden="{{flag ? true : false}}">Hidden</view>
// page.js
Page({
data: {
flag: true
}
})
<view>{{num1 + num2}} + {{num3}} + d</view>
// page.js
Page({
data: {
num1: 12,
num2:18,
num3:10
}
})
输出内容:
3 + 3 + d
wx:for
在组件上使用 wx:for 控制属性绑定一个数组,即可使用数组中各项的数据重复渲染该组件。
默认数组的当前项的下标变量名默认为 index
,数组当前项的变量名默认为 item
<view wx:for="{{array}}">
{{index}}: {{item.message}}
</view>
Page({
data: {
array: [{
id: '1',
name:"张三",
}, {
id: '2',
name:"李四",
}]
}
})
可以使用 wx:for-item 可以指定数组当前元素的变量名
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
</view>
可以使用 wx:for-index 可以指定数组当前下标的变量名:
<view wx:for="{{array}}" wx:for-index="idx" wx:for-item="itemName">
{{idx}}: {{itemName.message}}
</view>
block wx:for
类似 block wx:if,也可以将 wx:for 用在<block/>
标签上,以渲染一个包含多节点的结构块。例如:
<block wx:for="{{[1, 2, 3]}}">
<view>{{index}}:</view>
<view>{{item}}</view>
</block>
注意: <block/>
并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性。
wx:if 在框架中,使用 wx:if="{{condition}}" 来判断是否需要渲染该代码块:
<view wx:if="{{condition}}">True</view>
也可以用 wx:elif 和 wx:else 来添加一个 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>
WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。 WXSS 用来决定 WXML 的组件应该怎么显示。 为了适应广大的前端开发者,WXSS 具有 CSS 大部分特性。同时为了更适合开发微信小程序,WXSS 对 CSS 进行了扩充以及修改。 与 CSS 相比,WXSS 扩展的特性有:
rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
建议: 开发微信小程序时设计师可以用 iPhone6
作为视觉稿的标准。
ps: 为什么是以iPhone6 作为一个屏幕参考机型呢?因为小程序出现前的年代,很多UI设计师都是参考当时流行的机型来进行定义设计稿的尺寸宽度
注意: 在较小的屏幕上不可避免的会有一些毛刺,请在开发时尽量避免这种情况。
示例:
使用 @import
语句可以导入外联样式表,@import
后跟需要导入的外联样式表的相对路径
,用 ;
表示语句结束。
/** app.wxss **/
@import "common.wxss";
.middle-p {
padding:15px;
}
组件上支持使用 style、class 属性来控制组件的样式。
<view style="color:{{color}};" />
style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。
<view class="normal_view" />
小程序中的 wxss 支持的样式选择器有如下:
定义在 app.wxss 中的样式为全局样式,作用于每一个页面。在 page 的 wxss 文件中定义的样式为局部样式,只作用在对应的页面,并会覆盖 app.wxss 中相同的选择器。
<view id="tapTest" data-hi="WeChat" bindtap="tapName">Click me!</view>
Page({
tapName(event) {
console.log(event)
}
})
事件分为冒泡事件和非冒泡事件:
事件冒泡列表:
注:除上表之外的其他组件自定义事件如无特殊声明都是非冒泡事件,如的submit事件,的input事件,
事件绑定的写法同组件的属性,以 key、value 的形式。
bind
或 catch
开头,然后跟上事件的类型,如bindtap、catchtouchstart。自基础库版本 1.5.0 起,在非原生组件中,bind和catch后可以紧跟一个冒号,其含义不变,如bind:tap、catch:touchstart。bind事件
绑定不会阻止冒泡事件向上冒泡,catch事件
绑定可以阻止冒泡事件向上冒泡。
例如:
<!-- 如下是通过 bind 绑定事件行为,有冒泡行为 -->
<view bindtap="fatherEvent">
fatherView
<view bindtap="sayHello" data-id="12" data-name="张三"
data-desc-intor="helloWorld"
>点我
</view>
</view>
<!-- catch绑定的事件行为,只会在当前组件中产生行为,不会有冒泡行为 -->
<view bindtap="fatherEvent">
fatherView
<view catchtap ="sayHello" data-id="12" data-name="张三"
data-desc-intor="helloWorld"
>点我
</view>
</view>
target 和 currentTarget 如何区分?可以使用事件冒泡来区别
在组件中可以定义数据,这些数据将会通过事件传递给注册绑定事件函数中,在组件中的书写方式:
以data-开头
,多个单词由连字符-链接,不能有大写(大写会自动转成小写),如data-element-type,
最终在 event.currentTarget.dataset
中会将连字符转成驼峰 elementType。
例如:
引入模块。返回模块通过 module.exports
或 exports
暴露的接口。
// 准备数据
var carList = [
{ path: "/img/car/298.jpg", name: "宇通客车" },
{ path: "/img/car/93.jpg", name: "永源" },
{ path: "/img/car/232.jpg", name: "御捷" },
{ path: "/img/car/94.jpg", name: "众泰" },
{ path: "/img/car/22.jpg", name: "中华" },
{ path: "/img/car/74.jpg", name: "中兴" },
{ path: "/img/car/182.jpg", name: "之诺" },
{ path: "/img/car/206.jpg", name: "知豆" }
];
// 通过 module.exports 导出数据即可
module.exports.brandList = carList
// 通过 require() 方法导入 模块,只支持 相对当前项目的相对路径
var brandList= require("../../data/cardata.js");
console.log(brandList)
页面的逻辑层中,可以使用 this.setData() 方法,动态的为 当前页面的初识数据对象
data 属性 进行参数赋值
/**
* 页面的初始数据
*/
data: {
msg:"Hello World"
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var that=this;
// 三秒过后变成中文的你好
setTimeout(function(){
that.setData({ msg: "你好" })
},3000)
}
},
<view>{{msg}}</view> <!--输出你好-->