文件和目录介绍
小程序包括两个部分:主体文件、页面文件。
主体文件由三部分组成:
- app.js:小程序入口文件
- app.json:小程序的全局配置文件
- app.wxss:小程序的全局样式
注意事项:主体文件名字必须是app、app.js和app.json文件是必须的
页面文件是每个页面所需的文件,小程序页面文件都存放在pages目录下,一个页面一个文件夹。
页面文件由四个文件组成,每个文件只对当前页面有效:
- .js:页面逻辑
- .wxml:页面结构
- .wxss:页面样式
- .json:小页面配置
注意事项:.js文件和.wxml文件是必须的
配置文件介绍
- app.json:小程序全局配置文件,用于配置小程序的一些全局属性和页面路由。
- 页面.json:小程序页面配置文件,也称局部配置文件,用于配置当前页面的窗口样式、页面标题等
- project.config.json:小程序项目配置的配置文件,用于保存项目的一些配置信息和开发者的个人设置。
- sitemap.json:配置小程序及其页面是否允许被微信索引,提高小程序在搜索引擎搜索到的概率。
全局配置-pages配置
pages字段:用来指定小程序由那些页面组成,用于让小程序知道由那些页面组成以及页面定义在那个目录,每一项对应一个页面的路径信息
注意事项:
- 页面路由不需要写文件后缀,框架会自动去寻找对应位置的四个文件进行处理。
- 小程序中新增/减少页面,都需要对pages数组进行修改。
- 未指定entryPagePath时,数组的第一项代表小程序的初始页面(首页)。
全局配置-window配置
window字段:用于设置小程序的状态栏、导航条、标题、窗口背景色。微信小程序页面配置文档https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html
全局配置-tabbar配置
tabBar字段:定义小程序顶部、底部tab栏,用以实现页面之间的快速切换,可以通过配置tarBar配置项指定tab栏的表现,以及tab切换时显示的对应页面。
注意事项:
- tab按数组的顺序排序,list配置最少2个、最多5个tab
app.json配置如下
{
//页面路由
"pages": [
"pages/index/index",
"pages/cate/cate",
"pages/cart/cart",
"pages/profile/profile",
"pages/list/list"
],
"window": {
"navigationBarTitleText": "慕尚花坊",//小程序名称
"navigationBarBackgroundColor": "#f3514f", //小程序title背景颜色
"enablePullDownRefresh":true,//是否开启下拉刷新
"backgroundColor": "#efefef",
"backgroundTextStyle":"light"
},
//导航栏配置
"tabBar": {
"selectedColor": "#f3514f",//选中的颜色
"color": "#666",//字体颜色
"list": [
{
"text":"首页",//名称
"pagePath": "pages/index/index",//路径
"iconPath": "/assets/tabbar/index.png", //没选中的icon
"selectedIconPath": "/assets/tabbar/index-active.png"//选中的icon
},
{
"text":"分类",
"pagePath": "pages/cate/cate",
"iconPath": "/assets/tabbar/cate.png",
"selectedIconPath": "/assets/tabbar/cate-active.png"
},
{
"text":"购物车",
"pagePath": "pages/cart/cart",
"iconPath": "/assets/tabbar/cart.png",
"selectedIconPath": "/assets/tabbar/cart-active.png"
},
{
"text":"我的",
"pagePath": "pages/profile/profile",
"iconPath": "/assets/tabbar/my.png",
"selectedIconPath": "/assets/tabbar/my-active.png"
}
]
},
"style": "v2",
"sitemapLocation": "sitemap.json",
"lazyCodeLoading": "requiredComponents"
}
页面配置
小程序的页面配置,也称局部配置,每一个小程序页面也可以使用自己的.json文件对本页面窗口表现进行配置。
需要注意的是:页面配置文件的属性和全局配置文件中的window属性几乎一致,只不过这里不需要额外指定window字段,因此如果出现相同的配置项,页面中配置项会覆盖全局配置文件中相同的配置项。
微信小程序页面配置文档https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html
项目配置文件和配置sass
在创建项目的时候,每个项目的根目录生成两个config.json文件,用于保存开发者在工具上做的个性化配置,例如和编译有关的配置。当重新安装微信开发者工具或换电脑工作时,只要载入同一个项目的代码包,开发者工具就会自动恢复带当时开发项目时的个性化配置。
project.config.json:项目配置文件,常用来进行配置公共的配置
project.private.config.json:项目私有的配置,常用来配置个人的配置
注意事项:
- project.private.config.json写到.gitignore避免版本管理的冲突。
- 与最终编译结果有关的设置必须设置到project.config.json
项目配置文件官方文档https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html配置sass步骤如下
然后将wxss样式文件后缀名改成scss就可以在项目中使用sass了。
配置文件-sitemap.json 文件
sitemap.json文件:配置小程序及其页面是否允许被微信索引,提高小程序在微信内部被用户搜索到的概率。
注意事项:
- 注:没有sitemap.json则默认所有页面都能被索引
- {"action":"allow","page":"*"}是优先级最低的默认规则,未显式指明"disallow"的都默认被索引
小程序的样式和组件介绍
小程序中不能使用HTML表情按,也就没有DOM和BOM,css也仅仅支持部分选择器
小程序提供了wxml进行页面结构编写,同时提供了wxss进行页面的样式编写
小程序组件官方文档https://developers.weixin.qq.com/miniprogram/dev/component/
样式-尺寸单位rpx
小程序规定任何型号手机:屏幕宽都为750rpx
样式-全局样式和局部样式
全局样式:指在app.wxss中定义的样式规则,作用于每一个页面,例如:设置字号、背景色、宽高等全局样式。
局部央视:指在app.wxss中定义的样式规则,只作用在对应的页面,并会覆盖app.wxss中相同的选择器。
组件-组件案例演示
小程序常用的组件:
- view组件
- swiper和swiper-item组件
- image组件
- text组件
- navigator组件
- scroll-view组件
- 字体图标
页面跳转
在小程序中。如果需要进行跳转,需要用到navigation组件,常见的属性有两个:
1.url:当前小程序内的跳转链接
2.open-type:跳转方式
navigate:保留当前页面,跳转到应用内的某个页面,但是不能跳转到tabbar页面
redirect:关闭当前页面,跳转到应用内的某个页面,但是不能跳转到tabbar页面
switchTab:跳转到tabBar页面,并关闭其他所有非tabBar页面
reLaunch:关闭所有页面,打开到应用内的某个页面
navigateBack:关闭当前页面,返回上衣页面或多级页面
注意事项:
1.路径可以带参数。参数与路径之间使用?分隔,参数键与参数值用=相连,不同参数用&分隔
例如:/list?id=10&name=hua,在onLoad(options)生命周期函数中获取传递的参数
2.open-type="switchTab"时不支持传参
在进行页面跳转时,需要在路径前面添加 / 斜线,否则跳转不成功
小程序内字体图标的使用
首先去iconfont网站新建一个项目,然后找到自己需要的图标添加入库,再然后添加到项目中
然后复制这个css文件到小程序中新建一个iconfont文件夹,里面放一个iconfont.scss
把复制过来的内容粘贴到这个scss文件里面,然后再在app.scss中引入这个文件,如下图
引入完成后,就可以使用字体图标了。
注意:真实项目不建议像我这样直接用,可以在那边把资源下载下来然后放到小程序里面,我这样用的话iconfont 网站要是有问题,那我们所引用的就都没用了。
这边这样引进来小程序会有个报错
解决的办法就是去iconfont网站,项目设置=>然后在字体格式勾上base64然后在生成一下,复制到小程序里面就解决了。
组件-背景图片的使用
注意:小程序的background-image不支持本地路径!!! 需要使用网络图片,或者base64,或者使用<image/>组件
事件系统-事件绑定和事件对象
小程序中绑定事件与在网页开发中绑定事件几乎一致,只不过在小程序不能通过on的方式绑定事件,也没有click事件,小程序中绑定事件使用bind方法,click事件也需要使用tap事件进行代替,绑定事件的方式有两种:
第一种:bind事件名,bind后面需要跟上冒号,冒号后面跟上事件名。例如:
<view bind:tap="fnName"></view>
第二种:bind事件名,bind后面直接跟上事件名,例如:<view bindtap="fnName"></view>
事件处理函数需要写到.js文件中,在.js文件中需要调用小程序提供的Page方法来注册小程序的页面,我们可以直接在Page方法中创建事件处理函数
事件分类以及阻止事件冒泡
事件分为:冒泡事件和非冒泡事件
冒泡事件:当一个组件的事件被触发后,该事件会向父节点传递
非冒泡事件:当一个组件的事件被触发后,该事件不会向父节点传递
使用bind绑定的事件,会触发事件冒泡,如果想阻止事件冒泡,可以用catch来绑定事件
这样就成功阻止了事件冒泡了
事件传参-data-*自定义数据
事件传参:在触发时间时,将一些数据作为参数传递给事件处理函数的过程就是事件传参。
在微信小程序中,我们经常会在组件上添加一些自定义数据,然后在事件处理函数中获取这些自定义数据,从而完成逻辑业务的开发。
在组件上通过 data-*的方式定义需要传递的数据,其中*是自定义的属性,例如:<view data-id="100" bindtap="handler"/> 然后通过事件对象进行获取自定义数据。
注意事项:
- event.target 是指事件触发者,event.currentTarget是指事件绑定者
- 使用data-方法传参数的时候,多个单词由连字符-连接,连字符写法会被转换成驼峰写法
- 使用data-方法传递参数的时候,而大写字符会自动转成小写字符
事件传参-mark 自定义数据
小程序进行事件传参的时候,除了使用data-*属性传递参数外,还可以使用mark标记传递参数
mark是一种自定义属性,可以在组件上添加,用来识别具体触发事件的target节点。同时mark还可以用于承载一些自定义数据。
在组件上使用mark:自定义属性的方式将数据传递给事件处理函数,例如:<view mark:id="100" bindtap="handler" />
mark和data-*很相似,主要区别在于:
mark包含从触发事件的节点到根节点上所有的mark:属性值
currentTarget.dataset或者target.dataset 只包含事件绑定者或者事件触发者那一个节点的data-*值。
wxml语法-声明和绑定数据
小程序页面中使用的数据均需要在Page() 方法的 data 对象中进行声明定义
在将数据声明好以后,在WXML使用Mustache语法(双大括号{{}})将变量包起来,从而将数据绑定
在{{ }} 内部可以做一些简单的运算,支持如下几种方式:
- 算数运算
- 三元运算
- 逻辑判断
- 其他...
注意事项:在{{}}语法中,只能写表达式,不能写语句,也不能调用js相关的方法
wxml语法-setData()修改数据
小程序中修改数据不推荐通过复制的方式进行修改,通过赋值的方式修改数据无法改变页面的数据,而是要通过调用setData()方法进行修改,setData()方法接受对象作为参数,key是需要修改的数据,value是最新的值
setData()方法有两个作用:
- 更新数据
- 驱动视图更新
wxml语法-setData()-修改对象类型数据
<!--index.wxml-->
<view>{{num}}</view>
<button type="primary" bind:tap="updateNum">更新 num</button>
<view>{{userInfo.name}}</view>
<view>{{userInfo.age}}</view>
<button type="warn" bind:tap="updateUserInfo">修改对象类型数据</button>
// index.js
Page({
//在小程序页面中所需要使用的数据均来自于data对象
data: {
num: 1,
userInfo: {
name: 'tom',
age: '10',
test:111
}
},
updateNum() {
//获取数据
console.log(this.data.num)
//通过赋值的方式直接修改数据,能修改数据但是不能改变页面上的数据
//this.data.num +=1
// this.setData
this.setData({
//key 需要更新的数据
// value 最新的值
num: this.data.num += 1,
})
},
updateUserInfo() {
//新增单个/多个属性
// this.setData({
// //如果给对象新增属性,可以将key写成数据路径的方式 a.b.c
// 'userInfo.name':'tom',
// "userInfo.age":10
// })
//修改单个 / 多个属性
// this.setData({
// //如果需要给对象修改属性,也可以将key写成数据路径的方式 a.b.c
// 'userInfo.name':'jerry',
// 'userInfo.age':15
// })
// 目前新增和修改都是使用数据路径,如果新增和修改的数据量比较小,还能接受
//如果修改的数据很多,每次都写数据路径,就太麻烦了
// 可以使用es6提供的展开运算符和Object.assign()
//es6提供的展开运算符
//通过展开运算符能够将对象中的属性复制给另外一个对象
//后面的属性会覆盖前面的属性
// const userInfo ={
// ...this.data.userInfo,
// name:'jerry',
// age:18
// }
// this.setData({
// userInfo
// })
//object.assign() 将多个对象合并为一个对象
// const userInfo = Object.assign(this.data.userInfo,{name:'jerry'},{age:18})
// console.log(userInfo)
// this.setData({
// userInfo
// })
//删除单个属性
// delete this.data.userInfo.age
// this.setData({
// userInfo:this.data.userInfo
// })
//删除多个属性 rest 剩余参数
const {age,test,...rest} = this.data.userInfo
this.setData({
userInfo:rest
})
}
})
wxml语法-setData()-修改数组类型数据
// index.js
Page({
//在小程序页面中所需要使用的数据均来自于data对象
data: {
num: 1,
userInfo: {
name: 'tom',
age: '10',
test:111
},
list:[1,2,3]
},
updateList(){
//新增数组元素
//如果直接使用push方法,可以直接更新data,但是不能更新页面中的数据
// this.data.list.push(4)
// this.setData({
// list:this.data.list
// })
// const newlist= this.data.list.concat(4)
// this.setData({
// list:newlist
// })
//修改数组元素
// this.setData({
// 'list[1]':6
// })
//删除数组元素
this.data.list.splice(1,1)
this.setData({
list:this.data.list
})
}
})
wxml语法-简易双向数据绑定
在wxml中,普通属性的绑定是单向的,例如:<input value="{{value}}" />
如果希望用户输入数据的同时改变data中的数据,可以借助简易双向绑定机制,在对应属性之前添加model:前缀即可:
例如 <input model:value="{{value}}" />
注意事项:简易双向绑定的属性值如下限制:
- 只能是一个单一字段的绑定
- 尚不能写data路径,不支持数组和对象
<!-- <input type="text" value="{{value}}" /> -->
<!-- 双向绑定:数据能够影响页面,页面更新也能够影响数据 -->
<!-- <input type="text" model:value="{{value}}" /> -->
<!-- 如果需要获取复选框的选中效果,需要给checked 添加model: -->
<!-- <checkbox model:checked="{{isChecked}}">是否同意该协议</checkbox>{{isChecked}} -->
Page({
//在小程序页面中所需要使用的数据均来自于data对象
data: {
value: 123,
isChecked:false
}
})
wxml-列表渲染-基本使用
列表渲染就是指通过循环遍历一个数组或对象,将其中的每个元素渲染到页面上
在组件上使用wx:for 属性绑定一个数组或对象,即可使用每一项数据重复渲染当前组件
每一项的变量名默认为item,下标变量名默认为index
在使用wx:for进行遍历的时候,建议加上wx:key属性,wx:key的值以两种形式提供:
- 字符串:代表需要遍历的array中的item的某个属性,该属性的值需要是列表中唯一的字符串或数字,其不能动态改变
- 保留关键字*this代表在for循环中的item本身,当item本身是一个唯一的字符串或者数字时可以使用
注意事项
- 如果不加wx:key,会报一个warning,如果明确知道该列表是静态,及以后数据不会改变,或者不必关注其顺序,可以选择忽略。
- 在给wx:key添加属性值的时候,不需要使用双大括号语法,直接使用遍历的array中item的某个属性
<view wx:for="{{list}}" wx:key="index">{{item}}</view>
wxml-列表渲染-进阶用法
1.如果需要对默认的变量名和下标进行修改,可以使用wx:for-item 和 wx:for-index
- 使用wx:for-item可以指定数组当前元素的变量名
- 使用wx:for-index可以指定数组当前下标的变量名
2.将wx:for用在<block/>标签上,以渲染一个包含多个节点的结构块
- <block/>并不是一个组件,它仅仅是一个包装元素,不会在页面中做任何渲染,只接受控制属性
- <block/>标签在wxml中可以用于组织代码结构,支持列表渲染、条件渲染等。
<view wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i"> {{fruitItem.name}}{{i}} </view> <view wx:for="{{obj}}" wx:key="key" wx:for-item="objItem" wx:for-index="key"> {{objItem}}{{key}} </view> <block wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i"> <view>名字:{{fruitItem.name}}</view> <view>价格:{{fruitItem.price}}</view> </block>
wxml语法-条件渲染
条件渲染主要用来控制页面结构的展示和隐藏,在微信小程序中实现条件渲染有两种方式:
1.使用wx:if、wx:elif、wx:else 属性组
2.使用hidden属性
wx:if和hidden二者的区别
- wx:if:当条件为true时将结构展示出来,否则结构不会进行展示,通过移除/新增节点的方式来实现
- hidden:当条件为true时将结构隐藏,否则结构会展示出来,通过display样式属性来实现的
生命周期-小程序运行机制
生命周期-小程序更新机制
// app.js
App({
//onLaunch 是小程序的钩子函数,这个钩子函数在冷启动时肯定会执行到
//当小程序冷启动时,会自动微信后台请求新版本的信息,如有新版本,会立即进行下载
onLaunch(){
// 使用 wx.getUpdateManager 方法监听下载的状态
const updateManager = wx.getUpdateManager()
// 当下载完成新版本以后,会触发onUpdateReady 回调函数
updateManager.onUpdateReady(function(){
// 在回调函数中给用户提示
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用',
complete: (res) => {
if (res.confirm) {
//强制当前小程序使用新版本并且会重启当前小程序
updateManager.applyUpdate()
}
}
})
})
}
})
微信开发者工具可以模拟强制更新
先在编译模式这里添加编译模式=》然后保存刷新即可
生命周期-小程序生命周期介绍
应用生命周期是指应用程序进程从创建到消亡的整个过程
小程序的生命周期指的是小程序从启动到销毁的整个过程
一个小程序完整的生命周期由 应用生命周期、页面生命周期、和组件生命周期三部分来组成
小程序生命周期伴随着一些函数,这些函数由小程序框架本身提供,被称为生命周期函数,生命周期函数会按照顺序依次自动触发调用。帮助程序员在特定的时机执行特定的操作,辅助程序员完成一些比较复杂的逻辑。
生命周期-应用生命周期
应用生命周期通常是指一个小程序从启动=>运行=>销毁的整个过程
应用生命周期伴随着一些函数,我们称为应用生命周期函数,应用生命周期函数需要在app.js文件的App()方法中进行定义,App()方法必须在app.js中进行调用,主要用来注册小程序。
应用生命周期函数由 onLaunch、onShow、onHide三个函数组成
// app.js
App({
/**
* 当小程序初始化完成时,会触发onLaunch(全局只触发一次)
*/
onLaunch(){
//当进行冷启动时,才会触发 onLaunch 钩子函数
// 如果是热启动,不会触发,onLaunch 钩子函数,会触发 onShow 钩子函数
//因此呢 onLaunch (全局只触发一次)
console.log('onLaunch 小程序初始化完成时')
},
/**
* 当小程序启动,或从后台进入前台显示会触发onShow
*/
onShow(){
console.log('onShow 小程序启动,或从后台进入前台显示会触发')
},
/**
* 当小程序从前台台进入后台显示会触发onHide
*/
onHide(){
console.log('onHide 当小程序从前台台进入后台显示会触发')
}
})
生命周期-页面生命周期
页面生命周期就是指小程序页面从 加载=>运行=>销毁 的整个过程
页面生命周期函数需要在Page()方法进行定义
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载 --一个页面只会调用一次
*/
onLoad(options) {
console.log('onLoad 页面创建的时候执行')
},
/**
* 生命周期函数--监听页面初次渲染完成 --一个页面只会调用一次
*/
onReady() {
console.log('onReady 页面初次渲染完成,代表页面已经准备妥当,可以和视图层进行交互')
},
/**
* 生命周期函数--监听页面显示 -从后台进入前台也会触发
*/
onShow() {
console.log('onShow 页面在前台展示的时候')
},
/**
* 生命周期函数--监听页面隐藏 -在当前小程序进入后台时,也会触发执行
*/
onHide() {
console.log('onHide 页面隐藏')
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
console.log('onUnload 页面卸载,销毁')
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
生命周期-生命周期两个细节补充
- tabBar 页面之间相互切换,页面不会被销毁
- 点击左上角,返回上一个页面,会销毁当前页面
小程序API-小程序API介绍
小程序API-网络请求
发起网络请求回去服务器的数据,需要使用wx.request()接口API
wx.request请求的域名必须在微信公众平台进行配置,如果使用wx.request请求未配置的域名,在控制台会有相应的报错。
可以测试这个接口地址 :https://gmall-prod.atguigu.cn/mall-api/index/findBanner
//如果需要发起网络请求,需要使用wxwx.request API
wx.request({
//接口地址
url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
//请求方式
method: 'GET',
//请求参数
data: {},
//请求头
header: {},
// API调用成功后的回调
success: (res) => {
if(res.data.code ===200){
this.setData({
list:res.data.data
})
console.log(this.data.list)
}
},
// 失败的回调
fail: (err) => {
console.error(err)
},
// API 不管调用成功还是失败以后,执行的回调
complete: () => {}
})
小程序API-界面交互-loading提示框
小程序提供了一些用于界面交互的API,例如:loading提示框、消息提示框、静态对话框等API
loading提示框常配合网络请求来使用,用于增加用户体验,对应的API有两个:
- wx.showLoading()显示loading提示框
- wx.hideLoading()关闭loading提示框
//显示loading 提示框
wx.showLoading({
//用来显示提示的内容
//提示的内容不会自动换行,如果提示的内容比较多,因为在同一行显示
//多出来的内容就会被隐藏
title: '数据正在加载中...',
// 是否展示透明蒙层,防止触摸穿透
mask:true,
})
小程序API-界面交互-模态对话框-消息提示框
wx.showModal() : 模态对话框,常用于用户是否执行一些操作
例如:询问用户是否退出登录、是否删除商品等
wx.showToast() 消息提示框,根据用户的某些操作来告知操作的结果
例如:退出成功给用户提示,提示删除成功等
async delHandler(){
const res = await wx.showModal({
title: '是否删除商品',
content: '羽毛球',
})
if(res.confirm){
// showToast 消息提示框
wx.showToast({
title: '删除成功',
icon:'none',
duration:2000
})
}else{
wx.showToast({
title: '取消删除',
icon:'error',
duration:2000
})
}
}
小程序API-本地存储
小程序本地存储是指在小程序中使用API将数据存储在用户的设备上,以便小程序运行时和下次启动时快速地读取这些数据
//将数据存到本地
setstorage(){
//第一个参数:本地存储中指定的key
//第二个参数:需要存储的数据
//wx.setStorageSync('num',1)
//在小程序中
//如果存储的是对象类型数据,不需要使用JSON.stringify 和JSON.parse 进行转换
//直接进行存储和获取即可
// wx.setStorageSync('obj', {
// name:'tom',
// age:10
// })
//---异步API
wx.setStorage({
key:'num',
data:1
})
wx.setStorage({
key:'obj',
data:{
name:'jerry',
age:18
}
})
},
async getstorage(){
//从本地存储的数据中获取 key 的数据
// const num =wx.getStorageSync('num')
// const obj =wx.getStorageSync('obj')
//---异步API
const num = await wx.getStorage({
key:'num'
})
const obj = await wx.getStorage({
key:'obj'
})
console.log(num,obj)
},
delstorage(){
//从本地移除指定key的数据,内容
// wx.removeStorageSync('num')
//---异步API
wx.removeStorage({
key:'num'
})
},
clearstorage(){
//清空本地存储的全部数据
//wx.clearStorageSync()
//---异步API
wx.clearStorage()
}
小程序API-路由与通信
在小程序中实现页面的跳转,有两种方式:
- 声明式导航:navigator组件
- 编程式导航:使用小程序提供的API
小程序API-页面处理函数-上拉加载
上拉加载是小程序中常见的一种加载方式,当用户滑到页面底部时,会自动加载更多的内容,以便用户继续浏览
小程序中实现上拉加载的方式
- 在app.json 或者 page.json 中配置距离页面底部距离:onReachBottomDistance;默认50px
- 在页面.js中定义onReachBottom事件监听用户上拉加载
小程序API-页面处理函数-下拉刷新
下拉刷新是小程序中常见的一种刷新方式,当用户下拉页面时,页面会自动刷新,以便用户获取到最新的内容。
小程序中实现下拉刷新的方式
- 在app.json或者page.json中开启允许下拉,同时可以配置 窗口、loading 样式等
- 在页面.js中定义 onPullDownRefresh 事件监听用户下拉刷新
自定义组件-创建-注册-使用组件
小程序目前已经支持组件化开发,可以将页面中功能模块抽取成自定义组件,以便在不同的页面中重复使用;也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护。
开发中常见的组件有两种:
- 公共组件:将页面内的功能模块抽取成自定义组件,以便在不同的页面中重复使用。
- 页面组件:将复杂的页面拆分成多个低耦合的模块,有助于代码维护
如果是公共组件,建议放在项目根目录的components文件夹中
如果是页面组件,建议放在对应页面的目录下
建议:一个组件一个文件夹
开发中常见的组件分为公共组件和页面组件两种,因此注册组件的方式也分为两种:
- 全局注册:在app.json文件中配置usingComponents进行注册,注册后可以在任意页面使用
- 局部注册:在页面的json文件中配置usingComponents进行注册,注册后只能在当前页面使用
在usingComponents中进行组件注册时,需要提供自定义组件的组件名和自定义组件文件路径
在将组件注册后以后,直接将 自定义组件的组件名当成组件标签名使用即可
自定义组件-组件的数据以及方法
组件数据和方法需要在.js的component方法中进行定义,component创建自定义组件
- data:定义组件的内部数据
- methods:在组件中事件处理程序需要写到methods方法中才可以
自定义组件-组件的属性
Properties是指组件的对外属性,主要用来接收组件使用者传递租界内内部的数据,和data一同用于组件的模板渲染
组件注册完成后使用,这边的数据有点类似与vue中的父传子
然后在组件的.js文件中,接收
然后就直接在组件页面元素上直接用就可以了
注意事项:
设置类型属性需要使用type属性,属性类型是必填项,value属性为默认值
属性类型可以为String、Number、Boolean、Object、Array,也可以为null表示不限制类型
自定义组件-组件wxml的slot-插槽
按照一下用法使用即可
自定义组件-组件样式以及注意事项
自定义组件拥有自己wxss样式,组件wxss文件的样式,默认只对当前组件生效。
自定义组件-组件样式隔离
自定义组件-数据监听器
数据监听器主要用于监听和响应任何属性(properties)和数据(data)的变化,当数据发生变化时就会触发对应回调函数,从而方便开发者进行业务逻辑的处理
在组件中如果需要进行数据监听 需要使用observers字段
用法如下
<view>{{num}}</view>
<view>{{count}}</view>
<view>{{obj.name}}</view>
<view>{{arr[1]}}</view>
<view>{{label}}</view>
<button type="warn" plain bind:tap="updateDate">
更改数据
</button>
// components/custom04/custom04.js
Component({
/**
* 组件的属性列表
*/
properties: {
label:{
type:String,
value:'测试'
}
},
/**
* 组件的初始数据
*/
data: {
num: 10,
count: 100,
obj: {
name: 'Tom',
age: 10
},
arr: [1, 2, 3]
},
//用来监听数据变化
observers: {
//key :需要监听的数据
//value :就是一个回调函数、形参:最新的参数
// num:function(newNum){
// // 对data中的数据进行监听,如果数据没有发生变化,监听不会执行
// console.log('变化了',newNum)
// },
// count:function(newCount){
// console.log(newCount)
// }
//同时监听多个
// 'num,count': function (newNum, newCount) {
// console.log(newNum, newCount)
// }
//支持监听属性以及内部数据的变化
// 'obj.name': function (newObjName) {
// console.log(newObjName)
// },
// 'arr[1]':function(newItem){
// console.log(newItem)
// }
//使用通配符
// 'obj.**':function(newObj){
// console.log(newObj)
// }
label:function(newLabel){
//主要使用者传递了数据,这时在监听器中就能获取的数据
// 也就是说,监听器立即就执行了
console.log(newLabel)
}
},
/**
* 组件的方法列表
*/
methods: {
//更改数据
updateDate() {
this.setData({
num: this.data.num + 1,
// count: this.data.count - 1
// 'obj.name': 'jerry',
// 'arr[1]': '4'
})
}
}
})
自定义组件-组件通信-父往子传值
自定义组件-组件通信-子传父
子组件如果需要向父组件传递数据,可以通过小程序提供的事件系统实现,可以传递任意数据。
- 自定义组件内部使用triggerEvent方法发射一个自定义的事件,同时可以携带任意数据
- 自定义组件标签上通过bind方法监听发射的事件,同时绑定事件处理函数,在事件函数中通过事件对象获取传递的数据
子组件
<button type="primary" plain bind:tap="sendData">传递数据</button>
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
num:666
},
/**
* 组件的方法列表
*/
methods: {
//传递数据给父组件
sendData(){
//如果需要将数据传递给父组件
//需要使用 triggerEvent 发射自定义事件
//第二个参数,是携带的参数
this.triggerEvent('myevent',this.data.num);
}
}
})
父组件
<view>{{num}}</view>
<!-- 需要在自定义组件标签上通过 bind方法绑定自定义事件,同时绑定事件处理函数 -->
<custom05 bind:myevent="getData"></custom05>
Page({
data:{
num:''
},
getData(event){
//可以通过事件对象.detail 获取子组件传递给父组件的数据
console.log(event)
this.setData({
num:event.detail
})
}
})
自定义组件-组件通信-获取组件实例
父组件可以通过 this.selectComponent方法,获取子组件实例对象,这样就可以直接访问子组件的任意数据和方法
this.selectComponent 方法在调用时需要传入一个匹配选择器 selector
首先在子组件上添加class或者id
<custom05 bind:myevent="getData" class="child" id="child"></custom05>
然后在父组件上操作即可
<button type="primary" plain bind:tap="getChild">获取子组件的实例对象</button>
// pages/cart/cart.js
Page({
data:{
},
getChild(){
const res = this.selectComponent('.child')
console.log(res)
}
})
这样就可以获取到子组件的实例对象了。
自定义组件-组件生命周期
组件的生命周期:指的是组件自身的一些钩子函数,这些函数在特定的时间节点时被自动触发
组件的生命周期函数需要在 lifetimes字段内进行声明
组件的生命周期函数有5个:created、attached、ready、moved、detached
// components/custom06/custom06.js
Component({
data:{
name:'tom'
},
//组件生命周期声明对象
lifetimes:{
// created:组件实例被创建好以后执行
created(){
console.log('组件 created')
//所以载cerated 钩子函数中不能调用setdata
//可以给组件添加一些自定义的属性,可以通过this的方式进行添加
this.test = '测试'
// this.setData({
// name:'jerry'
// })
},
//attached:组件初始化完毕,模板解析完成,已经把组件挂载到页面上
attached(){
console.log('组件 attached')
console.log(this.test)
//一般页面中的交互会在attached 钩子函数中进行执行
this.setData({
name:'jerry'
})
},
//组件被销毁
detached(){
console.log('组件 detached')
}
}
})
自定义组件-组件所在页面的生命周期
// components/custom06/custom06.js
Component({
data:{
name:'tom'
},
// 组件所在页面的生命周期
pageLifetimes:{
//监听组件所在的页面展示(后台切前台)状态
show(){
console.log('组件所在的页面被展示')
},
//监听组件所在的页面隐藏(前台切后台,点击tabBar)状态
hide(){
console.log('组件所在的页面被隐藏')
}
}
})
自定义组件-小程序生命周期总结
自定义组件-使用Component构造页面
简而言之就是用构建组件的Component 方法来替换掉page 方法,相比于page来说,Component 提供的方法更多
1.正常新建页面
2.然后将page方法改成Component 在 detail.js中
Component({
// 为什么需要使用 Component 方法进行构造页面
//Component 方法功能比Page方法强大很多
//如果使用Component 方法构造页面,可以实现更加复杂的页面逻辑开发
//小程序页面也可以使用Component方法进行构造
//注意事项:
//1.要求.json文件中必须包含usingComponents字段
//2.里面的配置项需要和 Component中的配置项保持一致
//3.页面中Page方法有一些钩子函数,时间监听方法,这些钩子函数、事件监听方法必须放在methods对象中
//4.组件的属性 properties 也可以接收页面的参数,在onLoad 钩子函数中可以通过this.data 进行获取
properties:{
id:String,
title:String
},
data: {
name: 'tom'
},
methods: {
//更新name
updateName() {
this.setData({
name: 'jerry'
})
},
onLoad(options){
// console.log('页面创建',options)
console.log(this.data.id)
console.log(this.data.title)
}
}
})
3.datail.json 中必须要有 usingComponents
{
"usingComponents": {}
}
4.从其他页面传递过来的参数现在就可以有联众方式接收
1. 组件的properties方法
2.生命周期onLoad 函数
<navigator url="/pages/detail/detail?id=10&title=测试">跳转到详情页面</navigator>
自定义组件-拓展:组件复用机制behaviors
const behavior = Behavior({
/**
* 组件的属性列表
*/
properties: {
label:{
type:String,
value:'我已同意该协议'
}
},
/**
* 组件的初始数据
*/
data: {
name:'Tom',
obj:{
name:'Tyke'
}
},
/**
* 组件的方法列表
*/
methods: {
updateName(){
this.setData({
name:'Jerry'
})
}
},
lifetimes:{
attached(){
console.log('我是组件behavior生命周期函数')
}
}
})
export default behavior;
// components/custom08/custom08.js
import behavior from './behavior'
Component({
behaviors:[behavior],
//在以后开发中,使用 behaviors 进行代码复用的时候
//组件和 behaviors 可能存在相同字段
//如果存在相同的properties,就近原则,使用组件内部的数据
properties:{
label:{
type:String,
value:'匿名提交'
}
},
//如果存在相同的data
//如果是对象类型,属性会进行合并
//如果不是对象类型的数据,就近原则,展示的以组件内部为准
data:{
name:'组件中的name',
obj:{
name:'组件中的name',
age:100
}
},
//如果存在相同的方法,就近原则,使用组件内部的方法
methods:{
updateName(){
console.log('我是组件内部的方法!!!')
}
},
//如果存在相同的生命周期函数,生命周期函数都会被触发
lifetimes:{
attached(){
console.log('我是组件内部的生命周期函数')
}
}
})
自定义组件-拓展:外部样式类
这样就能在外面修改组件的样式了。
自定义组件-总结自定义组件
npm支持-如何使用npm包
目前小程序已经支持使用npm安装第三方包,因为node_modules目录中的包不会参与小程序项目的编译、上传和打包,因此在小程序项目中要使用npm包,必须走一遍构建npm的过程。
在构建成功以后,默认会在小程序项目根目录,
也就是 node_modules同级目录下生成miniprogram_npm目录,
里面存放着构建完成以后的npm 包,也就是小程序运行过程中真正的包
vant微信小程序版https://vant-ui.github.io/vant-weapp/
以vant 为例 先安装 ,安装好后就会有node_modules 目录,然后再到工具=>构建npm =>就会生成
miniprogram_npm目录
这边要注意安装的时候可能会报错,退出微信小程序开发工具,然后以管理员身份运行应该就可以解决了。
注意事项:
小程序运行在微信内部,因为运行环境的特殊性,这就导致并不是所有的包都能够在小程序使用
我们在小程序中提到的包指专为小程序定制的npm 包,简称小程序包 npm 包,在使用包之前需要先确定改包是否支持小程序
开发者如果需要发布小程序包,需要参考官方规范
npm支持-自定义构建npm
在实际的开发中,随着项目的功能越来越多、项目越来越复杂、文件目录也越来越繁琐,为了方便进行项目的开发,开发人员通常会对目录结构进行调整优化,例如:将小程序源码放miniprogram 目录下
这时候就需要开发者在project.config.json中 指定node_modules的位置和目标miniprogram_npm 的位置
具体配置如下
- 配置project.config.json的miniprogramRoot指定小程序源码的目录
- 配置project.config.json的setting.packNpmManually为true,开启自定义node_modules的位置和目标miniprogram_npm 位置 的构建 npm方式
- 配置project.config.json的setting.packNpmRelationList项,指定package.JsonPath和miniprogramNpmDistDir的位置
npm支持-vant weapp组件库的使用
在使用vant提供的组件时,只需要两个步骤:
- 将组件在app.json中进行全部注册或者index.json中进行局部注册
- 在引入组件后,可以直接在wxml中直接使用组件
注意事项:
将app.json中的style:v2去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱。
npm支持-vant weapp组件样式覆盖
vant weapp基于微信小程序的机制,为开发者提供了3种修改组件样式的方法
- 解除样式隔离:在页面中使用vant组件时,可直接在页面的样式文件中覆盖样式
- 使用外部样式类:需要注意的是普通央视和外部样式类的优先级是未定义的,使用时需要添加 !important保证外部样式的优先级
- 使用css变量:在页面或全局对多个组件的样式做批量修改以进行主题样式的定制
分包加载-小程序分包加载
分包加载-配置分包加载以及打包、引用原则
小程序如果需要进行分包加载,需在app.json中,通过 subPackages或者subpackages定义分包结构
每个分包结构含三个常用字段:
- root:分包的根目录,该目录下的所有文件都会被打包成一个独立的包
- name:分包的别名,用于在代码中引用该分包
- pages:指定当前分包中包含那些页面
例如:配置商品模块分包,分包包含:商品列表、商品详情两个页面
分包加载-独立分包
分包加载-分包预下载
开放能力-获取微信头像
<view>
<button class="btn" open-type="chooseAvatar" bindchooseavatar="chooseavatar">
<image class="avatar" src="{{avatarUrl}}" mode="aspectFill"></image>
</button>
</view>
// index.js
Page({
//在小程序页面中所需要使用的数据均来自于data对象
data: {
avatarUrl:'../../assets/banner/banner.jpg'
},
//获取微信头像
chooseavatar(event){
console.log(event)
const {avatarUrl} = event.detail;
this.setData({
avatarUrl
})
}
})
.btn{
background-color: transparent;
}
.btn::after{
border: none;
}
.avatar{
width: 200rpx;
height: 200rpx;
border-radius: 50%;
}
开放能力-获取微信昵称
<form bindsubmit="onSubmit">
<input type="nickname" name="nickname" placeholder="请输入昵称" />
<button type="primary" plain form-type="submit">点击获取昵称</button>
</form>
// index.js
Page({
//在小程序页面中所需要使用的数据均来自于data对象
data: {
},
//获取微信昵称
onSubmit(event){
console.log(event)
}
})
input{
border: 1px solid #179c16;
margin: 20rpx ;
height: 60rpx;
border-radius: 20rpx;
padding-left: 20rpx;
}
开放能力-转发功能
// pages/cate/cate.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage(obj) {
console.log(obj)
return{
title:'这是一个非常神奇的页面',
path:'/pages/cate/cate',
imageUrl:'../../assets/banner/banner.jpg'
}
}
})
<button open-type="share">转发</button>
开放能力-分享到朋友圈
开放能力-手机号验证组件
<button type="primary" open-type="getPhoneNumber" bindgetphonenumber="getphonenumber">快速验证组件</button>
<button type="warn" plain open-type="getRealtimePhoneNumber" bingetrealtimephonenumber="getrealtimephonenumber">实时验证组件</button>
// pages/cart/cart.js
Page({
data:{
num:''
},
// 手机号快速验证
getphonenumber(event){
//通过事件对象,可以看到,在event.detail中可以获取到code
//code动态令牌,可以使用code换取用户手机号
//需要将code发送给后端,后端在接收到code以后
//也需要调用API,换取用户的真正手机号
//再会将手机号返回给前端
console.log(event)
},
//手机号实时验证
getrealtimephonenumber(event){
console.log(event)
}
})
个人开发者账号没办法使用,会提示没有权限。
开放能力-客服功能
补充-框架接口-getApp()
App.js
// app.js
App({
//全局共享的数据
globalData:{
token:''
},
//全局共享的方法
setToken(token){
//如果想获取token,可以使用this的方式进行获取
this.globalData.token = token;
//在 App() 方法中如果想获取实例,直接通过this就可以获取到
}
})
其他页面使用
<button type="primary" plain bind:tap="login">登录</button>
//getApp() 方法用来获取全局唯一的App()实例
const appInstance = getApp()
Page({
data:{
num:1,
},
login(){
// console.log(appInstance)
appInstance.setToken('hdhhhdhdhhhdhdh')
}
})
补充-页面间通信
当前页面
<button type="warn" plain bind:tap="handler">跳转到列表页面</button>
// index.js
Page({
//点击按钮触发的事件处理函数
handler(){
wx.navigateTo({
url: '/pages/list/list',
events:{
//key 被打开页面通过 EventChannel 发射的事件
//value 回调函数
//为事件添加一个监听器,获取到被打开页面传递给当前页面的数据
currentevent:(res)=>{
console.log(res)
}
},
success(res){
console.log(res)
//通过success 回调函数的形参,可以获取eventChannel 对象
//eventChannel 对象给提供了emit 方法,可以发射事件,同时携带参数
res.eventChannel.emit('myevent',{
name:'tom'
})
}
})
}
})
跳转页面
// pages/list/list.js
Page({
onLoad(){
//通过 this.getOpenerEventChannel() 可以获取 EventChannel 对象
const EventChannel= this.getOpenerEventChannel()
//通过 EventChannel 提供的 on 方法 监听页面发射的自定义事件
EventChannel.on('myevent',(res)=>{
console.log(res)
})
//通过 EventChannel 提供的 emit 方法也可以向上一级页面传递数据
//需要emit定义自定义事件,携带需要传递的参数
EventChannel.emit('currentevent',{age:10})
}
})
补充-组件通信-事件总线
1.先安装 pubsub.js这个包
npm install pubsub-js
这边要注意!!!! 微信开发者工具可能会由于权限问题报错,可以先退出一下然后使用管理员身份运行,在安装就可以了
2.安装好包后,记得在工具中构建下npm
组件a 代码
<view class="a">
子组件a
<button bind:tap="sendData">传递数据给兄弟</button>
</view>
import PubSub from 'pubsub-js'
Component({
data:{
name:'TOM'
},
/**
* 组件的方法列表
*/
methods: {
sendData(){
// publish 发布,发射自定义事件
//1.自定义事件的名称
//2.需要传递的数据
PubSub.publish('myevent',{
name:this.data.name,
age:10
})
}
}
})
组件b接收兄弟组件a传递的数值
<view class="b">
子组件b 收到的参数为
<view>{{name}}</view>
</view>
// components/custom04/custom04.js
import PubSub from 'pubsub-js'
Component({
/**
* 组件的初始数据
*/
data: {
name:''
},
/**
* 组件的方法列表
*/
methods: {
},
lifetimes:{
attached(){
//subscribe 订阅、监听自定义的事件
//1.需要订阅、监听的自定义事件名称
//2.回调函数,回调函数有两个参数
// msg 自定义事件的名称
// data 传递过来的数据
PubSub.subscribe('myevent',(msg,data)=>{
console.log(msg,data)
this.setData({
name:data.name
})
})
}
}
})