文件和目录结构介绍
页面文件
配置文件介绍
全局配置-window 配置
全局配置-pages 配置
全局配置-tabbar 配置
页面配置
项目配置文件和配置sass
sitemap.json 文件
只有index页面能被索引到,sitemap.json当中的配置
小程序的样式和组件介绍
样式-尺寸单位 rpx
样式-全局样式和局部样式
组件-组件案例演示
view 小程序提供的容器组件,可以直接当成 div 使用即可
小程序当中一些标签的作用及其属性含义
<!-- src:图片的资源地址 -->
<!-- mode:图片的裁剪和缩放模式 -->
<!-- show-menu-by-longpress:长按展示菜单,菜单中有转发给好友、收藏、保存等功能 -->
<!-- lazy-load:图片懒加载功能,在滑动到一定的距离(上下三屏)以后展示图片 -->
<!-- <image src="../../assets/floor/1.png" mode="aspectFit" show-menu-by-longpress lazy-load /> -->
<!-- user-select:长按以后选中文本 -->
<!-- space:显示连续空格 -->
<!-- ensp(全部展示),emsp(空格更大了),nbsp(以字符大小进行展示)空格 -->
<!-- text里面不能写其他标签,否则不会展示 -->
<!-- <text user-select space="nbsp"><view user-select>尚硅谷</view>尚 硅谷</text> -->
<!-- 在进行 页面跳转时,需要再路径的前面添加 / 斜线,否则跳转不成功 -->
<!-- <navigator url="/pages/list/list?id=10&num=hua">到商品列表页面</navigator>
<navigator url="/pages/cate/cate?id=10&num=hua" open-type="switchTab">到商品分类页面</navigator> -->
<!-- navigate:只能跳转到非 TabBar 页面,不能跳转到 TabBar 页面,保留上一级页面 -->
<!-- <navigator url="/pages/list/list" open-type="navigate">到商品列表页面</navigator>
<navigator url="/pages/cate/cate" open-type="navigate">到商品分类页面</navigator> -->
<!-- redirect:只能跳转到非 TabBar 页面,不能跳转到 TabBar 页面,关闭上一级页面,也就不能通过箭头来返回了 -->
<!-- <navigator url="/pages/list/list" open-type="redirect">到商品列表页面</navigator>
<navigator url="/pages/cate/cate" open-type="redirect">到商品分类页面</navigator> -->
<!-- switchTab:只能跳转到 TabBar 页面,不能跳转到非 TabBar 页面,关闭其他所有的非 TabBar 页面 -->
<!-- <navigator url="/pages/list/list" open-type="switchTab">到商品列表页面</navigator>
<navigator url="/pages/cate/cate" open-type="switchTab">到商品分类页面</navigator> -->
<!-- reLaunch:关闭所有页面,然后打开小程序中某一个页面 -->
<!-- <navigator url="/pages/list/list" open-type="reLaunch">到商品列表页面</navigator>
<navigator url="/pages/cate/cate" open-type="reLaunch">到商品分类页面</navigator> -->
组件案例-轮播图区域绘制
组件案例-轮播图图片添加
组件案例-绘制公司信息区域
组件案例-跳转到商品列表
组件案例-推荐商品区域
组件案例-字体图标的使用
背景图的使用
事件绑定和事件对象
事件分类以及阻止事件冒泡
事件传参-data-*自定义数据
事件传参-mark 自定义数据
<!-- view 小程序提供的容器组件,可以直接当成 div 使用即可 -->
<!-- 第一种绑定事件的方式: bind:事件名 -->
<button type="primary" bind:tap="handler">绑定事件</button>
<!-- 第一种绑定事件的方式: bind事件名 -->
<button type="primary" bindtap="handler">绑定事件</button>
<!--在小程序中,input输入框默认没有边框,需要自己添加样式 -->
<input type="text" bindinput="getinputvalue" />
<view class="line"></view>
<view class="catch" bind:tap="parentHandler">
<button bind:tap="btnHandler">按钮</button>
<!--
子组件事件被触发了
父组件事件被触发了
-->
</view>
<view class="catch" bind:tap="parentHandler">
<button catch:tap="btnHandler">按钮</button>
<!--
子组件事件被触发了
-->
</view>
<!-- 如果需要展示数据,在 wxml 中需要使用双大括号写法将变量进行包裹 -->
<view>{{school}}</view>
<view>{{obj.name}}</view>
<!-- 绑定属性值,如果需要动态绑定一个变量,属性值也需要使用双大括号进行包裹 -->
<view id="{{id}}">绑定属性值</view>
<!-- 不加上双大括号的话,将不会生效 -->
<!--如果属性值是布尔值,也需要使用双大括号进行包裹 -->
<checkbox checked="{{isChecked}}" />
<!-- 算数运算 -->
<view>{{id + 1}}</view>
<view>{{id - 1}}</view>
<!-- 三元运算 -->
<view>{{id === 1 ? '等于' : '不等于'}}</view>
<!-- 逻辑判断 -->
<view>{{id === 1}}</view>
<!-- 在双括号写法内部,只能写表达式,不能写语句,也不能调用 js 的方法 -->
<!-- <view>{{if(id===1) {}}}</view> -->
<!-- <view>{{ for(const i=0; i<= 10;i++) {}}}</view> -->
<!-- <view>{{obj.name.toUpperCase}}</view> 页面中不会显示 -->
// pages/cate/cate.js
Page({
btnHandler(event) {
// currentTartget 事件绑定者,也就是指:哪个组件绑定了当前事件处理函数
// target 事件触发者,也就是指:哪个组件触发了当前事件处理函数
// currentTartget 和 target 都是指按钮,因为是按钮绑定的事件处理函数,同时点击按钮触发事件处理函数
// 这时候通过谁来获取数据都可以
console.log(event.currentTartget.dataset.id, '555')
console.log(event.target.dataset.name, '555')
},
// view 绑定的事件处理函数
parentHandler(event){
// 点击蓝色区域(不点击按钮)
// currentTartget 事件绑定者:view
// target 事件触发者:view
// currentTartget 和 target 都是指 view,如果想要获取 view 身上的数据,使用谁都可以
// 点击按钮(不点击蓝色区域)
// currentTartget 事件绑定者:view
// target 事件触发者:按钮
// 如果想要获取 view 身上的数据,必须使用currentTartget身上的才可以
// 如果相获取的是事件触发者,就需要使用target
console.log(event)
// 在传递参数的时候,如果自定义属性是多个单词,单词与单词之间使用中划线 - 进行连接
// 在事件对象中会被转换为小驼峰写法
console.log(event.currentTarget.dataset.parentId)
// 在传递参数的时候,如果自定义属性是多个单词,单词如果使用的小驼峰写法
// 在事件对象中会被转为全部小写的
console.log(event.currentTarget.dataset.parentname)
},
// 按钮绑定的事件处理
btnHandlerMark(event) {
console.log(event.mark.id)
console.log(event.mark.name)
},
parentHandlerMark(event) {
// 先点击蓝色区域(不点击按钮)
// 通过事件对象获取的是 view 身上绑定的函数
// 先点击按钮(不点击蓝色区域)
// 通过事件对象获取到的是 触发事件的节点 以及 父节点身上所有的 mark 数据
console.log(event)
},
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
}
})
WXML 语法
声明和绑定数据
setData() 修改数据
setData() – 修改对象类型数据
setData() – 修改数组类型数据
/**
* 页面的初始数据
*/
data: {
num: 1,
userInfo:{
name: 'tom',
age: 10,
test: 111
},
list: [1,2,3]
// list: [{id: 1, name: 'tom'}]
},
updateNum() {
// 获取数据(要修改数据需要先获取到数据)
// 通过赋值的方式直接修改数据
// 能够修改数据,但是不能改变页面上的数据
// this.data.num += 1
// console.log(this.data.num)
// 这个方法接收一个对象作为参数
// this.setData() 两个作用
// 1.更新数据
// 2.驱动数据(页面)更新
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': 18
// })
// 目前进行新增和修改都是使用数据路径,如果新增和修改的数据量比较小,还可以
// 如果修改的数据很多,每次都写数据路径就太麻烦了
// 可以使用 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})
// this.setData({
// userInfo
// })
// 删除单个属性
// delete this.data.userInfo.age
// console.log(this.data.userInfo)
// this.setData({
// userInfo: this.data.userInfo
// })
// 删除多个属性 rest 剩余参数
// const {age,test,...rest} = this.data.usserInfo
// this.setData({
// userInfo: rest
// })
},
// 更新list
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
// })
// const newList = [...this.data.list, 4]
// this.setData({
// list: newList
// })
// 修改数组元素
// this.setData({
// 'list[1]': 6
// // 'list[0].name': 'jerry'
// })
// 删除数组元素
// this.data.list.splice(1, 1)
// this.setData({
// list: this.data.list
// })
const newList = this.data.list.filter(item=>item !== 2)
this.setData({
list: newList
})
},
简易双向数据绑定
<!-- 单向绑定,数据能够影响页面,但是页面更新不会影响到数据 -->
<!-- <input type="text" value="{{value}}" /> -->
<!-- 双向绑定:数据能够影响页面,页面更新也能够影响数据 model: -->
<!-- 如果想实现简易双向绑定,需要在对应的属性之间添加 model: -->
<input type="text" model:value="{{value}}" />
<!-- 如果需要获取复选框的选中效果,需要给 checked 添加 model: -->
<checkbox model:checked="{{isChecked}}"/>是否同意该协议
<!-- 注意事项1: 属性值只能是一个单一事项的绑定 -->
<!-- AppData数据改变之后,视图能够改变,但是视图改变之后,数据不能改变 -->
<input type="text" model:value="值为 {{value}}"/>
<!-- 注意事项2: 属性值不能写数据路径,也就是不支持对象和数组 -->
<!-- AppData数据改变之后,视图能够改变,但是视图改变之后,数据不能改变 -->
<input type="text" model:value="{{obj.value}}"/>
列表渲染-基本使用
<!-- 如果需要进行列表渲染,需要使用wx:for属性 -->
<!-- 属性值需要使用双大括号进行包裹 -->
<!-- 每一项变量名默认是item -->
<!-- 每一项下标(索引) 的变量名默认是 index -->
<!-- 如果渲染的是数组, item:数组的每一项,index: 下标 -->
<!-- <view wx:for="{{numList}}">{{item}}-{{index}}</view> -->
<!-- 如果渲染的是对象,item:对象属性的值,index:对象属性 -->
<!-- <view wx:for="{{obj}}">{{item}}-{{index}}</view> -->
<!-- wx:key 提升性能 -->
<!-- wx:key 属性值有两种添加形式 -->
<!-- 1.字符串,需要是遍历数组中 item 的某个属性,要求该属性是列表中唯一的字串或者数字,不能进行动态改变 -->
<!-- 保留关键字 *this, *this 代表的是item 本身,item本身是唯一的字符串或者数字" -->
<!-- wx:key 的属性值不需要使用双大括号进行包裹,直接写遍历的数组中 item 的某个属性 -->
<!-- wx:key如果不加上的话,控制台会报错 -->
<view wx:for="{{fruitList}}" wx:key="id">{{item.name}}</view>
<view wx:for="{{numList}}" wx:key="*this">{{item}}</view>
列表渲染-进阶用法
<!-- 如果需要修改默认的变量名,需要使用 wx:for-item 属性 -->
<!-- 如果需要修改默认的下标变量名,需要使用 wx:for-index 属性 -->
<!-- 两个属性需要和 wx:for 写到同一个组件上 -->
<!-- 再重命名,修改以后,需要使用最新的变量名才可以 -->
<!-- 数组 -->
<view wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i">{{fruitItem.name}}</view>
<!-- 对象 -->
<view wx:for="{{obj}}" wx:key="index" wx:for-item="value" wx:for-index="key">{{value}}-{{key}}</view>
<!-- <view wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i">
<view>名字: {{fruitItem.name}}</view>
<view>价格: {{fruitItem.price}}</view>
</view> -->
<!-- block 不是一个组件,只是渲染元素 -->
<!-- 也就是只是包装元素,可以组织代码结构,支持列表渲染 -->
<!-- block不会在页面中做任何渲染,只接受控制属性 -->
<block wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i">
<view>名字: {{fruitItem.name}}</view>
<view>价格: {{fruitItem.price}}</view>
</block>
条件渲染
<!-- wx:if 属性组 -->
<!-- wx:if wx:elif wx:else -->
<!-- 只有对应的条件成立,属性所在的组件才会进行展示 -->
<!-- <view wx:if="{{num === 1}}">num 等于 {{num}}</view>
<view wx:elif="{{num === 2}}">num 22等于 {{num}}</view>
<view wx:else>num 大于 2,目前 num 等于 {{num}}</view> -->
<!-- wx:elif wx:else 不能单独使用,在使用的时候,必须结合 wx:if 来使用 -->
<view wx:if="{{num === 1}}">num 等于 {{num}}</view>
<view wx:elif="{{num === 2}}">num 22等于 {{num}}</view>
<view wx:else>num 大于 2,目前 num 等于 {{num}}</view>
<!-- 使用了 wx:if 属性组的组件不能被打断,组件必须连贯才可以 -->
<view wx:if="{{num === 1}}">num 等于 {{num}}</view>
<!-- <view></view> -->
<view wx:elif="{{num === 2}}">num 22等于 {{num}}</view>
<view wx:else>num 大于 2,目前 num 等于 {{num}}</view>
<!-- hidden 属性 -->
<!-- hidden 属性 属性值 如果是 true,就会隐藏结构,如果是 false,才会展示结构 -->
<view hidden="{{ !isFlag }}">如果isFlag 是true,展示结构,否则隐藏结构</view>
<!-- wx:if 控制结构的展示与隐藏,通过新增与移除结构来实现的 -->
<!-- hidden 属性控制结构的显示与隐藏,是通过 css 的 display 属性来实现 -->
小程序运行机制
小程序更新机制
// onLaunch 是小程序的钩子函数,这个钩子函数在冷启动时肯定会执行到
// 当小程序冷启动时,会自动微信后台请求新版本的信息,如果有新版本,会立即进行下载
onLaunch() {
// 使用wx.getUpdateManager() 方法监听下载的状态
const UpdateManager = wx.getUpdateManager()
// 当下载完成新版本之后,会触发 onUpdateReady 回调函数
UpdateManager.onUpdateReady(function() {
// 在回调函数中给用户提示
wx.showModal({
title: '更新提示',
content: '新版本已经准备完成,是否重新启动应用?',
success(res){
if(res.confirm){
// 强制当前小程序使用新版本并且会重启当前小程序
updateManager.applyUpdate()
}
},
complete: (res) => {
if (res.cancel) {
}
if (res.confirm) {
}
}
})
})
}
小程序生命周期介绍
应用生命周期
当进行冷启动时,才会触发 onLaunch 钩子函数
如果是热启动,不会触发 onLaunch 钩子函数,会触发 onShow 钩子函数
因此 onLaunch(全只会触发一次)
页面生命周期
onLoad:一个页面只会调用一次
onReady:一个页面只会调用一次
onHide:在当前小程序进入后台时,也会触发执行
onShow:如果从后台进入前台,也会触发
小程序 API 介绍
网络请求
界面交互-loading 提示框
// 获取数据
getData() {
wx.showLoading({
// 用来显示提示的内容
// 提示的内容不会自动换行,如果提示的内容比较多,因为在同一行展示
// 多出来的内容会被隐藏
title: '数据加载中...',
// 是否显示透明层,防止触摸穿透
mask: true
})
// 如果需要发起网络请求,需要使用 wx.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(res)
},
// API 调用失败之后,执行的回调
fail: (err) => {
console.log(err)
},
// API 不管调用成功还是失败以后,执行的回调
complete: (res) => {
console.log(res)
// 关闭掉loading提示框
// hideLoading 和 showLoading 必须结合,配对使用才可以
wx.hideLoading()
}
})
},
界面交互-模态对话框-消息提示框
// 删除商品
async delHandler() {
// showModal 显示模态对话框
const {confirm} = await wx.showModal({
title: '提示',
content: '是否删除该商品?'
})
if(confirm) {
// showToast 消息提示框
wx.showToast({
title: '删除成功',
icon: 'none',
duration: 2000
})
}else {
wx.showToast({
title: '取消删除',
icon: 'none',
duration: 2000
})
}
console.log(res)
},
本地存储
// 将数据存储到本地
setStorage() {
// 第一个参数:本地存储中指定的 key
// 第二个参数: 需要存储的数据
// wx.setStorageSync('num', 1)
// 在小程序中
// 如果存储的是对象类型数据,不需要使用 JSON.stringify 和 JSON.parse 进行转换
// wx.setStorageSync('obj', {name: 'tom',age: 18})
// --------------- 异步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')
console.log(num,obj)
// --------------- 异步API --------------------
const {data} = await wx.getStorage({
key:'obj',
})
console.log(data)
},
// 删除本地存储的数据
removeStorage() {
// 从本地移除指定 key 的数据,内容
wx.removeStorageSync('num')
// --------------- 异步API --------------------
wx.removeStorage({
key: 'num',
})
},
// 清空本地存储的全部数据
clearStorage() {
wx.clearStorageSync()
// --------------- 异步API --------------------
wx.clearStorage()
},
路由与通信
页面处理函数-上拉加载
页面处理函数-下拉刷新
// 监听用户上拉加载
onReachBottom() {
console.log('监听用户上拉加载')
// 产品需求:
// 当用户上拉,需要数字进行累加
// 当用户上拉加载时,需要对数据进行累加,每次加载 3 个数字
// 目前是 [1,2,3],[1,2,3,4,5,6]
// 怎么进行追加?
// 获取目前数组中最后一项 n,n+1, n+2, n+3
wx.showLoading({
title: '数据加载中...',
})
setTimeout(()=>{
// 获取数组的最后一项
const lastNum = this.data.numList[this.data.numList.length -1]
// 定义需要追加的元素
const newArr = [lastNum+1,lastNum+2,lastNum+3]
this.setData({
numList: [...this.data.numList, ...newArr]
})
wx.hideLoading()
},1500)
},
// 监听用户下拉刷新
onPullDownRefresh() {
console.log('监听用户下拉刷新')
// 产品需求:
// 当用户上拉加载更多以后,如果用户进行了下拉刷新
// 需要将数据进行重置
this.setData({
numList: [1,2,3]
})
// 在下拉刷新之后,loading效果有可能不会回弹回去
if(this.data.numList.length === 3) {
wx.stopPullDownRefresh()
}
},
增强 scroll-view
profile.wxml
<scroll-view
scroll-y
class="scroll-y"
lower-threshold="100"
bindscrolltolower="getMore"
enable-back-to-top
refresher-enabled
refresher-default-style="white"
refresher-background="#f7f7f7"
bindrefresherabort="refreshHandler"
refresher-triggered="{{isTriggered}}"
>
<view wx:for="{{numList}}" wx:key="*this">{{item}}</view>
</scroll-view>
profile.js
// scroll-view 上拉加载更多事件的事件处理函数
getMore() {
wx.showLoading({
title: '数据加载中...',
})
setTimeout(()=>{
// 获取数组的最后一项
const lastNum = this.data.numList[this.data.numList.length -1]
// 定义需要追加的元素
const newArr = [lastNum+1,lastNum+2,lastNum+3]
this.setData({
numList: [...this.data.numList, ...newArr]
})
wx.hideLoading()
},1500)
},
refreshHandler() {
wx.showToast({
title: '下拉刷新...',
})
this.setData({
numList: [1,2,3],
isTriggered: false // 允许弹回去
})
},
创建和注册组件
组件的数据以及方法
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据,用来定义当前租价所需要使用的数据
*/
data: {
isChecked: false
},
/**
* 组件的方法列表:在组件中,所有的事件处理函数都需要写在methods方法中
*/
methods: {
// 更新复选框的状态
updateChecked() {
this.setData({
isChecked: !this.data.isChecked
})
}
}
})
组件的属性
组件 wxml 的 slot - 插槽
<!-- <text>我是自定义组件</text> -->
<view class="custom-checkbox-container">
<view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left'}}">
<checkbox value="{{isChecked}}" bindtap="updateChecked" />
<view>
<!-- label 和 子节点内容都进行了展示 -->
<!-- 要么展示 label 要么展示 子节点内容 -->
<!-- 如果用户传递了label属性,就展示label -->
<!-- 如果用户没有传递 label 属性,就展示 子节点内容 -->
<text wx:if="{{label !== ''}}">{{label}}</text>
<slot wx:else></slot>
</view>
</view>
</view>
<!-- label 文本显示内容 -->
<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right">
我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>
<view class="line"></view>
<custom-checkbox label="匿名提交" position="left">
匿名提交 - 111
</custom-checkbox>
组件样式以及注意事项
如果是在全局样式文件中设置样式,会影响项目中全部的相同组件
如果是在页面样式文件中设置样式,会影响当前页面所有的相同组件
组件样式隔离
数据监听器
// 用来监听数据以及属性是否发生了改变
observers: {
// key:需要监听的数据
// value: 就是一个回调函数,形参:最新的数据
num: function(newNum) {
// 对 data 中的数据进行监听,如果数据没有发生改变,监听器不会执行
console.log(newNum)
},
count: function(newCount) {
// 对 data 中的数据进行监听,如果数据没有发生改变,监听器不会执行
console.log(newCount)
},
// 同时监听多个数据
'num,count': function(newNum,newCount) {
console.log(newNum,newCount)
},
// 支持监听属性以及内部属性的变化
'obj.name': function(newName) {
console.log(newName)
},
'arr[1]': function(newItem) {
console.log(newItem)
},
// 使用通配符
'obj.**': function(newObj) {
console.log(newObj)
},
'label': function(newlabel) {
// 只要使用者传递了数据,这时候在监听器中就能获取传递的数据
// 也就是说,监听器立即就执行了
console.log(newlabel)
}
},
/**
* 组件的方法列表
*/
methods: {
// 更新数据
updateData() {
this.setData({
// num: this.data.num +1,
// count: this.data.count - 1
// 'obj.name': 'jerry',
// 'arr[1]': 666
label: '最新的标题'
})
}
}
组件通信-父往子传值
observers: {
// 如果需要将 properties 中的数据赋值给 data
// 可以使用 observers 进行处理
checked: function(newChecked) {
console.log(newChecked)
this.setData({
isChecked: newChecked
})
}
},
<!-- 组件传值 index.wxml -->
<!-- label 文本显示内容 -->
<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right" checked="{{isChecked}}">
我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>
<view class="line"></view>
<view class="custom">
<custom-checkbox label="匿名提交" position="left">
匿名提交 - 111
</custom-checkbox>
</view>
组件通信-子往父传值
// 更新复选框的状态
updateChecked() {
this.setData({
// isChecked: !this.data.isChecked,
checked: !this.properties.checked
// label: '在组件内部也可以修改 properties 中的数据'
})
console.log(this.properties.checked)
// 在js中可以访问和获取 properties 中的数据
// 但是一般情况下,不建议修改,因为会造成数据流的混乱
// 目前复选框组件的 状态是存储在复选框组件内部的,存储在自定义父组件内部的
// 但是,在以后实际开发中,组件使用者,父组件有时候也需要获取到复选框内部的状态
// 怎么办?
// 这时候,自定义组件内部就需要发射一个自定义事件
// 如果组件使用者,父组件需要使用数据,绑定自定义事件进行获取即可
this.triggerEvent('changechecked', this.data.isChecked)
}
<-- 组件使用者及其逻辑 -->
<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right" checked="{{isChecked}}" bind:changechecked="getData">
我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>
getData(event) {
console.log(event.detail)
if(event.detail) {
console.log('提交')
} else {
console.log('请同意协议! ')
}
}
组件通信-获取组件实例
<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right" checked="{{isChecked}}" class="child" id="child" bind:changechecked="getData">
我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>
// 获取子组件实例对象
getChild() {
// this.selectComponent 方法获取子组件实例对象
// 获取到实例对象之后,就能获取子组件所有的数据,也能调用子组件的方法
const res = this.selectComponent('#child')
console.log(res.data.isChecked)
}
组件生命周期
// components/custom06/custom06.js
Component({
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
data: {
name: 'tom'
},
/**
* 组件的方法列表
*/
methods: {
},
// 组件生命周期声明对象
lifetimes: {
// created: 组件实例被创建好以后执行
created() {
console.log('组件 created')
// 在组件实例刚刚被创建时执行,注意此时不能调用 setData
// 可以去给组件添加一些自定义的属性,可以通过this的方式进行添加
this.test = '测试'
this.setData({
name: 'jerry'
})
},
// 组件被初始化完毕,模板解析完成,已经把组件挂载到页面上
attached() {
console.log('组件 attached')
console.log(this.test)
// 一般页面中的交互会在 attached 钩子函数中进行执行
this.setData({
name: 'jerry'
})
},
// 组件被销毁时
detached() {
console.log('组件 detached')
}
}
})
组件所在页面的生命周期
具体效果可以看实际操作
// 组件所在页面的生命周期
pageLifetimes: {
// 监听组件所在的页面展示(前台切后台)状态
show() {
console.log('组件所在页面被展示')
},
// 监听组件所在的页面隐藏(前台切后台,点击 tabBar)状态
hide() {
console.log('组件所在页面被隐藏')
}
}
小程序生命周期总结
使用 Component 构造页面
Component({
// 为什么需要使用 Component 方法进行构造页面
// Component 方法功能比 Page 方法强大很多
// 如果使用 Component 方法构造页面,可以实现更加复杂的页面逻辑开发
// 小程序页面也可以使用 Component 方法进行构造
// 注意事项:
// 1.要求 .json 文件中必须包含 usingComponents 字段
// 2.里面的配置项需要和 Component 中的配置项保持一致
// 3.页面中 Page 方法有一些钩子函数,事件监听方法,这些钩子函数,事件监听方法必须放在methods对象中
// 组件的属性 properties 也可以接受页面的参数,在unLoad 钩子函数中可以通过 this.data 进行获取
properties: {
id: String,
title: String
},
data: {
name: 'tom'
},
methods:{
// 更新 name
updateName() {
this.setData({
name: 'jerry'
})
},
onLoad() {
console.log('页面加载 - 2')
console.log(this.data.id)
console.log(this.data.title)
console.log(this.properties.id)
console.log(this.properties.title)
}
}
})
拓展:组件复用机制 behaviors
// behavior.js
const behavior = Behavior({
/**
* 组件的属性列表
*/
properties: {
label: {
type: String,
value: '我已同意该协议'
}
},
/**
* 组件的初始数据
*/
data: {
name: 'Tom',
obj: {
name: 'Tyke'
}
},
/**
* 组件的方法列表
*/
methods: {
updateName(){
this.setData({
name: 'Jerry'
})
console.log('我是 behavior 的方法~~~~') }
},
lifetimes: {
attached(){
console.log('我是 behavior 的生命周期函数~~~~')
}
}
})
export default behavior
// custom08.js
// 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: '组件中的 obj name',
age: 100
}
},
// 如果存在相同的方法,就近原则,使用组件内部的数据
methods: {
updateName(){
console.log('我是组件内部的方法!!!!')
}
},
// 如果存在相同的生命周期函数,生命周期的函数都会被触发
lifetimes: {
attached(){
console.log('我是组件内部的生命周期函数 ~~~~~~')
}
}
})
拓展:外部样式类
组件使用者
<!-- 属性是在 externalClasses 里面定义的元素 -->
<!-- 属性值必须是一个类名 -->
<custom09 extend-class="my-class" />
组件逻辑
Component({
externalClasses: ['extend-class']
})
组件结构
<!-- 在同一节点上,如果存在外部样式类 和 普通样式类 -->
<!-- 两个类的优先级是未定义 -->
<!-- 建议:在使用外部样式类的时候,样式需要通过 !important 添加权重 -->
<view class="extend-class box">通过外部样式类修改组件的样式</view>
完善复选框案例以及总结自定义组件
// 如果 styleIsolation 属性值是 shared
// 这时候呢 externalClasses 选项会失效
externalClasses: ['xxxxx'],
// 如果要让点击文本之后,按钮也被选中,可以使用label标签包裹起来
使用 npm 包
自定义构建 npm
Vant Weapp 组件库的使用
Vant Weapp 组件样式覆盖
小程序分包加载
配置分包加载以及打包、引用原则
因为小程序会先下载主包,在主包下载好之后,分包就可以使用主包的公共资源
"subPackages": [
{
"root": "modules/goodModule",
"name": "goodModule",
"pages": [
"pages/list/list",
"pages/detail/detail"
]
}
独立分包
因为此时主包和其他页面的包还没有被加载
"subPackages": [
{
"root": "modules/goodModule",
"name": "goodModule",
"pages": [
"pages/list/list",
"pages/detail/detail"
]
},
{
"root": "modules/marketModule",
"name": "marketModule",
"pages": [
"pages/market/market"
],
"independent": true
}
分包预下载
"preloadRule": {
"pages/index/index": {
"network": "all",
"packages": ["modules/goodModule"]
},
"modules/marketModule/pages/market/market": {
"network": "all",
"packages": ["__APP__"]
}
}
获取微信头像
逻辑
// 用来获取微信头像
chooseavatar(event) {
console.log(event)
// 目前获取的微信头像是临时路径
// 临时路径时有失效事件的,在实际开发中,需要将临时路径上传到公司的服务器
const {avatarUrl} = event.detail
this.setData({
avatarUrl
})
},
页面结构
<view>
<button class="btn" open-type="chooseAvatar" bindchooseavatar="chooseavatar">
<image class="avatar" src="{{avatarUrl}}" mode=""/>
</button>
</view>
获取微信昵称
页面结构
<!-- 需要使用 form 组件包裹住 input 以及button组件 -->
<form bindsubmit="onSubmit">
<!-- input 输入框组件的 type 属性设置为 nickname,用户点击输入框,键盘上方才会显示微信昵称 -->
<!-- 如果添加了 name 属性,form 组件就会自动收集带有 name 属性的表单元素的值 -->
<input type="nickname" name="nickname" placeholder="请输入昵称" />
<!-- 如果将 form-type="submit" , 就将按钮变成提交按钮 -->
<!-- 在点击提交按钮的时候,会触发 表单的 bindsubmit 提交事件 -->
<button type="primary" plain form-type="submit">点击获取按钮</button>
</form>
.js
// 获取微信昵称
onSubmit(event) {
// console.log(event)
const {nickname} = event.detail.value
console.log(nickname)
}
转发功能
分享到朋友圈
.js
// 监听页面按钮的转发 以及 右上角的转发按钮
onShareAppMessage(obj) {
console.log(obj)
return {
title: '这是一个非常神奇的页面~~~~',
path: '/pages/cate/cate',
imageUrl: '../../assets/bgimage.png'
}
},
// 监听右上角 分享到朋友圈 按钮
onShareTimeline() {
return {
title: '帮我砍一刀~~~',
query: 'id=1',
imageUrl: '../../assets/bgimage.png'
}
},
.wxml
<button open-type="share">转发</button>
手机号验证组件
.js
// 手机号快速验证
getPhoneNumber(event) {
// 通过事件对象,可以看到,在 event.detail 中可以获取到 code
// code 动态令牌,可以使用 code 换取用户的手机号
// 需要将 code 发送给后端,后端在接收到 code 以后
// 也需要调用API,换取用户的真正手机号
// 在换取成功以后,会将手机号返回给前端
console.log(event)
},
// 手机号实时验证
getRealtimePhoneNumber(event) {
console.log(event)
},
.wxml
<button
type="primary"
plain
open-type="getPhoneNumber"
bindgetphonenumber="getPhoneNumber"
>快速验证组件</button>
<button
type="warn"
plain
open-type="getRealtimePhoneNumber"
bindgetrealtimephonenumber="getRealtimePhoneNumber"
>实时速验证组件</button>
客服功能
框架接口-getApp()
app.js
App({
// 全局共享的数据
globalData() {
token: ''
},
// 全局共享的方法
setToken(token) {
// 如果想获取 token,可以使用 this 的方式进行获取
this.globalData.token = token
// 在 App() 方法中如果想获取 App() 实例,可以通过this的方式进行获取
// 不能通过getApp()方法获取
},
})
profile.js
// getApp() 用来获取全球唯一的 APP() 实例
const appInstance = getApp()
Page({
login() {
// 不要通过 app 实例调用钩子函数
console.log(appInstance)
appInstance.setToken('fghionodgnedmnteiy')
},
})
cart.js
const appInstance = getApp()
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log(appInstance.globalData.token)
},
页面间通信
//打开页面
// 点击按钮触发的事件处理函数
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'})
}
})
}
// 被打开页面
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
console.log(options)
console.log('小程序页面 - list - 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})
},
组件通信-事件总线
import PubSub from 'pubsub-js'
sendData() {
// publish 发布,发射自定义事件
// 1.自定义事件的名称
// 2.需要传递的数据
PubSub.publish('myevent',{name: this.data.name,age: 10})
}
lifetimes: {
attached() {
// subscribe 订阅,监听自定义的事件
// 1.需要订阅,监听的自定义事件名称
// 2.回调函数,回调函数有两个参数
// 2.1 msg: 自定义事件的名称
// 2.2 data: 传递过来的数据
PubSub.subscribe('myevent', (msg, data)=>{
console.log(msg, data)
this.setData({
name: data.name
})
})
}
}
自定义导航栏
.json
{
"usingComponents": {},
"navigationBarTitleText": "商品分类",
"navigationBarBackgroundColor": "#00AF92",
"enablePullDownRefresh": true,
"backgroundTextStyle": "dark",
"navigationStyle": "custom"
}
.wxml
<swiper class="custom-swiper" indicator-dots autoplay interval="2000">
<swiper-item>
<image src="../../assets/banner/banner-1.png" mode=""/>
</swiper-item>
<swiper-item>
<image src="../../assets/banner/banner-2.png" mode=""/>
</swiper-item>
<swiper-item>
<image src="../../assets/banner/banner-3.png" mode=""/>
</swiper-item>
</swiper>