背景
上一篇文章我们主要介绍了微信小程序的几个配置,其中app.json
是对于微信小程序全局的配置,page.json
是对于小程序页面的配置,project.config.json
是对于小程序开发工具的配置,sitemap.json
是用于配置小程序和页面是否可以被微信检索。这篇文章主要用于介绍微信小程序的页面构成。
页面构成
从事过网页编程的人知道,网页编程采用的是 HTML + CSS + JS 这样的组合,其中 HTML
是用来描述当前这个页面的结构,CSS
用来描述页面的样子,JS
通常是用来处理这个页面和用户的交互。其实微信小程序的页面也相当于一个网页,其中的构成也与之类似。如下图所示即是一个页面index包含的内容,其中index.json
上篇文章已经提到是页面的配置,其他的如index.wxml
与HTML
类似,用于定于微信小程序的页面结构,index.wxss
则与CSS
类似,是用于描述页面的样子,而index.js
是用于微信小程序的交互。
WXML
以下代码显示了我们建立的测试项目的index.wxml
的内容,可以看出与 HTML
非常相似,WXML
由标签、属性等等构成。但是也有很多不一样的地方,主要有两点不同。
<!--index.wxml-->
<view class="container">
<view class="userinfo">
<block wx:if="{{canIUseOpenData}}">
<view class="userinfo-avatar" bindtap="bindViewTap">
<open-data type="userAvatarUrl"></open-data>
</view>
<open-data type="userNickName"></open-data>
</block>
<block wx:elif="{{!hasUserInfo}}">
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
<button wx:elif="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
<view wx:else> 请使用1.4.4及以上版本基础库 </view>
</block>
<block wx:else>
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
</block>
</view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
标签名称不同且封装了更多组件
往往写 HTML 的时候,经常会用到的标签是 div
, p
, span
,开发者在写一个页面的时候可以根据这些基础的标签组合出不一样的组件,例如日历、弹窗等等。换个思路,既然大家都需要这些组件,为什么我们不能把这些常用的组件包装起来,大大提高我们的开发效率。
从上边的例子可以看到,小程序的 WXML
用的标签是 view
, button
, text
等等,这些标签就是小程序给开发者包装好的基本能力,微信小程序还提供了地图、视频、音频等等组件能力。微信小程序组件中提供了很多封装好的组件,这里就不过多介绍,以后会专门写一篇文章结合例子详细介绍微信小程序提供的组件。
在这里我还是忍不住想要解释一下为什么这里不过多介绍细节,这就牵扯到这篇文章的主题是宿主环境和页面结构而不是具体实现,而且微信小程序提供了很丰富的组件,如果都详细介绍则详略失当,让人抓不住重点。这又让我想到了之前初中学习语文关于陶渊明读书方法的争论,到底是略其大观“不求甚解”,还是应该追根问底,对我个人而言,我觉得两种方法都对,只是时机不同,当完全接触一个新事物的时候,我们就应该略其大观,在整体上有一个认识,这时候不要过多追究细节,否则就会深陷其中难以自拔。当我们对于一个新的事物已经有了整体上的认识,想继续研究则需要选择一个方面,一丝不苟不放过一个细节地去研究,这样才能深刻的理解和应用。这一系列的前几篇文章都是略其大观,不会牵扯大多细节,希望大家能够对微信小程序有一个整体认识即可,好了废话到此结束。
多了一些 wx:if
这样的属性以及 {{ }} 这样的表达式
在网页的一般开发流程中,我们通常会通过 JS
操作 DOM
(对应 HTML
的描述产生的树),以引起界面的一些变化响应用户的行为。例如,用户点击某个按钮的时候,JS
会记录一些状态到 JS
变量里边,同时通过 DOM
API 操控 DOM
的属性或者行为,进而引起界面一些变化。当项目越来越大的时候,你的代码会充斥着非常多的界面交互逻辑和程序的各种状态变量,显然这不是一个很好的开发模式,因此就有了 MVVM 的开发模式(例如 React, Vue),提倡把渲染和逻辑分离。简单来说就是不要再让 JS
直接操控 DOM
,JS
只需要管理状态即可,然后再通过一种模板语法来描述状态和界面结构的关系即可。这么说可能比较抽象,以我们建立的测试项目为例,我们在屏幕中显示了“Hello World”,那具体是如何实现的呢。
在WXML中我们声明了一个变量motto
<text class="user-motto">{{motto}}</text>
在JS中我们将motto赋值为“Hello World”,与此同时我们还可通过函数去改变motto的值从而更改页面状态,而不需要直接去操控DOM节点。
data: {
motto: 'Hello World',
userInfo: {},
hasUserInfo: false,
canIUse: wx.canIUse('button.open-type.getUserInfo'),
canIUseGetUserProfile: false,
canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName') // 如需尝试获取用户信息可改为false
}
通过 {{ }} 的语法把一个变量绑定到界面上,我们称为数据绑定。仅仅通过数据绑定还不够完整的描述状态和界面的关系,还需要 if
/else
, for
等控制能力,在小程序里边,这些控制能力都用 wx:
开头的属性来表达。
WXSS
WXSS
具有 CSS
大部分的特性,小程序在 WXSS
也做了一些扩充和修改。
新增了尺寸单位。在写
CSS
样式时,开发者需要考虑到手机设备的屏幕会有不同的宽度和设备像素比,采用一些技巧来换算一些像素单位。WXSS
在底层支持新的尺寸单位rpx
,开发者可以免去换算的烦恼,只要交给小程序底层来换算即可,由于换算采用的浮点数运算,所以运算结果会和预期结果有一点点偏差。提供了全局的样式和局部样式。和前边
app.json
,page.json
的概念相同,你可以写一个app.wxss
作为全局样式,会作用于当前小程序的所有页面,局部页面样式page.wxss
仅对当前页面生效。此外
WXSS
仅支持部分CSS
选择器
JS
一个服务仅仅只有界面展示是不够的,还需要和用户做交互:响应用户的点击、获取用户的位置等等。在小程序里边,我们就通过编写 JS
脚本文件来处理用户的操作。还是以我们建立的测试项目来说明,下面左图是测试项目的启动页面,当用户点击时就会发生页面跳转,跳转到右边所示的页面。
这是如何实现的呢?首先看一下index.wxml
,其相关内容如下,可以看到view有一个属性bindtap,这是用来响应用户点击操作的,它的属性值是bindViewTap,这是一个函数名,该函数定义了用户点击时该如何反应,这个函数的定义则在index.js
。
WXML相关内容
<block wx:if="{{canIUseOpenData}}">
<view class="userinfo-avatar" bindtap="bindViewTap">
<open-data type="userAvatarUrl"></open-data>
</view>
<open-data type="userNickName"></open-data>
</block>
JS相关内容
bindViewTap() {
wx.navigateTo({
url: '../logs/logs'
})
}
最后
有兴趣可以关注公众号QStack,会定期分享一些文章和免费的学习资源。