微信小程序开发 —— 基础知识

1,931 阅读16分钟

这是我参与8月更文挑战的第21天,活动详情查看:8月更文挑战

一、目录结构

微信小程序目录结构

二、配置

一个小程序应用程序会包括最基本的两种配置文件。一种是全局配置文件 app.json 和 页面自己的配置文件 page.json.

配置文件中不能出现注释

2.1 全局配置 app.json

app.json 是当前小程序的全局配置,包括了小程序的所有页面路径、界面表现、网络超时时间、底部tab等。

 {
   "pages":[
     "pages/index2/index2",
     "pages/index/index",
     "pages/logs/logs"
   ],
   "window":{
     "backgroundTextStyle":"dark",
     "navigationBarBackgroundColor": "#0094ff",
     "navigationBarTitleText": "WeChat",
     "navigationBarTextStyle":"black",
     "enablePullDownRefresh":true
   },
   "tabBar": {
     "list": [
       {
         "pagePath":"pages/index/index",
         "text":"首页",
         "iconPath": "icons/home.png",
         "selectedIconPath": "icons/home_active.png"
       },
       {
         ...
       }
     ],
     "backgroundColor": "#CCC",
     "color": "#000",
     "selectedColor": "#0094ff",
     "borderStyle": "white"
   }
 }

2.2 页面配置page.json

page.json 表示页面目录下 page.json 和小程序页面相关的配置;

我们可以独立为每一个页面定义属性,如顶部颜色、是否允许被下拉刷新等;

page.json 只能设置 app.json 中部分 window 配置项的内容,page.json 会覆盖 app.jsonwindow 中相同的配置。

三、视图层

WXML(WeiXin Markup Language)是框架设计的一套标签语言,结合 基础组件、事件系统,可以构成页面的结构

3.1 数据绑定

WXML 中的动态数据均来自对应 Page 的 data。

简单绑定

数据绑定使用 Mustache 语法(双大括号)将变量包起来,可以作用于:

内容

 <view> {{ message }} </view>
 Page({
   data: {
     message: 'Hello MINA!'
   }
 })

组件属性(需要在双引号之内)

 <view id="item-{{id}}"> </view>
 Page({
   data: {
     id: 0
   }
 })

控制属性(需要在双引号之内)

 <view wx:if="{{condition}}"> </view>
 Page({
   data: {
     condition: true
   }
 })

关键字(需要在双引号之内)

true:boolean 类型的 true,代表真值。

false: boolean 类型的 false,代表假值。

 <checkbox checked="{{false}}"> </checkbox>

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

运算

可以在 {{}} 内进行简单的运算,支持的有如下几种方式:

三元运算
 <view hidden="{{flag ? true : false}}"> Hidden </view>

算数运算

 <view> {{a + b}} + {{c}} + d </view>
 Page({
   data: {
     a: 1,
     b: 2,
     c: 3
   }
 })

view中的内容为 3 + 3 + d

逻辑判断
 <view wx:if="{{length > 5}}"> </view>
字符串运算
 <view>{{"hello" + name}}</view>
 Page({
   data:{
     name: 'MINA'
   }
 })
数据路径运算
 <view>{{object.key}} {{array[0]}}</view>
 Page({
   data: {
     object: {
       key: 'Hello '
     },
     array: ['MINA']
   }
 })

组合

也可以在 Mustache 内直接进行组合,构成新的对象或者数组。

数组
 <view wx:for="{{[zero, 1, 2, 3, 4]}}"> {{item}} </view>
 Page({
   data: {
     zero: 0
   }
 })

最终组合成数组[0, 1, 2, 3, 4]

对象
 <template is="objectCombine" data="{{for: a, bar: b}}"></template>
 Page({
   data: {
     a: 1,
     b: 2
   }
 })

最终组合成的对象是 {for: 1, bar: 2}

也可以用扩展运算符 ... 来将一个对象展开

 <template is="objectCombine" data="{{...obj1, ...obj2, e: 5}}"></template>
 Page({
   data: {
     obj1: {
       a: 1,
       b: 2
     },
     obj2: {
       c: 3,
       d: 4
     }
   }
 })

最终组合成的对象是 {a: 1, b: 2, c: 3, d: 4, e: 5}

如果对象的 key 和 value 相同,也可以间接地表达。

 <template is="objectCombine" data="{{foo, bar}}"></template>
 Page({
   data: {
     foo: 'my-foo',
     bar: 'my-bar'
   }
 })

最终组合成的对象是 {foo: 'my-foo', bar:'my-bar'}

注意:上述方式可以随意组合,但是如有存在变量名相同的情况,后边的会覆盖前面,如:

 <template is="objectCombine" data="{{...obj1, ...obj2, a, c: 6}}"></template>
 Page({
   data: {
     obj1: {
       a: 1,
       b: 2
     },
     obj2: {
       b: 3,
       c: 4
     },
     a: 5
   }
 })

最终组合成的对象是 {a: 5, b: 3, c: 6}

注意: 花括号和引号之间如果有空格,将最终被解析成为字符串

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

等同于

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

3.2 列表渲染

wx:for

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

默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item

使用 wx:for-item 可以指定数组当前元素的变量名,

使用 wx:for-index 可以指定数组当前下标的变量名:

 <view wx:for="{{array}}" wx:for-index="i" wx:for-item="value">
     {{i}} : {{value}}
 </view>>
 <view wx:for="{{person}}" wx:for-index="key" wx:for-item="value">
   {{key}} : {{value}}
 </view>
 Page({
   /**
    * 页面的初始数据
    */
   data: {
     array:["姓名","年龄","性别"],
     person:{
       name:"xiaojian",
       age:22,
       gender:"man"
     }
 })

wx:for 还可以嵌套

 <view wx:for="{{[1,2,3,4,5,6,7,8,9]}}" wx:for-item="i">
   <view wx:for="{{[1,2,3,4,5,6,7,8,9]}}" wx:for-item="j">
     <view wx:if="{{j <= i}}">
       {{j}} * {{i}} = {{j * i}}
     </view>
   </view>
 </view>

注意:当 wx:for 的值没有用两个花括号括起来,将被当成字符串,字符串被解析成字符数组

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

等同于

 <view wx:for="{{['[','1','2','3','4','5',']']}}">
   {{item}}
 </view>

输出

 0 : [
 1 : 1
 2 : 2
 3 : 3
 4 : 4
 5 : 5
 6 : ]

注意: 花括号和引号之间如果有空格,将最终被解析成为字符串

wx:key

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

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

  1. 字符串,代表在 for 循环的 array 中 item 的某个 property,该 property 的值需要是列表中唯一的字符串或数字,且不能动态改变。
  2. 保留关键字 *this 代表在 for 循环中的 item 本身,这种表示需要 item 本身是一个唯一的字符串或者数字。

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

如不提供 wx:key,会报一个 warning, 如果明确知道该列表是静态,或者不必关注其顺序,可以选择忽略。

3.3 WXSS

WXSS (WeiXin Style Sheets)是一套样式语言,用于描述 WXML 的组件样式。

尺寸单位

  • rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备rpx换算px (屏幕宽度/750)px换算rpx (750/屏幕宽度)
iPhone51rpx = 0.42px1px = 2.34rpx
iPhone61rpx = 0.5px1px = 2rpx
iPhone6 Plus1rpx = 0.552px1px = 1.81rpx

建议: 开发微信小程序时设计师可以用 iPhone6 作为视觉稿的标准。

注意: 在较小的屏幕上不可避免的会有一些毛刺,请在开发时尽量避免这种情况。

样式导入

在一个页面文件夹下的页面文件是不用导入该文件夹下的样式文件的,它们所有的文件都是自动关联的。

要导入外联样式表,需要在该页面文件夹下的 page.wxss 文件里:

使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。

 /* page.wxss */
 @import "../../styles/commons.wxss";
 ...

且, page.wxss 的样式优先级大于 外部引入的样式表;

即,针对相同的标签写的样式, page.wxss 中的样式会覆盖外部引入的样式

注意wxss 中的注释只能写成 / ... /

内联样式

框架组件上支持使用 style、class 属性来控制组件的样式。

  • style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度。
 <view style="color:{{color}};" />
  • class:用于指定样式规则,其属性值是样式规则中类选择器名(样式类名)的集合,样式类名不需要带上.,样式类名之间用空格分隔。
 <view class="normal_view" />

四、组件

1、基本组件

1.1 view

相当于 html 中的div

属性类型默认值必填说明最低版本
hover-classstringnone指定按下去的样式类。当 hover-class="none" 时,没有点击态效果1.0.0
hover-stop-propagationbooleanfalse指定是否阻止本节点的祖先节点出现点击态1.5.0
hover-start-timenumber50按住后多久出现点击态,单位毫秒1.0.0
hover-stay-timenumber400手指松开后点击态保留时间,单位毫秒1.0.0

1.2 text

文本,相当于 html 中的span

text只能嵌套 text

属性类型默认值必填说明最低版本
selectablebooleanfalse文本是否可选 (已废弃)1.1.0
user-selectbooleanfalse文本是否可选,该属性会使 文本节点显示为 inline-block2.12.1
spacestring显示连续空格1.4.0
decodebooleanfalse是否解码1.4.0

space 的合法值

说明最低版本
ensp中文字符空格一半大小
emsp中文字符空格大小
nbsp根据字体设置的空格大小

1.3 image

图片标签,image 组件默认宽度 320px、高度 240px

支持 JPG、PNG、SVG、WEBP、GIF 等格式,2.3.0 起支持云文件ID。

注意:该标签 其实是 web 中的 图片和 背景图片 的结合!并且不支持以前 web 中的背景图片的写法!

属性类型默认值必填说明
srcstring图片资源地址
modestringscaleToFill图片裁剪、缩放的模式
webpbooleanfalse默认不解析 webP 格式,只支持网络资源
lazy-loadbooleanfalse图片懒加载,在即将进入一定范围 (上下三屏)时才开始加载

mode 的合法值

说明
scaleToFill缩放模式,不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素
aspectFit缩放模式,保持纵横比缩放图片,使图片的长边能完全显示出来。也就是说,可以完整地将图片显示出来。
aspectFill缩放模式,保持纵横比缩放图片,只保证图片的短边能完全显示出来。也就是说,图片通常只在水平或垂直方向是完整的,另一个方向将会发生截取。
widthFix缩放模式,宽度不变,高度自动变化,保持原图宽高比不变
heightFix缩放模式,高度不变,宽度自动变化,保持原图宽高比不变
top裁剪模式,不缩放图片,只显示图片的顶部区域
bottom裁剪模式,不缩放图片,只显示图片的底部区域
center裁剪模式,不缩放图片,只显示图片的中间区域
left裁剪模式,不缩放图片,只显示图片的左边区域
right裁剪模式,不缩放图片,只显示图片的右边区域
top left裁剪模式,不缩放图片,只显示图片的左上边区域
top right裁剪模式,不缩放图片,只显示图片的右上边区域
bottom left裁剪模式,不缩放图片,只显示图片的左下边区域
bottom right裁剪模式,不缩放图片,只显示图片的右下边区域

1.4 swiper

微信内置轮播图组件。默认宽度 100%,高度150px.

滑块视图容器。其中只可放置swiper-item组件,否则会导致未定义的行为。

属性类型默认值必填说明
indicator-dotsbooleanfalse是否显示面板指示点
indicator-colorcolorrgba(0, 0, 0, .3)指示点颜色
indicator-active-colorcolor#000000当前选中的指示点颜色
autoplaybooleanfalse是否自动切换
currentnumber0当前所在滑块的 index
intervalnumber5000自动切换时间间隔
durationnumber500滑动动画时长
circularbooleanfalse是否采用衔接滑动
verticalbooleanfalse滑动方向是否为纵向
easing-functionstring"default"指定 swiper 切换缓动动画类型

easing-function 的合法值

说明最低版本
default默认缓动函数
linear线性动画
easeInCubic缓入动画
easeOutCubic缓出动画
easeInOutCubic缓入缓出动画

1.5 navigator

导航组件,类似超链接标签

属性类型默认值必填说明
targetstringself在哪个目标上发生跳转,默认当前小程序
urlstring当前小程序内的跳转链接链接后不用加文件名.wxml
open-typestringnavigate跳转方式
deltanumber1当 open-type 为 'navigateBack' 时有效,表示回退的层数

target 的合法值

说明
self当前小程序
miniProgram其它小程序

open-type 的合法值

说明
navigate保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。
redirect关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面
switchTab跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
reLaunch关闭所有页面,打开到应用内的某个页面
navigateBack关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层
exit退出小程序,target="miniProgram"时生效

1.6 video

视频。

属性类型默认值必填说明
srcstring要播放视频的资源地址,支持网络路径、 本地临时路径、云文件ID(2.3.0
durationnumber指定视频时长
controlsbooleantrue是否显示默认播放控件 (播放/暂停按钮、播放进度、时间)
autoplaybooleanfalse是否自动播放
loopbooleanfalse是否循环播放
mutedbooleanfalse是否静音播放
show-mute-btnbooleanfalse是否显示静音按钮
initial-timenumber0指定视频初始播放位置
titlestring视频的标题,全屏时在顶部展示
enable-play-gesturebooleanfalse是否开启播放手势,即双击切换播放/暂停

1.7 button

按钮

样式

属性类型默认值必填说明
sizestringdefault按钮的大小
typestringdefault按钮的样式类型
plainbooleanfalse按钮是否镂空,背景色透明
disabledbooleanfalse是否禁用
loadingbooleanfalse名称前是否带 loading 图标
form-typestring用于 form 组件,点击分别会触发 form 组件的 submit/reset 事件
open-typestring微信开放能力

size 的合法值

说明
default默认大小
mini小尺寸

type 的合法值

说明
primary绿色
default白色
warn红色

form-type 的合法值

说明
submit提交表单
reset重置表单

open-type 的合法值

说明
contact打开客服会话,如果用户在会话中点击消息卡片后返回小程序,可以从 bindcontact 回调中获得具体信息,具体说明
share触发用户转发,使用前建议先阅读使用指引
getPhoneNumber获取用户手机号,可以从bindgetphonenumber回调中获取到用户信息,具体说明
getUserInfo获取用户信息,可以从bindgetuserinfo回调中获取到用户信息
launchApp打开APP,可以通过app-parameter属性设定向APP传的参数具体说明
openSetting打开授权设置页
feedback打开“意见反馈”页面,用户可提交反馈内容并上传日志,开发者可以登录小程序管理后台后进入左侧菜单“客服反馈”页面获取到反馈内容

2、自定义组件

小程序允许我们使用自定义组件的方式来构建页面。

自定义组件就像是web中,一个个公共页面,将一个个公共页面提取出来,在其他页面中用到时就直接使用一个标签就解决了。

2.1 创建自定义组件

类似页面,一个自定义组件由 jsonwxmlwxssjs 4个文件组成

1601363344921

 # MyHeader.json
 {
   "component": true,
   "usingComponents": {}
 }
 # MyHeader.wxml
 <view class="my_header">
   {{initalData}}
   <view>
     <!-- 该标签可以加入自定义的内容 -->
     <slot></slot>
   </view>
 </view>
 // components/MyHeader/MyHeader.js
 Component({
   /**
    * 组件的属性列表
    * 初始值,当有页面使用这个组件并声明了 initalData 这个属性,初始值将会被替换
    * 属性名:{
    *    type:(类型),
    *    value:(默认值)
    *    }
    */
   properties: {
     initalData:{
       value:"这是初始值",
       type:String
     }
   },
   /**
    * 组件的初始数据
    */
   data: {
   },
   /**
    * 组件的方法列表
    */
   methods: {
   }
 })
 .my_header{
   color:blue;
   background-color: red;
   width:200px;
   height:200px;
 }

2.2 使用自定义组件

1601363721976

 # customModule.json
 {
   "usingComponents": {
     "my":"../../components/MyHeader/MyHeader"
   }
 }
 # customModule.wxml
 <view>
   <my>包含数据</my>
 </view>>

1601383330353

 # customModule.wxml
 <view initalData="替换值">
   <my>自定义???</my>
 </view>>

1601383355960

2.3 进阶

自定义组件,一个导航条,对每次点击添加样式。

1601382229005

 # Tabs.json
 {
   "component": true,
   "usingComponents": {}
 }
 <!-- Tabs.wxml -->
 <view class="tabs">
   <view class="tabs_title">
     <view wx:for="{{tabs}}" 
     wx:key="id" 
     class="title_item {{item.isActive?'active':'none'}}"
     bindtap="handleItemTap"
     data-index="{{index}}">
       {{item.name}}
     </view>
   </view>
   <view class="tab_content">内容</view>
 </view>
 /* Tabs.wxss */
 .tabs{
 ​
 }
 .tabs_title{
   display:flex;
   padding:10rpx;
 }
 .title_item{
   flex:1;
   display:flex;
   justify-content: center;
   align-items: center;
 }
 .active{
   color:red;
   border-top: 5px solid red;
 }
 // Tabs.js
 Component({
   /**
    * 组件的属性列表
    */
   properties: {
 ​
   },
   /**
    * 组件的初始数据
    */
   data: {
     tabs:[
       {
         id:0,
         name:"首页",
         isActive:true
       },
       {
         id:1,
         name:"原创",
         isActive:false
       },
       {
         id:2,
         name:"分类",
         isActive:false
       },
       {
         id:3,
         name:"关于",
         isActive:false
       }
     ]
   },
 ​
   /**
    * 组件的方法列表
    */
   methods: {
     /**
      * 1.绑定点击事件 需要在methods 中绑定
      * 2.获取被点击的索引
      * 3.获取原数组
      * 4.对数组循环
      *  4.1  给每个循环项 选中属性 改为 false
      *  4.2  给当前索引的项 添加选中
      */
     handleItemTap(e){
       console.log(e);
       // 2.获取被点击的索引
       var indexList = e.currentTarget.dataset.index;
       // 3.获取原数组
       var tabs = this.data.tabs;
       tabs.forEach((v,i)=>i===indexList?v.isActive=true:v.isActive=false);
       this.setData({
         tabs
       })
     }
   }
 })
 ​

使用

 # customModule.json
 {
   "usingComponents": {
     "Tabs":"../../components/Tabs/Tabs"
   }
 }
 <!-- customModule.wxml -->
 <Tabs></Tabs>
自定义组件--父向子传递数据

自定义组件为 子,使用自定义组件的页面是 父

用 属性列表 替换 自定义组件中的固定值

 <!-- customModule.wxml -->
 <Tabs tabs="{{tabs}}"></Tabs>
 // customModule.js
 Page({
 ​
   /**
    * 页面的初始数据
    */
   data: {
     tabs:[
       {
         id:0,
         name:"热门",
         isActive:true
       },
       {
         id:1,
         name:"重点",
         isActive:false
       },
       {
         id:2,
         name:"声明",
         isActive:false
       },
       {
         id:3,
         name:"反馈",
         isActive:false
       }
     ]
   }
 })
 // Tabs.js
 Component({
   /**
    * 组件的属性列表
    */
   properties: {
     tabs:{
       type:Array,
       value:[]
     }
   },
   /**
    * 组件的初始数据
    */
   data: {
 ​
   },
 ​
   /**
    * 组件的方法列表
    */
   methods: {
     handleItemTap(e){
      ...
     }
   }
 })
 ​
自定义组件--子向父传递数据

根据上方方法,子组件使用的父组件的数据,但是执行点击事件时,修改的仍是子组件数据;所以,要编写成修改父组件中的数据的值

解决方法:

将子组件点击事件交给父组件执行,子组件负责传递数据给父组件

 # Tabs.js
 ...
 handleItemTap(e){
       // 2.获取被点击的索引
       var index = e.currentTarget.dataset.index;
 ​
       // 5.点击事件触发的时候
       //  触发父组件中的自定义事件  同时传递数据给父组件
       this.triggerEvent("itemChange",{index});
 }
 ...
 <!-- customModule.wxml -->
 <!-- 定义事件,bind事件名称,的形式 -->
 <Tabs tabs="{{tabs}}" binditemChange="handleItemChange">
 </Tabs>
 # customModule.js
 ...
 // 自定义事件 接受子组件传的数据  并执行相应操作
 handleItemChange(e){
     // console.log(e);
     // 2.获取被点击的索引
     var index = e.detail.index;
     // 3.获取原数组
     var tabs = this.data.tabs;
     // 4.对数组循环
     tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
     this.setData({
         tabs
     })
 }
 ...

五、小程序生命周期

1、应用生命周期

属性类型默认值必填说明
onLaunchfunction监听小程序初始化。
onShowfunction生命周期回调——监听小程序启动或切前台。
onHidefunction生命周期回调——监听小程序切后台。
onErrorfunction错误监听函数。
onPageNotFoundfunction页面不存在监听函数。
onUnhandledRejectionfunction未处理的 Promise 拒绝事件监听函数。
onThemeChangefunction监听系统主题变化

2、页面生命周期

属性类型默认值必填说明
dataObject页面的初始数据
onLoadfunction生命周期回调—监听页面加载
onShowfunction生命周期回调—监听页面显示
onReadyfunction生命周期回调—监听页面初次渲染完成
onHidefunction生命周期回调—监听页面隐藏
onUnloadfunction生命周期回调—监听页面卸载
onPullDownRefreshfunction监听用户下拉动作
onReachBottomfunction页面上拉触底事件的处理函数
onShareAppMessagefunction用户点击右上角转发
onShareTimelinefunction用户点击右上角转发到朋友圈
onAddToFavoritesfunction用户点击右上角收藏
onPageScrollfunction页面滚动触发事件的处理函数
onResizefunction页面尺寸改变时触发,详见 响应显示区域变化
onTabItemTapfunction当前是 tab 页时,点击 tab 时触发
其他any开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问

3、页面生命周期图解

小程序生命周期