Ari的小跟班

  :: :: 博问 :: 闪存 :: :: :: :: 管理 ::
  65 随笔 :: 1 文章 :: 1 评论 :: 15044 阅读

参考黑马程序员的教程黑马程序员前端微信小程序开发教程,微信小程序从基础到发布全流程_企业级商城实战(含uni-app项目多端部署)_哔哩哔哩_bilibili,感谢黑马程序员。

基础知识

实现本地生活案例

效果如下:

1.一共有三个页面,先创建三个页面,主要是在app.json中,微信开发者工具中的json无法写注释,所以我在这里写注释,以//开头,参考时不要把注释也复制进json文件中。

在app.json中将背景色小程序标题、以及tabBar设置完毕了。

{
//配置页面
"pages":[
"pages/home/home",
"pages/message/message",
"pages/contact/contact"
],
"window":{
"backgroundTextStyle":"light",
//用于设置小程序的背景色,这里设置成了蓝色
"navigationBarBackgroundColor": "#2b4b6b",
//用于配置小程序的标题“本地生活”
"navigationBarTitleText": "本地生活",
//设置小程序标题的字体颜色
"navigationBarTextStyle":"white"
},
//这里配置tabbar的相关信息
"tabBar": {
"list": [{
"pagePath": "pages/home/home",
"text": "首页",
"iconPath": "/images/tabs/home.png",
"selectedIconPath": "/images/tabs/home-active.png"
},
{
"pagePath": "pages/message/message",
"text": "消息",
"iconPath": "/images/tabs/message.png",
"selectedIconPath": "/images/tabs/message-active.png"
},
{
"pagePath": "pages/contact/contact",
"text": "联系我们",
"iconPath": "/images/tabs/contact.png",
"selectedIconPath": "/images/tabs/contact-active.png"
}
]
},
"style": "v2",
"sitemapLocation": "sitemap.json"
}

2.主要实现的页面在home页面中,home.js如下:

两个数组分别用来存放轮播图和九宫格的数据

// pages/home/home.js
Page({
/**
* 页面的初始数据
*/
data: {
// 存放轮播图数据的数组
swiperList:[],
// 存放九宫格数据
gridList:[]
},
// 获取轮播图数据的方法
getSwiperList(){
wx.request({
url: 'https://www.escook.cn/slides',
method:'GET',
success:(res)=>{
console.log(res);
this.setData({
swiperList:res["data"]
})
}
})
},
//获取九宫格数据的方法
getGridList(){
wx.request({
url: 'https://www.escook.cn/categories',
method:"GET",
success:(res)=>{
this.setData({
gridList:res["data"]
})
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.getSwiperList();
this.getGridList();
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() { },
/**
* 生命周期函数--监听页面显示
*/
onShow() { },
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {}
})

3.home.wxml的内容如下:

其实比较简单,但是最关键的还是wxss的配置,用于设置布局。

<!--pages/home/home.wxml-->
<!-- 轮播图区域 -->
<!--indicator开启轮播图的小圆点 circular使轮播图是衔接滚动,即滚动到最后一个之后再滚动就滚动到第一个了 -->
<swiper indicator-dots circular>
<!-- 这里的wx:key="id"指的是,key等于item["id"],id是item里就有的属性 -->
<swiper-item wx:for="{{swiperList}}" wx:key="id">
<image src="{{item['image']}}"></image>
</swiper-item>
</swiper>
<!-- 轮播图区域 -->
<!-- 九宫格区域 -->
<view class="grid-list">
<view class="grid-item" wx:for="{{gridList}}" wx:key="id">
<image src="{{item['icon']}}"></image>
<text>{{item["name"]}}</text>
</view>
</view>
<!-- 图片区域 -->
<view class="img-box">
<!-- 加了mode="widthFix"后,图片可以自动在宽度不变的情况下,高度调成自适应的值 -->
<image src="/images/link-01.png" mode="widthFix"></image>
<image src="/images/link-02.png" mode="widthFix"></image>
</view>

4.home.wxss的内容:

​ (1)flex模型

​ (2)box-sizing: border-box;设置盒子模型为border-box后padding和border的值就不会在影响元素的宽高,相当于把padding和border的值都算在content里。

/* pages/home/home.wxss */
swiper {
height: 350rpx;
}
swiper image{
width: 100%;
height: 100%;
}
/* Flexbox 是 flexible box 的简称(注:意思是“灵活的盒子容器”),是 CSS3 引入的新的布局模式。它决定了元素如何在页面上排列,使它们能在不同的屏幕尺寸和设备下可预测地展现出来。 */
.grid-list{
display: flex;
flex-wrap: wrap;/*允许换行*/
/* 构成左侧和上侧的边框 */
border-left: 1rpx solid #efefef;
border-top: 1rpx solid #efefef;
}
.grid-item{
width: 33.33%;
height: 200rpx;
display: flex;
/* 改变主轴的方向,使得每个小格子的内部是纵向的布局 */
flex-direction: column;
/* 用于实现小格子内部的内容为居中 */
align-items: center;
justify-content: center;
/* 给九宫格的每个元素加右侧和下侧的边框,
不加左侧和上侧是因为由最外层的边框构成左侧和上侧 */
border-right: 1rpx solid #efefef;
border-bottom: 1rpx solid #efefef;
/* 默认情况下,盒子都是content box,加了border之后,一行就放不下三个格子了
,所以改成border-box */
box-sizing: border-box;
/* 盒子模型是指:外边距(margin)+ border(边框) + 内边距(padding)+ content(内容),可以把每一个容器,比如div,都看做是一个盒子模型。比如你给一个div设置宽高为500px,但实际你设置的只是content,之后你又设置了padding:10px;border:1px solid red;
没有设置box-sizing:border-box属性,宽高会加上padding和border的值,需要我们手动去计算,减去padding和border的值,并调整content的值,以免超过给定的宽高加了box-sizing:border-box属性,padding和border的值就不会在影响元素的宽高,相当于把padding和border的值都算在content里
*/
}
.grid-item image{
width: 60rpx;
height: 60rpx;
}
.grid-item text{
font-size: 24rpx;
/* 九宫格中的文本与图片隔一段间距 */
margin-top: 10rpx;
}
.img-box{
display: flex;
/* 使得离九宫格有一定的距离 */
padding: 20rpx 10rpx;
/*使得在弹性盒对象的元素中的各项周围留有空白: */
justify-content: space-around;
}
.img-box image{
/* 让图片之间有一定的距离 */
/* 剩余10%的区域出来,100%-45%*2=10% */
width: 45%;
}

项目资料链接:localLife.rar - 蓝奏云 (lanzouj.com),若第一个访问不上可以访问第二个:http://gofile.me/6TtvQ/QgjYLKaCW 访问密码:locallife

页面导航

声明式导航

​ 声明式导航指的是在页面上声明一个导航组件,通过点击该组件实现页面的跳转。

1.导航到tabBar页面

tabBar 页面指的是被配置为 tabBar 的页面。在使用 组件跳转到指定的 tabBar 页面时,需要指定 url 属性和 open-type 属性,其中:

(1)url 表示要跳转的页面的地址,必须以 / 开头

(2)open-type 表示跳转的方式,必须为 switchTab

<navigator url="/pages/message/message" open-type="switchTab">导航到消息页面</navigator>

2.导航到非tabBar页面

非 tabBar 页面指的是没有被配置为 tabBar 的页面。在使用 组件跳转到普通的非 tabBar 页面时,则需要指定 url 属性和 open-type 属性,其中:

(1)url 表示要跳转的页面的地址,必须以 / 开头

(2)open-type 表示跳转的方式,必须为 navigate。为了简便,在导航到非 tabBar 页面时,open-type="navigate" 属性可以省略

<navigator url="/pages/message/message">导航到非tabBar</navigator>

3.后退导航

如果要后退到上一页面或多级页面,则需要指定 open-type 属性和 delta 属性,其中:

(1)open-type 的值必须是 navigateBack,表示要进行后退导航

(2)delta 的值必须是数字,表示要后退的层级。为了简便,如果只是后退到上一页面,则可以省略 delta 属性,因为其默认值就是 1。

<navigator open-type='navigateBack' delta='1'>返回上一页</navigator>

编程式导航

​ 调用小程序的导航API,实现页面的跳转。

1.导航到 tabBar 页面

调用wx.switchTab(Object object)方法,可以跳转到 tabBar 页面。其中 Object 参数对象的属性列表如下:

//页面结构
<button bindtap="gotoMessage">跳转到消息页面</button>
//通过编程式导航,跳转到message页面
gotoMessage(){
wx.switchTab({
url:'/pages/message/message'
})
}

2.导航到非tabBar页面

调用wx.navigateTo(Object object)方法,可以跳转到非 tabBar 的页面。其中 Object 参数对象的属性与上图类似。只是url的路径是非tabBar页面的路径

3.后退导航

调用 wx.navigateBack(Object object) 方法,可以返回上一页面或多级页面。其中 Object 参数对象可选的属性列表如下:

可以不用传object参数给wx.navigateBack().

导航传参

声明式导航传参

navigator 组件的 url 属性用来指定将要跳转到的页面的路径。同时,路径的后面还可以携带参数:

(1)参数与路径之间使用 ? 分隔

(2)参数键与参数值用 = 相连

(3)不同参数用 & 分隔

例如:<navigator url="/pages/info/info?name=zs&age=20">跳转到info页面</navigator>

编程式导航传参

​ 方式与声明式导航类似,也是在url里面构造。调用 wx.navigateTo(Object object) 方法跳转页面时,也可以携带参数,代码示例如下:

获得参数

通过声明式导航传参或编程式导航传参所携带的参数,可以直接在 onLoad 事件中直接获取到,示例代码如下:

onLoad:function(options){
console.log(options);
}

传参只有给非tabBar页面传参时才有效,给tabBar页面传参的话,tabBar页面是收不到参数的。

下拉刷新

1.定义:下拉刷新是移动端的专有名词,指的是通过手指在屏幕上的下拉滑动操作,从而重新加载页面数据的行为。

2.启用下拉刷新:

(1)全局开启下拉刷新:在 app.json 的 window 节点中,将 enablePullDownRefresh设置为 true

(2)局部开启下拉刷新:在页面的 .json 配置文件中,将 enablePullDownRefresh 设置为 true

在实际开发中,推荐使用第 2 种方式,为需要的页面单独开启下拉刷新的效果。

3.配置下拉刷新窗口的样式

在全局或页面的 .json 配置文件中,通过 backgroundColor 和 backgroundTextStyle 来配置下拉刷新窗口的样式,其中:

(1)backgroundColor用来配置下拉刷新窗口的背景颜色,仅支持16 进制的颜色值

(2)backgroundTextStyle 用来配置下拉刷新 loading 的样式,仅支持 darklight

下面是backgroundColor="#efefef"即浅灰色并且backgroundTextStyle="dark"时的效果。

4.监听页面的下拉刷新事件

在页面的 .js 文件中,通过 onPullDownRefresh() 函数即可监听当前页面的下拉刷新事件。

例如,在页面的 wxml 中有如下的 UI 结构,点击按钮可以让 count 值自增 +1:

​ 然后下拉刷新之后就让count归零:

onPullDownRefresh:function(){
this.setData({
count:0
})
wx.stopPullDownRefresh();
}

5.停止下拉刷新的效果

当处理完下拉刷新后,下拉刷新的 loading 效果会一直显示,不会主动消失,所以需要手动隐藏下拉刷新的 loading 效果。此时,调用 wx.stopPullDownRefresh() 可以停止当前页面的下拉刷新。

上拉触底

1.定义:上拉触底是移动端的专有名词,通过手指在屏幕上的上拉滑动操作,从而加载更多数据的行为。

2.监听页面的上拉触底事件:在页面的 .js 文件中,通过 onReachBottom() 函数即可监听当前页面的上拉触底事件。示例代码如下

3.配置上拉触底距离:上拉触底距离指的是触发上拉触底事件时,滚动条距离页面底部的距离。可以在全局或页面的 .json 配置文件中,通过 onReachBottomDistance 属性来配置上拉触底的距离。小程序默认的触底距离是 50px,在实际开发中,可以根据自己的需求修改这个默认值。

4.案例实现:上拉触底调用随机获取颜色。一共有六个步骤:

①定义获取随机颜色的方法 ②在页面加载时获取初始数据 ③渲染 UI 结构并美化页面效果

在上拉触底时调用获取随机颜色的方法添加 loading 提示效果对上拉触底进行节流处理

(1)步骤一:定义获取随机颜色的方法

data: {
count:0,
colorList:[]
}
getColors(){
wx.request({
url: 'https://www.escook.cn/api/color',
method:'GET',
// {data:res}指直接获取res中的data的属性值
success:({data:res})=>{
console.log(res);
this.setData({
colorList:[...this.data.colorList,...res.data]
})
}
})
},

获得的数据格式:

(2)步骤二:在页面加载时获取初始数据

onLoad(options) {
this.getColors();
},

(3)步骤三:渲染 UI 结构并美化页面效果

页面<view wx:for="{{colorList}}" wx:key="index" class="num-item" style="background-color: rgba({{item}});">{{item}}</view>

wxss:

.num-item{
border: 1rpx solid #efefef;
border-radius: 8rpx;
line-height: 200rpx;
margin:15rpx;
text-align: center;
text-shadow: 0rpx 0rpx 5rpx #fff;
box-shadow: 1rpx 1rpx 6rpx #aaa;
}

(4)步骤四:上拉触底时获取随机颜色

//初始形式是下面这种,我们得用带冒号的形式
// onReachBottom() {
// },
onReachBottom:function(){
this.getColors();
},

(5)步骤五:添加loading提示效果:完善getColors函数

getColors(){
wx.showLoading({title: '颜色数据加载中'})
wx.request({
url: 'https://www.escook.cn/api/color',
method:'GET',
// {data:res}指直接获取res中的data的属性值
success:({data:res})=>{
console.log(res);
this.setData({
colorList:[...this.data.colorList,...res.data]
})
},
complete:()=>{
wx.hideLoading();
}
})
},

(6)步骤六:对上拉触底进行节流处理

​ 比如数据还在加载的时候,连续触底多次,那么就会请求多个数据,这个时候就要添加节流操作。节流处理分为三步:

①在 data 中定义 isloading 节流阀。false 表示当前没有进行任何数据请求,true 表示当前正在进行数据请求。

②在 getColors() 方法中修改 isloading 节流阀的值。在刚调用 getColors 时将节流阀设置 true,在网络请求的 complete 回调函数中,将节流阀重置为 false。

③在 onReachBottom 中判断节流阀的值,从而对数据请求进行节流控制。如果节流阀的值为 true,则阻止当前请求,如果节流阀的值为 false,则发起数据请求

Page({
data: {
colorList:[],
isloading:false
},
getColors(){
this.setData({
isloading:true
})
wx.showLoading({title: '颜色数据加载中'})
wx.request({
url: 'https://www.escook.cn/api/color',
method:'GET',
// {data:res}指直接获取res中的data的属性值
success:({data:res})=>{
console.log(res);
this.setData({
colorList:[...this.data.colorList,...res.data]
})
},
complete:()=>{
this.setData({
isloading:false
})
wx.hideLoading();
}
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {this.getColors();},
/**
* 页面上拉触底事件的处理函数
*/
//初始形式是下面这种,我们得用带冒号的形式
// onReachBottom() {
// },
onReachBottom:function(){
if(!this.data.isloading){//只有节流阀为false的时候才发起请求
this.getColors();
}
}
})

自定义编译模式

​ 默认的编译模式下,每次编译都是跳转到首页,若我们想编译完之后直接跳转到我们希望的页面(也就是修改过的页面),我们可以自定义编译模式。

生命周期

定义

​ 生命周期(Life Cycle)是指一个对象从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段。我们可以把每个小程序运行的过程,也概括为生命周期:小程序的启动,表示生命周期的开始;小程序的关闭,表示生命周期的结束;中间小程序运行的过程,就是小程序的生命周期

分类

在小程序中,生命周期分为两类,分别是:

1.应用生命周期:指小程序从启动 -> 运行 -> 销毁的过程。

2.页面生命周期:特指小程序中,每个页面的加载 -> 渲染 -> 销毁的过程。

其中,页面的生命周期范围较小,应用程序的生命周期范围较大,如图所示:

生命周期函数

定义

​ 生命周期函数是由小程序框架提供的内置函数,会伴随着生命周期,自动按次序执行。

​ 生命周期函数的作用:允许程序员在特定的时间点,执行某些特定的操作。例如,页面刚加载的时候,可以在 onLoad 生命周期函数中初始化页面的数据。

​ 注意:生命周期强调的是时间段,生命周期函数强调的是时间点。

分类

1.应用的生命周期函数

​ 特指小程序从启动 -> 运行 -> 销毁期间依次调用的那些函数。在app.js文件中声明:

​ (1)onLaunch:function(options){}小程序初始化完成时,执行此函数,全局只触发一次、可以做一些初始化的工作。

​ (2)onShow:function(options){}小程序启动,或从后台进入前台显示时触发。

​ (3)onHide:function(){}小程序从前台进入后台时触发

2.页面的生命周期函数

​ 特指小程序中,每个页面从加载 -> 渲染 -> 销毁期间依次调用的那些函数。小程序的页面生命周期函数需要在页面的 .js 文件中进行声明。

​ (1)onLoad:function(options){}监听页面加载,一个页面只调用1次

​ (2)onShow:function(){}监听页面显示

​ (3)onReady:function(){}监听页面初次渲染完成,一个页面只调用1次

​ (4)onHide:function(){}监听页面隐藏

​ (5)onUnload:function(){}监听页面卸载,一个页面只调用1次

WXS脚本

概述

​ 1.WXS(WeiXin Script)是小程序独有的一套脚本语言,结合 WXML,可以构建出页面的结构。

​ 2.WXS的应用场景:wxml 中无法调用在页面的 .js 中定义的函数,但是,wxml 中可以调用 wxs 中定义的函数。因此,小程序中 wxs 的典型应用场景就是“过滤器”(就是显示之前做一下处理)。

​ 3.wxs 和 JavaScript 的关系:

虽然 wxs 的语法类似于 JavaScript,但是 wxs 和 JavaScript 是完全不同的两种语言

(1)wxs 有自己的数据类型:number 数值类型、string 字符串类型、boolean 布尔类型、object 对象类型、function 函数类型、array 数组类型、date 日期类型、regexp 正则

(2)wxs 不支持类似于 ES6 及以上的语法形式。不支持:let、const、解构赋值、展开运算符、箭头函数、对象属性简写、etc...

​ 支持:var 定义变量、普通 function 函数等类似于 ES5 的语法

(3)wxs 遵循 CommonJS 规范

​ ①module 对象 ②require() 函数 ③module.exports 对象

基础语法

1.内嵌 wxs 脚本

wxs 代码可以编写在 wxml 文件中的 标签内,就像 Javascript 代码可以编写在 html 文件中的 script 标签内一样。

wxml 文件中的每个 标签,必须提供 module 属性,用来指定当前 wxs 的模块名称,方便在 wxml 中访问模块中的成员:

<view>{{m1.toUpper(username)}}</view>
<wxs module="m1">
<!--将文本转为大写形式zx -> ZX -->
module.exports.toUpper = function(str){
return str.toUpperCase();
}
</wxs>

2.定义外联的wxs脚本

​ wxs 代码还可以编写在以 .wxs 为后缀名的文件内,就像 javascript 代码可以编写在以 .js 为后缀名的文件中一样。示例代码如下:

//tools.wxs文件
function toLower(str){
return str.toLowerCase();
}
module.exports = {toLower:toLower}

3. 使用外联的 wxs 脚本

在 wxml 中引入外联的 wxs 脚本时,必须为 标签添加 modulesrc 属性,其中:module 用来指定模块的名称;src 用来指定要引入的脚本的路径,且必须是相对路径

<!-- 调用m2模块中的方法-->
<view>{{m2.toLower(country)}}</view>
<!-- 引用外联的tools.wxs脚本,并命名为m2-->
<wxs src="../../utils/tools.wxs" module="m2"></wxs>

WXS的特点

1.与 JavaScript 不同

​ 为了降低 wxs(WeiXin Script)的学习成本, wxs 语言在设计时借大量鉴了 JavaScript 的语法。但是本质上,wxs 和 JavaScript 是完全不同的两种语言!

2.不能作为组件的事件回调

wxs 典型的应用场景就是“过滤器”,经常配合 Mustache 语法进行使用,例如:<view>{{m2.toLower(country)}}</view>

但是,在 wxs 中定义的函数不能作为组件的事件回调函数。例如,下面的用法是错误的:<button bindtap="m2.toLower">按钮</button>

3.隔离性

隔离性指的是 wxs 的运行环境和其他 JavaScript 代码是隔离的。体现在如下两方面:①wxs 不能调用 js 中定义的函数 ②wxs 不能调用小程序提供的 API

4. 性能好

在 iOS 设备上,小程序内的 WXS 会比 JavaScript 代码快 2 ~ 20 倍。在 android 设备上,二者的运行效率无差异。

本地生活案例v2

​ 点击九宫格进入shoplist页面,shoplist页面的标题根据传入的参数改变。

1.改变具体页面的标题

navigator传参数

<!-- 九宫格区域 -->
<view class="grid-list">
<navigator class="grid-item" wx:for="{{gridList}}" wx:key="id" url="/pages/shoplist/shoplist?id={{item['id']}}&title={{item['name']}}">
<image src="{{item['icon']}}"></image>
<text>{{item["name"]}}</text>
</navigator>
</view>

shoplist页面调用微信的API来改变标题:

onLoad(options) {
this.setData({query:options})
},
onReady() {
wx.setNavigationBarTitle({
title: this["data"]["query"]["title"],
})
},

2.列表页面的 API 接口,以分页的形式,加载指定分类下商铺列表的数据:

(1)接口地址,https://www.escook.cn/categories/:cate_id/shops,URL 地址中的 :cate_id 是动态参数,表示分类的 Id

(2)请求方式为GET请求,请求参数:① _page 表示请求第几页的数据 ② _limit 表示每页请求几条数据

​ 其中header里面有X-Total-Count属性,其值就是total,将它赋值给data里的total。

完整代码如下:

// pages/shoplist/shoplist.js
Page({
data: {
query:{},
shopList:[],
page:1,
pageSize:10,
total:0,
loading:false
},
onLoad(options) {
this.setData({query:options});
this.getShopList();
},
getShopList(stopfresh){
//配置节流阀
this.setData({loading:true});
//展示loading效果
wx.showLoading({
title: '数据加载中',
})
wx.request({
url: `https://www.escook.cn/categories/${this["data"]["query"]["id"]}/shops`,//使用了模板字符串
method:'GET',
data:{
_page:this["data"]["page"],
_limit:this["data"]["pageSize"]//请求多少数据
},
success:(res)=>{
this.setData({
shopList:[...this["data"]["shopList"],...res["data"]],
total:res["header"]["X-Total-Count"]-0 //内容为数字的字符串减去0就是number类型的
})
},
complete:()=>{
this.setData({loading:false});
wx.hideLoading();
stopfresh && stopfresh();//因为是异步的,所以关闭刷新必须在这里进行,只有传了这个函数时才会调用
}
})
},
onReady() {
wx.setNavigationBarTitle({
title: this["data"]["query"]["title"],
})
},
onUnload() {},
onPullDownRefresh() {
this.setData({
page:1,//初始化为第一页
shopList:[],
total:0
});
this.getShopList(wx.stopPullDownRefresh);
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
//判断是否请求完毕
if(this["data"]["page"]*this["data"]["pageSize"]>=this["data"]["total"]){
wx.showToast({
title:"到底了"
});
return;
}
//当节流阀为false的时候才去请求数据
if(!this["data"]["loading"]){
this.setData({page:this["data"]["page"]+1});
this.getShopList();
}
},
})

wxss如下:

/* pages/shoplist/shoplist.wxss */
.shop-item{
display: flex;
padding: 15rpx;
border: 1rpx solid #efefef;
border-radius: 8rpx;
margin: 15rpx;
box-shadow: 1rpx 1rpx 15rpx #ddd;
}
.thumb image{
width: 250rpx;
height: 250rpx;
/* 这样上一张图片与下一张图片之间就不会有间距了 */
display: block;
margin-right: 15rpx;
}
.info{
/* 弹性布局 */
display: flex;
/* 纵向方向 */
flex-direction: column;
/* 文字分散对齐 */
justify-content: space-around;
font-size: 24rpx;
}
.shop-title{
font-weight: bold;
}

具体代码文件:locallifev2.rar - 蓝奏云 (lanzouj.com),若打不开则打开这个:http://gofile.me/6TtvQ/wQRNA7e2i 密码是:locallifev2

自定义组件

创建组件

①在项目的根目录中,鼠标右键,创建 components -> test 文件夹

②在新建的 components -> test 文件夹上,鼠标右键,点击“新建 Component”

③键入组件的名称之后回车,会自动生成组件对应的 4 个文件,后缀名分别为 .js,.json, .wxml 和 .wxss

注意:为了保证目录结构的清晰,建议把不同的组件,存放到单独目录中,例如:

引用组件

组件的引用方式分为“局部引用”和“全局引用”,顾名思义:

1.局部引用:组件只能在当前被引用的页面内使用,在页面的 .json 配置文件中引用组件的方式,叫做“局部引用”。示例代码如下:

2.全局引用:组件可以在每个小程序页面中使用,在 app.json 全局配置文件中引用组件的方式,叫做“全局引用”。示例代码如下:

tips:

根据组件的使用频率和范围,来选择合适的引用方式:如果某组件在多个页面中经常被用到,建议进行“全局引用;如果某组件只在特定的页面中被用到,建议进行“局部引用”

组件与页面的区别

从表面来看,组件和页面都是由 .js、.json、.wxml 和 .wxss 这四个文件组成的。但是,组件和页面的 .js 与 .json 文件有明显的不同:

1.组件的 .json 文件中需要声明 "component": true 属性

2.组件的 .js 文件中调用的是 Component() 函数

3.组件的事件处理函数需要定义到 methods 节点中

组件的样式

1.组件样式隔离:

默认情况下,自定义组件的样式只对当前组件生效,不会影响到组件之外的 UI 结构,如图所示:

1.组件 A 的样式不会影响组件 C 的样式

2.组件 A 的样式不会影响小程序页面的样式

3.小程序页面的样式不会影响组件 A 和 C 的样式

好处:

①防止外界的样式影响组件内部的样式

②防止组件的样式破坏外界的样式

2.组件样式隔离的注意点:(1)app.wxss 中的全局样式对组件无效 (2)只有 class 选择器会有样式隔离效果,id 选择器、属性选择器、标签选择器不受样式隔离的影响,即在app.wxss中使用id 选择器、属性选择器、标签选择器会影响到组件内部的样式

建议:在组件引用组件的页面中建议使用 class 选择器不要使用 id、属性、标签选择器!

3.修改组件的样式隔离选项

默认情况下,自定义组件的样式隔离特性能够防止组件内外样式互相干扰的问题。但有时,我们希望在外界能够控制组件内部的样式,此时,可以通过 styleIsolation 修改组件的样式隔离选项,用法如下:

//在组件的.js文件中新增如下配置
Component({
options:{
styleIsolation:'isolated'
}
})

或者在组件的.json文件中新增如下配置

{
"styleIsolation":"isolated"
}

styleIsolation 的可选值:

数据、方法和属性

1.data 数据:在小程序组件中,用于组件模板渲染的私有数据,需要定义到 data 节点中,示例如下:

Component({
data:{
count:0
}
})

2.methods 方法:在小程序组件中,事件处理函数和自定义方法需要定义到 methods 节点中,示例代码如下:

methods: {
// 点击事件处理函数
addCount() {
if (this.data.count >= this.properties.max) return
this.setData({
count: this.data.count + 1,
max: this.properties.max + 1
})
this._showCount()
},
_showCount() {
wx.showToast({
title: 'count是' + this.data.count,
icon: 'none'
})
},
showInfo() {
console.log(this.data)
console.log(this.properties)
console.log(this.data === this.properties)
}
}

3.properties 属性:在小程序组件中,properties 是组件的对外属性,用来接收外界传递到组件中的数据,示例代码如下:

//在js文件中
properties: {
// 第一种方式:简化的方式
// max: Number
// 第二种方式:完整的定义方式
max: {
type: Number,
value: 10
}
},
//在wxml文件中:
<view>max属性的值是:{{max}}</view>

4.data 和 properties 的区别:

在小程序的组件中,properties 属性和 data 数据的用法相同,它们都是可读可写的,只不过:

(1)data 更倾向于存储组件的私有数据 (2)properties 更倾向于存储外界传递到组件中的数据

5.使用 setData 修改 properties 的值:

​ 由于 data 数据properties 属性在本质上没有任何区别,因此 properties 属性的值也可以用于页面渲染,或使用 setData 为 properties 中的属性重新赋值,示例代码如下:

数据监听器

一、介绍

​ 数据监听器用于监听和响应任何属性和数据字段的变化,从而执行特定的操作。它的作用类似于 vue 中的 watch 侦听器。在小程序组件中,数据监听器的基本语法格式如下:

Component({
observers:{
'字段A,字段B':function(字段A的新值,字段B的新值){
//do something
}
}
})

举例:

1.组件的 UI 结构如下:

<view>{{n1}}+{{n2}} = {{sum}}</view>
<button size="mini" bindtap="addN1">n1自增</button>
<button size="mini" bindtap="addN2">n2自增</button>

2.组件的js如下:

Component({
/**
* 组件的属性列表
*/
properties: {},
/**
* 组件的初始数据
*/
data: {
n1:0,
n2:0,
sum:0
},
observers:{
'n1,n2':function(n1,n2){
this.setData({sum:n1+n2});
}
},
/**
* 组件的方法列表
*/
methods: {
addN1(){this.setData({n1:this["data"]["n1"]+1})},
addN2(){this.setData({n2:this["data"]["n2"]+1})},
}
})

二、监听的具体用法

1.数据监听器支持监听对象中单个多个属性的变化,示例语法如下:

比如data中有一个对象为rgb,observers可以监听三个子属性的变化

Component({
data:{
rgb:{r:0,g:0,b:0},
fullColor:'0,0,0'
},
observers:{
'rgb.r,rgb.g,rgb.b':function(r,g,b){
this.setData({
fullColor:`${r},${g},${b}`
})
}
}
})

2.监听对象中所有属性的变化:

如果某个对象中需要被监听的属性太多,为了方便,可以使用通配符 ** 来监听对象中所有属性的变化,示例代码如下:

observers:{
'rgb.**':function(r,g,b){
this.setData({
fullColor:`${r},${g},${b}`
})
}
}

纯数据字段

一、介绍

​ 纯数据字段指的是那些不用于界面渲染的 data 字段。

​ 应用场景:例如有些情况下,某些 data 中的字段既不会展示在界面上,也不会传递给其他组件,仅仅在当前组件内部使用。带有这种特性的 data 字段适合被设置为纯数据字段。好处:纯数据字段有助于提升页面更新的性能

二、使用规则

​ 在 Component 构造器的 options 节点中,指定 pureDataPattern 为一个正则表达式,字段名符合这个正则表达式的字段将成为纯数据字段,示例代码如下:

Component({
options:{
//指定所有_开头的数据字段为纯数据字段
pureDataPattern:/^_/
},
data:{
a:true,//普通数据字段
_b:true//纯数据字段
}
})

组件的生命周期

一、生命周期函数

二、组件主要的生命周期函数:

​ 在小程序组件中,最重要的生命周期函数有 3 个,分别是 createdattacheddetached。它们各自的特点如下:

  1. 组件实例刚被创建好的时候,created 生命周期函数会被触发

​ (1)此时还不能调用 setData

​ (2)通常在这个生命周期函数中,只应该用于给组件的 this 添加一些自定义的属性字段

2.在组件完全初始化完毕、进入页面节点树后, attached 生命周期函数会被触发

​ (1)此时, this.data 已被初始化完毕

​ (2)这个生命周期很有用,绝大多数初始化的工作可以在这个时机进行(例如发请求获取初始数据)

3.在组件离开页面节点树后, detached 生命周期函数会被触发

​ (1)退出一个页面时,会触发页面内每个自定义组件的 detached 生命周期函数

​ (2)此时适合做一些清理性质的工作

三、使用声明周期函数

1.在小程序组件中,生命周期函数可以直接定义在 Component 构造器的第一级参数中,也可以在 lifetimes 字段内进行声明(这是推荐的方式,其优先级最高)。示例代码如下:

四、组件所在页面的生命周期

​ 有时,自定义组件的行为依赖于页面状态的变化,此时就需要用到组件所在页面的生命周期。比如说一个组件显示的颜色是rgb三个参数决定的,组件每次被渲染时都会显示出随机生成的rgb从而显示出不同的颜色,这个时候就需要组件所在页面的生命周期

​ 例如:每当触发页面的 show 生命周期函数的时候,我们希望能够重新生成一个随机的 RGB 颜色值。

​ 在自定义组件中,组件所在页面的生命周期函数有如下 3 个,分别是:

​ 组件所在页面的生命周期函数,需要定义在 pageLifetimes 节点中,示例代码如下:

​ 那么每当触发页面的 show 生命周期函数的时候,我们希望能够重新生成一个随机的 RGB 颜色值。步骤如下:

插槽

​ 在自定义组件的 wxml 结构中,可以提供一个 节点(插槽),用于承载组件使用者提供的 wxml 结构。比如组件中有一个位置我并不知道要具体写什么结点,这个时候就可以用组件使用者传过来的结点来进行渲染。

一、单个插槽

​ 在小程序中,默认每个自定义组件中只允许使用一个 进行占位,这种个数上的限制叫做单个插槽。

二、多个插槽

​ 在小程序的自定义组件中,需要使用多 插槽时,可以在组件的 .js 文件中,通过如下方式进行启用。

​ 示例代码如下:

​ 定义多个插槽:可以在组件的 .wxml 中使用多个 标签,以不同的 name 来区分不同的插槽。示例代码如下:

image-20220814164306041

​ 在使用带有多个插槽的自定义组件时,需要用 slot 属性来将节点插入到不同的 中。示例代码如下:

组件通信

一、父子组件之间通信的 3 种方式

(1)属性绑定:用于组件向组件的指定属性设置数据,仅能设置 JSON 兼容的数据

(2)事件绑定:用于组件向组件传递数据,可以传递任意数据

(3)获取组件实例:父组件还可以通过 this.selectComponent() 获取子组件实例对象,这样就可以直接访问子组件的任意数据和方法。


(1)属性绑定(父传子)

​ 属性绑定用于实现父向子传值,而且只能传递普通类型的数据,无法将方法传递给子组件。父组件的示例代码如下:

//父组件的data结点
data:{count:0}
//父组件的wxml结构
<my-test3 count="{{count}}"></my-test3>

​ 子组件在 properties 节点中声明对应的属性并使用。示例代码如下:

//子组件的properties节点
properties:{count:Number}
//子组件的wxml结构
<text>子组件中的count值为:{{count}}</text>

(2)事件绑定(子传父)

事件绑定用于实现子向父传值,可以传递任何类型的数据。使用步骤如下:

①在父组件的 js 中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件

//在父组件中定义syncCount方法,将来这个方法会被传递给子组件,供子组件进行调用
syncCount(e){
this.setData({
count:e["detail"]["value"]
})
}

②在父组件的 wxml 中,通过自定义事件的形式,将步骤 1 中定义的函数引用,传递给子组件

<!--使用bind:自定义事件名称(推荐)-->
<my-test3 count="{{count}}" bind:sync="syncCount"></my-test3>
<!--或在bind后面直接写上自定义事件名称-->
<my-test3 count="{{count}}" bindsync="syncCount"></my-test3>

③在子组件的 js 中,通过调用 this.triggerEvent('自定义事件名称', { /* 参数对象 */ }) ,将数据发送到父组件

④在父组件的 js 中,通过 e.detail 获取到子组件传递过来的数据

(3)获取组件实例(子传父或者父传子)

​ 可在父组件里调用 this.selectComponent("id或class选择器") ,获取子组件的实例对象,从而直接访问子组件的任意数据和方法。调用时需要传入一个选择器,例如 this.selectComponent(".my-component")。

behaviors

一、概念

​ behaviors 是小程序中,用于实现组件间代码共享的特性,类似于 Vue.js 中的 “mixins”。

二、behaviors的工作方式

​ 每个 behavior 可以包含一组属性数据生命周期函数方法。组件引用它时,它的属性、数据和方法会被合并到组件中。每个组件可以引用多个 behavior,behavior 也可以引用其它 behavior。

三、创建Behavior

​ 调用 Behavior(Object object) 方法即可创建一个共享的 behavior 实例对象,供所有的组件使用:

module.exports = Behavior({
data: {
username: 'zs'
},
properties: {},
methods: {}
})

​ 四、导入并使用behavior

//使用require()导入需要的自定义behavior模块
const myBehavior = require('../../behaviors/my-behavior')
Component({
//将导入的behavior实例对象,挂载到behaviors数组节点中,即可生效
behaviors: [myBehavior],
//组件的其他节点
})

五、behavior中所有可用的节点

​ 若behavior中有生命周期函数,比如created,那么behavior中的created会比引用了behavior的组件的created函数先触发。

使用npm包

​ 目前,小程序中已经支持npm安装第三方包,但是有三个限制:1.不支持依赖于Node.js内置库的包2.不支持依赖于浏览器内置对象的包3.不支持依赖于C++插件的包

Vant weapp

​ Vant Weapp是有赞前端团队开源的一套小程序UI程序库

安装

​ 具体可以参考vant小程序官网。

1.通过npm安装(建议制定版本为@1.3.3)

​ 2.构建npm包

​ 3.修改app.json

全局数据共享

​ 类似于Redux,小程序中也有用于全局数据共享的插件,即mobx。

​ 在小程序中,可使用mobx-miniprogram配合mobx-miniprigram-bindings实现全局数据共享,其中:(1)mobx-miniprogram用来创建Store实例对象(2)mobx-miniprogram-bindings用来把Store中的共享数据或方法、绑定到组件或页面中使用

安装

​ 需要使用npm环境安装,命令为:npm install --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1,安装完毕之后,删除miniprogram_npm目录,重新构建npm

使用

1.在项目的根目录下创建文件夹store,其下创建store.js,创建store实例:

//在这个JS文件中,专门来创建store的示例对象
import {action, observable} from 'mobx-miniprogram';
export const store = observable({
// 数据字段
numA:1,
numB:2,
//计算属性,用get修饰计算属性,这样sum的值只能是可读的而不可写
get sum(){
return this.numA+this.numB;
},
//actions方法,用来修改store中的数据
updateNum1:action(function(step){
this.numA += step;
}),
updateNum2:action(function(step){
this.numB += step;
})
});

​ actions方法用来修改store中的数据,注意是写法,函数被action()包裹的。

2.在页面中引用创建的示例,比如在message中,页面布局如下:

<view>{{numA}} + {{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="btnHandler1" data-step="{{1}}">numA+1</van-button>
<van-button type="danger" bindtap="btnHandler1" data-step="{{-1}}">numA-1</van-button>

message.js如下:

// pages/message/message.js
import {createStoreBindings} from 'mobx-miniprogram-bindings';
import {store} from '../../store/store';
Page({
data: {},
onLoad(options) {
this.sotreBindings = createStoreBindings(this,{
store, //代表数据源
fields:['numA','numB','sum'],//代表绑定哪些字段
actions:['updateNum1']//代表绑定哪些方法
})
},
tiaozhuandaoContact(){
wx.navigateTo({
url: '/pages/nottabBar/nottabBar?name=zs&age=20',
})
},
onReady() {},
onShow() {},
onHide() {},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
this.sotreBindings.destroyStoreBindings();//在页面卸载时解除绑定
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {},
btnHandler1(e){
this.updateNum1(e["target"]["dataset"]["step"]);
console.log(e["target"]["dataset"]["step"]);
}
})

3.若要在组件中使用store里的变量以及方法,比如number.js

// components/numbers/numbers.js
import {storeBindingsBehavior} from 'mobx-miniprogram-bindings';
import {store} from '../../store/store'
Component({
behaviors:[storeBindingsBehavior],
storeBindings:{
store,//数据源
fields:{
numA:'numA',//第一种数据绑定方式
numB:()=>store["numB"],//第二种数据绑定方式
sum:(store)=>store["sum"]//第三种数据绑定方式
},
actions:{
updateNum2:'updateNum2'
}
},
/**
* 组件的属性列表
*/
properties: {},
/**
* 组件的初始数据
*/
data: {},
/**
* 组件的方法列表
*/
methods: {
btnHandler2(e){
this.updateNum2(e["target"]["dataset"]["step"])
}
}
})
posted on   Ari的小跟班  阅读(547)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示