- 发请求语法
wx.request({
url: '请求地址',
method: '请求方式',
data: {
// 请求携带的参数,不管是get还是post都是写这里
},
success: res => {
// 成功调用
},
fail: err => {
// 失败调用
},
complete: () => {
// 不管成功还是失败都调用
}
})
- 发请求前,一定要把域名设置到微信开发者后台才可以
- 接口必须是https协议头
- 在开发阶段可以临时跳过这些校验,但是正式上线必须设置,否则无法正常使用
- window的一些配置
"window": {
"navigationBarBackgroundColor": "导航条背景颜色",
"navigationBarTitleText": "导航栏标题",
"navigationBarTileStyle": "文字颜色,只有black和white可以选",
"backgroundColor": "下拉的背景颜色",
"backgroundTextStyle": "下拉的指示器的颜色,只有light和dark可以选"
}
- tabbar如何配置-跟window平级
"tabbar": {
"color": "默认文字颜色",
"selectedColor": "选中的文字颜色"
"list": [
{
"text": "标题",
"iconPath": "图标",
"selectedIconPath": "选中的图标",
"pagePath": "对应的页面路径"
}
]
}
- 配置下拉刷新,全局就是写到
window
里
"enablePullDownRefresh": true
- 写到全局里代表所有页面都有下拉,但是下拉这个功能一般只是某些页面用,所以应该写到局部(某个页面对应的json文件),写法跟上面一样,但是不用写
window
- 如果下拉会触发一个钩子
onPullDownRefresh () {
}
- 如果想手动停止下拉调用
wx.stopPullDownRefresh()
- 小程序默认可以上拉触底,但是要保证内容超过1屏,自动会触发,默认设置距离底部50触发,触发会调用一个钩子
onReachBottom () {
}
- 也可以设置上拉触底的距离,全局就写到window里,局部就去掉window
"onReachBottomDistance": 距离
- 导航到tabbar页面
<navigator url="tabbar页面路径" open-type="switchTab"></navigator>
wx.switchTab({
url: '路径'
})
- 导航到tabbar页面,不能通过网址传参
案例:本地生活-详情页与跳转
- 接口地址:https://applet-base-api-t.itheima.net/categories/:cate_id/shops
- 请求方式:GET
- 请求参数:
- _page 表示请求第几页的数据
- _limit 表示每页请求几条数据
详情页布局
- 每一个商家就是一个view,然后分为一左一右,左边图片,右边又是个view,右边的view里放四行view
<view>
<view wx:for="1111" class="shop-item">
<image mode="aspectFill" src="../../images/link-01.png"></image>
<view class="detail">
<view class="title">宫廷月亮虾饼</view>
<view class="phone">电话: 155-3071-0686</view>
<view class="addr">地址:深圳市XXXXXXXXX</view>
<view class="time">营业时间:周一到周日,全年无休</view>
</view>
</view>
</view>
.shop-item {
display: flex;
align-items: center;
}
.shop-item image {
width: 250rpx;
height: 250rpx;
margin: 0 10px;
}
.detail {
flex: 1;
}
.detail .title {
font-weight: 700;
font-size: 18px;
}
.detail view {
margin-top: 10px;
font-size: 14px;
}
点击跳转到详情页并携带id和查出数据
- 来到
home
给九宫格的每个盒子加点击事件,需要携带当前的数据
<view class="grid-box">
<view wx:for="{{ gridList }}" wx:key="id" class="grid-item" mark:item="{{item}}" bindtap="toList">
<image mode="widthFix" src="{{ item.icon }}"></image>
<view>{{ item.name }}</view>
</view>
</view>
// 点击跳转
toList(e) {
// 拿到参数
// console.log(e.mark.item)
wx.navigateTo({
url: '/pages/list/list?id=' + e.mark.item.id,
})
},
- 回到
list
页面,在onLoad里拿到参数,并存起来,但是存的id不用渲染,可以声明成纯数据字段。然后再准备一个发请求的代码,调用拿到数据存起来
data: {
_id: 0,
list: []
},
options: {
pureDataPattern: /^_/
},
/**
* 生命周期函数--监听页面加载
*/
onl oad(options) {
// console.log(options)
// 发请求获取数据
this.data._id = options.id
this.getList()
},
getList() {
wx.request({
url: `https://applet-base-api-t.itheima.net/categories/${this.data._id}/shops`,
data: {
_page: 1,
_limit: 10
},
success: res => {
this.setData({
list: res.data
})
}
})
}
- 去渲染到页面
<view>
<view wx:for="{{ list }}" wx:key="id" class="shop-item">
<image mode="aspectFill" src="{{ item.images[0] }}"></image>
<view class="detail">
<view class="title">{{ item.name }}</view>
<view class="phone">电话: {{ item.phone }}</view>
<view class="addr">地址:{{ item.address }}</view>
<view class="time">营业时间:{{ item.businessHours }}</view>
</view>
</view>
</view>
完成上拉加载更多页
- 如果要加载更多页,就意味着发请求时,页码不能写死
1
,如果写死1
,永远只能加载第一页,所以用一个变量来记录和控制,而这个变量不需要渲染,所以可以声明成纯数据字段
data: {
_page: 1
}
- 发请求时使用
_page
作为页码,并且在请求成功后要让页码+1
getList() {
wx.request({
url: `https://applet-base-api-t.itheima.net/categories/${this.data._id}/shops`,
data: {
_page: this.data._page,
.........
},
success: res => {
// 每加载完一页,就让页码+1,方便查出下一页
this.data._page++
.......
}
})
},
- 监听下拉触底,在下拉触底里调用发请求的方法
onReachBottom () {
this.getList()
}
- 优化提示,发请求前弹出加载中,请求完成就关掉弹出的提示
getList() {
wx.showLoading({
title: '加载中'
})
wx.request({
url: `https://applet-base-api-t.itheima.net/categories/${this.data._id}/shops`,
data: {
.........
.........
},
success: res => {
......
.......
},
complete: () => {
wx.hideLoading()
}
})
},
完成节流阀
- 先声明个变量记录当前有没在加载数据
data: {
_isLoading: false
}
- 发请求之前把节流阀改为true,代表当前正在加载,等请求结束,把节流阀改为false,代表可以新的请求
getList() {
this.data._isLoading = true
.......
wx.request({
url: `https://applet-base-api-t.itheima.net/categories/${this.data._id}/shops`,
data: {
.........
.........
},
success: res => {
......
.......
},
complete: () => {
......
this.data_isLoading = false
}
})
},
- 在下拉触底里要判断,如果为true,代表当前还有个请求没完成正在加载,所以就直接return
onReachBottom () {
if (this.data_isLoading) return
this.getList()
}
完成下拉刷新
- 因为下拉只要
list
页面有下拉,所以来到list.json
开启下拉,并设置样式
"enablePullDownRefresh": true,
"backgroundColor": "#ddd",
"backgroundTextStyle": "dark"
- 然后监听下拉事件,因为下拉要刷新重新加载最新数据,所以需要在下拉里把页码改成1,并把数组清空再重新调用发请求的方法
onPullDownRefresh() {
this.data._page = 1
this.setData({
list: []
})
this.getList()
},
- 最后再请求完成的回调里手动停止下拉的动画
wx.stopPullDownRefresh()
wxs介绍 - 为什么需要用wxs
- 小程序里无法在结构中
wxml
中调用js
里声明的函数 - 但是很多时候,我们确实有需要调用函数的需求,所以为了解决这种你需要在
wxml
中调用函数的场景,微信提供了一种脚本叫wxs
- 什么叫
wxs
?- 微信script
- 它相当于是一门微信创造的独立的脚本语言(js也是一种脚本语言)
- 它专门用来上面的需求:封装一函数,这些函数可以在
wxml
中直接调用 - 特点:
- 跟js的语法非常相似(方便前端开发者可以快速上手),甚至可以说语法一模一样
- 最大的区别在于:wxs不能用es6的那些新语法
wxs的内嵌写法
- 内嵌写法是指写到
wxml
里面 - 语法是
<wxs module="名字">
// 声明函数
module.exports = {
暴露的名字: 对应的函数名
}
</wxs>
- 例
<wxs module="m1">
// 声明函数
function toUpper (str) {
return str.toUpperCase()
}
module.exports = {
toUpper: toUpper
}
</wxs>
- 用法
m1.toUpper(传入字符串)
wxs的外联写法
- 先准备一个独立的
wxs
文件,在里面写代码,例 - 创建了一个文件叫
tool.wxs
,代码如下
function toLower(str) {
return str.toLowerCase()
}
module.exports = {
toLower: toLower
}
- 在需要用的地方,做导入
<wxs module="m2" src="wxs的路径"></wxs>
- 用法
m2.方法名()
wxs和js语法的不同点
- 大部分基础语法是一样的
- 核心是:es6的语法在wxs通通不能用
- 例如:let、const、模板字符串、简写等等都不能用
- wxs里的正则写法跟js的不一样,wxs的正则如下编写
var reg = getRegExp('正则内容')
使用wxs处理电话号码
- 因为wxs也建议最好用外联写法, 所以来到
项目根目录
新建utils
文件夹,里面新建phone.wxs
文件,在里面封装一个处理手机号格式的函数,并暴露出去
function formatPhone(str) {
// 先要判断传进来的是不是手机号
// wxs不能用js里的正则写法
var reg = getRegExp('^1[3-9]\d{9}$')
if (reg.test(str)) {
// 就要做格式处理
// 截取出手机号的前3位
var str1 = str.substring(0, 3)
// 截取出手机号的中间4位
var str2 = str.substring(3, 7)
// 截取出手机号的后面4位
var str3 = str.substring(7)
return str1 + '-' + str2 + '-' + str3
} else {
// 不是手机号,原样返回
return str
}
}
module.exports = {
formatPhone: formatPhone
}
- 然后来到
list
页面,导入这个wxs并使用到手机号那一个view上
<wxs module="m1" src="../../utils/phone.wxs"></wxs>
<view class="phone">电话: {{ m1.formatPhone(item.phone) }}</view>
- 知识点:
- wxs里要写正则,不能用js的写法, 要用
getRegExp('正则规则')
这种写法
- wxs里要写正则,不能用js的写法, 要用
生命周期介绍
- 生命周期:指的是从创建到销毁经历的一系列阶段
- 小程序里生命周期有三大类:
- 应用的生命周期
- 页面的生命周期
- 组件的生命周期
应用的生命周期函数
- 提示:
- 可以写一个
App
按回车,自动生成,而且还带注释,清晰的告诉你什么阶段调用的 - onLaunch
- 应用打开时并初始化完成调用,这里可以做一些初始化的工作,例如读取出之前保存的数据
- onShow
- 第一次显示时调用,或者从后台重新进入到前台调用
- onHide
- 从前台进入到后台时调用(前台到后台指的是切出去了)
- onError
- 发生错误调用
- 可以写一个
页面的生命周期函数
- onLoad
- 页面一加载就调用,可以做一些初始化数据的操作,例如去请求数据
- onReady
- 当页面内容渲染调用
- onShow
- 当页面显示调用
- 应用场景:因为tabbar页面默认情况下是切走没有销毁,所以如果从别的页面切回来又传递了参数,就不能在onLoad里接收参数了,只能在onShow里
- onHide
- 当页面隐藏调用
- onUnload
- 当页面卸载调用
- tabbar页面相当于有缓存,也就是切走了也没有销毁。但是非tabbar页面,切走了就销毁了
- 总结:
- 非tabbar页面,放心的在onLoad里接收参数,因为他们默认情况下,重新打开绝对都是重新加载新的
- tabbar页面,要接参数最好用onShow,而且它无法直接传参
组件 - 创建与使用
- 界面上的一个部分就是组件
- 因为相当于组成网页的一部分,所以就叫组件
- 小程序里页面就是页面,组件就是组件
- 组件如何创建?
- 一般情况下要放在
components
文件夹,然后里面每个组件都是一个独立的文件夹(以组件名起名),然后对着文件夹右键
选择新建component
即可创建 - 组件默认也有
json
、wxml
、wxss
、js
四部分,可以写自己的结构和样式以及逻辑代码
- 一般情况下要放在
- 组件如何使用?
- 局部使用
- 哪个页面要用,就在哪个页面自己的
json
文件里写如下配置
- 哪个页面要用,就在哪个页面自己的
- 局部使用
"usingComponents": {
"组件名": "组件路径"
}
- 全局使用
- 在 `app.json`里,加如下配置(跟上面的配置是一样的)
"usingComponents": {
"组件名": "组件路径"
}
组件与页面的区别
- 使用场景的区别:
- 组件一般指页面中的一部分
- 页面是一块大的页面
- 代码写法不同
- 页面是由
Page
函数创建,组件是由Component
函数创建 - 页面的函数直接写到
data
平级的位置,组件的函数写到methods
里面,methods
跟data
平级 - 页面的
json
文件里没有"component":true
,组件里有
- 页面是由
组件样式 - 样式隔离
- 组件不受外界写的样式影响,以及组件内部写的样式默认也不会影响到外部
- 如果选择器用的是标签选择器(不受这个影响,它会导致样式变成全局样式,官方不推荐用标签选择器)
- 有没有一种可能?我在父组件(页面)里想影响到子组件的样式
- 可以修改
options: {
// 还可以写纯数据字段
// 还可以写样式隔离选项
styleIsolation: '值'
}
- 取值有三种:
- isolated: 默认值,就是互不影响
- apply-shared: 页面的样式可以给组件,但是组件内部的样式不能给页面
- shared: 页面和组件之间的样式互相共享
- 针对的是class选择器,官方也是推荐用class选择器,避免用标签选择器
组件内的data和properties的区别.mp4
- 组件内的数据定义在
data
里 - 方法定义在
methods
- 组件内还有个地方叫
properties
,也是定义的属性的地方,但是这里的数据一般是由父组件传递过来的数据 - 本质上
data
和properties
没有任何区别,它们是同一个东西
this.data === this.properties 会得到 true
- 如果要修改也是都可以用
this.setData
来修改 - 但是,如果一个数据需要外界传进来还是得写在
properties
,如果一个数据是内部产生,建议就写在data
里 - properties语法
properties: {
属性名: {
type: 类型,
// 默认值
value: 默认值
}
}
组件通信 -父子传值
- 父传子
- 子里要声明接收哪些数据
properties:{
属性名: {
type: 数据类型,
value: 默认值
}
}
- 父里做传递,找到写这个组件的标签的位置,通过行内属性传递
<组件名 属性名="值"></组件名>
- 上面的写法相当于直接给字符串
<组件名 属性名="{{父里的某个data数据}}"></组件名>
- 上面的写法相当于把父里的某个data传递给子
- 子传父
- 通过自定义的
事件
来传递,相当于是vue里的this.$emit- 子里做传递
- 通过自定义的
this.triggerEvent('事件名', 要传递的数据)
- 父里要监听这个事件
<组件名 bind事件名="方法名"></组件吗>
- 子传递过来的数据就在 `方法`的参数里
方法 (e) {
// 在 e.detail 里
}
- 父里直接找到子组件对象,就可以访问子组件里的数据和方法
- 类似于vue里的ref加标记,再用$refs来操作
- 首先需要给组件加个选择器,一般建议用类选择器,id也可以
- 再通过
const 组件实例 = this.selectComponent('选择器')
// 这个组件实例就相当于这个组件内部的this,该怎么用就怎么用
- 例:
<my-button class="btn1" text="abc"></my-button>
<my-button class="btn2" bindxxx="fn2" text="{{ str }}"></my-button>
toSon() {
// 找到子组件
const btn1 = this.selectComponent('.btn1')
btn1.setData({
sb: '大随便'
})
const btn2 = this.selectComponent('.btn2')
btn2.setData({
sb: '很随便'
})
},
数据监听器
- 监听数据改变,类似于Vue里的
watch
- 语法:几乎跟watch是一样的,只不过把
watch
改成observers
observers: {
msg1 (newVal) {
console.log('msg1改变了', newVal)
},
msg2 (newVal) {
console.log('msg2改变了', newVal)
},
}
- 特点:可以同时监听多个数据
observers: {
// 参数和左边的顺序是一一对应的
"msg1, msg2" (newVal, newVal2) {
console.log('msg1改变了', newVal)
},
}
- 还可以用`**`代表所有
observers: {
// 监听obj里的所有属性,但其实就是等同于监听obj整个
"obj.**" (newVal) {
console.log('msg1改变了', newVal)
},
// 这个就不是obj所有属性改变就触发了
// 只是监听obj.pet这个对象的改变
"obj.pet.**" () {
},
// 监听所有数据
"**" () {
},
}
组件的生命周期
生命周期 | 参数 | 描述 | 最低版本 |
---|---|---|---|
created | 无 | 在组件实例刚刚被创建时执行 | 1.6.3 |
attached | 无 | 在组件实例进入页面节点树时执行 | 1.6.3 |
ready | 无 | 在组件在视图层布局完成后执行 | 1.6.3 |
moved | 无 | 在组件实例被移动到节点树另一个位置时执行 | 1.6.3 |
detached | 无 | 在组件实例被从页面节点树移除时执行 | 1.6.3 |
error | Object Error |
每当组件方法抛出错误时执行 | 2.4.1 |