微信小程序开发

一、小程序简介

与普通网页开发的区别

  • 1、运行环境不同:微信环境
  • 2、API不同:无法调用DOM和BOM,可以调用微信环境的API
  • 3、开发模式不同:申请小程序开发账号,安装小程序开发工具,创建和配置小程序项目。

二、创建小程序账号

https://mp.weixin.qq.com

     小程序ID

微信开发者工具

https://developers.weixin.qq.com/miniprogram/dev/devtools/stable.html

image-20230320144013649

image-20230320145504164

三、小程序项目结构

image-20230320150756915

image-20230320150919423

image-20230320151417730

image-20230320151627840

四、新建小程序页面

app.json -> pages 中新增页面的存放路径。小程序开发者工具即可帮我们自动创建对应的页面文件,如图:

image-20230320153245878

修改项目首页

image-20230320153506326

image-20230320153740312

image-20230320153938136

image-20230320154046945

image-20230320155308993

image-20230320161929031

Swiper组件的使用

<!--pages/list/list.wxml-->
<swiper class="swiper-container" 
indicator-dots  是否显示面板指示点
ndicator-color="white" 指示点颜色
indicator-active-color="red" 当前选中的指示点颜色
autoplay  是否自动切换
interval="2000" 自动切换间隔
circular 是否采用衔接滑动
    >
<swiper-item><view class="item">a</view></swiper-item>
<swiper-item><view class="item">b</view></swiper-item>
<swiper-item><view class="item">c</view></swiper-item>
</swiper>

image-20230613145722733

text组件的基本使用

  • selectable属性,实现长按选中文本内容的效果。

    <view>
    <text selectable>12121313</text>
    </view>
    

rich-text组件的使用

<rich-text nodes="<h1 style='color:red;'>标题</h1>"></rich-text>

image-20230613151654969

button组件

  • 按钮组件
  • 功能比HTML中的按钮丰富
  • 通过open-type属性可以调用微信的功能
<!--pages/text/text.wxml-->
<view>~~~~~~通过type指定按钮类型~~~~~~</view>
<button>默认按钮</button>
<button type="primary">主色调按钮</button>
<button type="warn">警告按钮</button>
<view>~~~~~~size="mini"小尺寸按钮~~~~~~</view>
<button size="mini">默认按钮</button>
<button type="primary" size="mini">主色调按钮</button>
<button type="warn" size="mini">警告按钮</button>
<view>~~~~~~~~~~~plain镂空按钮~~~~~~~~~~~~</view>
<button size="mini" plain>默认按钮</button>
<button type="primary" size="mini" plain>主色调按钮</button>
<button type="warn" size="mini" plain>警告按钮</button>

image-20230613153054437

image组件

  • 图片组件
  • 默认宽300px,高度240px

image-20230613153520221

五、API

1、事件监听API

  • 特点,以on开头,用来监听某些事件的触发
  • wx.onWindowResize(function callback)监听窗口尺寸的变化

2、同步API

  • 以Sync结尾的API都是同步API
  • 同步API的执行结果,可以通过函数返回值直接获取,如果执行出错会抛出异常
  • wx.setStorageSync('key','value')向本地存储写入内容

3、异步API

  • 类似jquery中的$.ajax(options)函数,需要通过success、fail、complete接收调用的结果
  • wx.request()发起网络请求,通过success回调函数接收数据

六、数据绑定

  • data中定义
  • WXML中使用数据。动态绑定数据。
image-20230613160524641
  • 动态绑定属性

image-20230613160857392

  • 三元运算

image-20230613161457635

  • 算数运算
<view>生成100以内的随机数{{radomNum1 * 100}}</view>

data: {
        info:'hello world!',
        imgsrc:'/images/343434.jpg',
        radomNum:Math.random() * 10,
        radomNum1:Math.random().toFixed(2)//两位小数的随机数 0.12
  },

七、事件绑定

事件是渲染层到逻辑层的通讯方式。通过事件可以将用户在渲染层产生的行为,反馈到逻辑层进行业务的处理。

image-20230613162135424

1、常见事件

image-20230613162210367

2、事件对象的属性列表

image-20230613162350617

3、target和currentTarget区别

image-20230613162722284

4、bindtap触摸行为

image-20230613163308240

5、在事件处理函数中为data中的数据赋值

<button type="primary" bindtap="fhandler">点我试试</button>
<view>加一{{count}}</view>
data: {
        count:0,
      },
fhandler(){
    this.setData({
      count: this.data.count +1,
    })
  },

6、事件传参 data-*参数名

<button bindtap="btnHandler" data-info="{{2}}">
    事件传参
</button>

info被解析成参数的名字

数值2会被解析为参数的值

在事件处理函数中,通过 event.target.dataset.参数名即可获取到具体参数的值

btnHandler(event){
    //dataset是一个对象,包含了所有通过data-* 传递过来的参数项
    console.log(event.target.dataset.info)
}

7、bindinput语法-给把文本框绑定输入事件

<input bindinput="inputHandler"></input>

inputHandler(e){
	console.log(e.detail.value)
}

8、实现文本框和data之间的数据同步

<input value="{{msg}}" bindinput="inputHandler"></input>
data:{
    msg:'你好'
},
inputHandler(e){
    this.setData({
      msg:e.detail.value
    })
input{
  border:1px solid red;
  margin: 5px;
  padding: 5px;
  border-radius: 5px;
}

image-20230613170823166

八、条件渲染

1、wx:if

<view wx:if="{{type ===1}}">男</view>
<view wx:elif="{{type ===2}}">女</view>
<view wx:else>保密</view>
data:{
    type:1
}

2、结合使用wx:if

如果一次性控制多个组件的展示与隐藏,可以使用一个标签将多个组件包装起来,并在标签上使用wx:if控制属性。block不是组件,不会被渲染出来。

3、hidden

hidden="{{true}}"

4、wx:if和hidden对比

  • 运行方式,wx:if是动态的创建和移除元素,控制元素的展示和隐藏。
  • hidden以切换样式的方式。(display:none),控制。
  • 频繁切换,使用hidden。
  • 控制复杂时,使用wx:if

九、列表渲染

1、wx:for

通过wx:for可以根据指定的数组,循环渲染重复的组件结构。

image-20230613185052242

循环项索引index,循环项用item。

2、手动指定索引和当前项变量名

  • 使用wx:for-index可以指定当前循环项的索引的变量名
  • wx:for-item可以指定当前项的变量名
<view wx:for="{{arr}}" wx:for-index="idx" wx:for-item='itemname'> 
  索引是:{{idx}},item项是:{{itemname}}
</view>

3、wx:key

<view wx:for="{{arr1}}" wx:key="id"> 
  我是{{item.name}}
</view>

arr1:[
          {id:1,name:'肖玉红'},
          {id:2,name:"黛玉甜"},
          {id:2,name:"送寺庙"}
        ],


十、wxss模板样式---css

1、rpx尺寸单位

750份

image-20230613190344512

2、@import样式

@import"/common/common.wxss";

3、全局样式 app.wxss

十一、全局配置 app.josn

image-20230613192322244

1、window

image-20230613192405709

image-20230613192600251

app.json

"window":{
    "backgroundTextStyle":"dark",
    "navigationBarBackgroundColor": "#94b452",
    "navigationBarTitleText": "小兔子学小程序",
    "navigationBarTextStyle":"white",
    "enablePullDownRefresh": true,
    "backgroundColor": "#2323bb"
  },

2、tabBar-多页面快速切换

image-20230613193759097

  • backgroundColor:背景色
  • selectedIconPath:选中时的图片背景
  • borderStyle:tabBar上边框的颜色
  • iconPath:未选中时的图片路径
  • selectedColor:tab上的文字选中时的颜色
  • color:文字默认颜色

image-20230613194050541

  "tabBar": {
    "list": [{
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath":"/images/noactive.png",    
        "selectedIconPath":"/images/active.png"
      },
      {
        "pagePath": "pages/text/text",
        "text": "个人中心",
        "iconPath":"/images/noactive.png",    
        "selectedIconPath":"/images/active.png"
      }
    ]
  },

十二、页面配置 xxx.json

页面配置会覆盖全局配置

image-20230613200309761

十三、网络数据请求

  • https
  • 将接口的域名添加到信任列表中

1、配置小程序的合法域名

小程序的-》开发-》开发设置

2、GET请求

getInfo(){
    wx.request({
        url:"https://www.baidu.com",
        methods:'GET',
        data:{
            name:'zf',
            age:20
        },
        success:(res) => {
            console.log(res)
        }
    })
}

3、POST请求

getInfo(){
    wx.request({
        url:"https://www.baidu.com",
        methods:'POST',
        data:{
            name:'zf',
            age:20
        },
        success:(res) => {
            console.log(res)
        }
    })
}

4、onload()

 /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {

  },

5、跳过request合法域名校验

image-20230614082255347

6、跨域和ajax

跨域和Ajax都是基于浏览器的,而小程序依赖微信客户端,所以没有跨域,而且”发起网络数据请求“。

十四、案例-本地生活

  • 新建项目并梳理项目结构
  • 配置导航栏效果
  • 配置tabBar效果
  • 实现轮播图效果
  • 实现九宫格效果
  • 实习图片布局

1、新建项目local-life

在app.json中创建三个新的文件夹

"pages": [
    "pages/home/home",
    "pages/message/message",
    "pages/contact/contact"
  ],

2、导航栏效果

"window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#2b4b6b",
    "navigationBarTitleText": "本地生活",
    "navigationBarTextStyle": "white"
  },

3、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"
    }
  ]
  },

4、轮播图效果

data中定义数组,存储接受请求的数据。

 data: {
    swiperList:[],
    gridList:[]
  },

写请求方法

// 获取轮播图数据的方法
  getSwiperList() {
    wx.request({
      url:'https://applet-base-api-t.itheima.net/slides',
      method:'GET',
      success:(res) =>{
        this.setData({
          swiperList:res.data
        })
      }
    })
  },
      //九宫格数据
  getGridList() {
    wx.request({
      url:'https://applet-base-api-t.itheima.net/categories',
      method:'GET',
      success:(res) =>{
          //存储到data数组中
        this.setData({
          gridList:res.data
        })
      }
    })
  },

在onload中调用----类似mouted

/**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    this.getSwiperList(),
    this.getGridList()
  },

页面

<!-- 轮播图 -->
<swiper class="swiper-container" 
indicator-dots 
ndicator-color="white" 
indicator-active-color="red" 
autoplay 
interval="5000" 
circular 
    >
<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">
  <image src="/images/link-01.png" mode="widthFix"></image>
  <image src="/images/link-02.png" mode="widthFix"></image>
</view>

css效果

/* pages/home/home.wxss */
.swiper-container {
  height: 350rpx;
}
swiper image {
  width: 100%;
  height: 100%;
}
.grid-list{
  display: flex;
  /* 一行装不下,可以换行 */
  flex-wrap: wrap;
  border-top: 1rpx solid red;
  border-left: 1rpx solid red ;
}
.grid-item{
  width: 33.33%;
  height: 200rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-right: 1rpx solid red;
  border-bottom: 1rpx solid red ;
  box-sizing: border-box;
}
.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 {
  width: 45%;
}

十五、页面导航---跳转

声明式导航

  • 声明一个导航组件,点击进行跳转。

  • <navigator url="/pages/message/message" open-type="switchTab">导航到消息列表</navigator>
    
  • 跳转到tabBar,open-type="switchTab"。

  • 导航到非tabBar页面

  • <navigator url="/pages/info/info" open-type="navigate">看看爷爷</navigator>
    
  • 后退导航。open-type="navigatorBack",表示要后退的层级。delta值为数字,表示要退后的层级。

  • <navigator url="/pages/info/info" open-type="navigatorBack" delta='1'>退</navigator>
    

编程式导航

  • 调用小程序的导航API,实现跳转。

  • 导航到tabBar

image-20230614142504928

<button bindtap="gotoMessage">跳转到消息页面</button>

gotoMessage(){
	wx.switchTab({
		url:'/pages/info/info'
	})
}
  • 导航到非tabBar
<button bindtap="gotoMessage">跳转到消息页面</button>

gotoMessage(){
	wx.navigateTo({
		url:'/pages/info/info'
	})
}
  • 后退导航
<button bindtap="goBack">跳转到消息页面</button>

goBack(){
	wx.navigateBack()
}

导航传参

声明式导航传参:参数与路径之间使用 ? 间隔,参数值与参数值用 = 相连, 不同参数用&分隔。

<navigator url="/pages/info/info?name=zs&age=20">看看爷爷</navigator>

编程式导航传参:

<button bindtap="gotoMessage">跳转到消息页面</button>

gotoMessage(){
	wx.navigateTo({
		url:'/pages/info/info?name=zs&gender=20'
	})
}

在onload中接受导航参数

/**生命周期函数--监听页面加载*/
  onLoad(options) {
	console.log(options)
  },

十六、页面事件

下拉刷新

app.json window enablePullDownRefresh true

自动关闭下拉

wx.stopPullDownRefresh()

上拉触底

onReachBootom(){
    
}

上拉触底案例

  • 定义随机获取颜色的方法

  • data: {
        colorList: [], //随机颜色的列表
        isloading:false
      },
      getColors() {
        this.setData({
          isloading:true
        })
        wx.showLoading({
          title: '别着急,小主,在加载中呢...',//展示lodaing效果
        })
        wx.request({
          url: 'https://applet-base-api-t.itheima.net/api/color',
          method: 'GET',
          success: function ({data:res}) {
            this.setData({
              colorList:[...this.data.colorList, ...res.data]
            })
          }.bind(this),
          fail:function(error){
            console.log(error)
          },
          complete:() => {
            wx.hideLoading() //隐藏加载效果
            this.setData({
              isloading:false
            })
          }
        })
      },    
    
  • 在页面加载时,获取初始颜色数据

  • 渲染UI结构并美化页面效果

  • <view wx:for="{{colorList}}" wx:key="index" class="num-item" style="background-color: rgba({{item}});">{{item}}</view>
    
  • .num-item{
      border:1rpx solid #efefef;
      border-radius: 8rpx;
      line-height: 350rpx;
      margin: 15rpx;
      text-align: center;
      text-shadow: 0rpx 0rpx 5rpx #fff;
      box-shadow: 1rpx 1rpx 6rpx #aaa;
    }
    
  • 在上拉触底时调用获取随机颜色的方法

  •  onReachBottom() {
        // console.log('上拉触底,触发了!')
        if(this.data.isloading) return
        this.getColors()
      },
    
  • 添加loading提示效果

  • 对上拉触底进行节流处理

    • 在data中定义isloading节流阀(默认为false)。true表示当前正在进行数据请求
    • 在getColors()方法中修改isloading节流阀的值。在刚调用时,将节流阀设置成true。在网络请求complete回调函数中,将节流阀重置为false。
    • 在onReachBottom()方法中判断节流阀的值,从而对数据请求进行节流控制。true,阻止。false,发起数据请求。

image-20230614162713947

十七、自定义编译模式

image-20230614163231723

十八、生命周期

应用生命周期函数

App({
  //初始化,全局值触发一次
    onLaunch(options){},
  //启动时,从后台进入前台显示时触发
    onshow(options){},
  //小程序从前台进入后台时触发
    onHide(){}
})

页面生命周期函数

onload onshow onReady onHide onShow pmUnload

十九、WXS脚本--过滤器

1、内嵌脚本

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

2、外联的wxs脚本

function(str){
  return str.toUpperCase()
}
moudle.exports = {
    toLower:toLower
}

引用

<wxs src='../../utils.tool.wxs' module="m1">
</wxs>

二十、案例-本地生活(列表页面)

创建shoplist文件夹

导航跳转-携带参数

<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>

动态设置当前页面的标题

wx.setNavigationTitle(Object object)
  • 获取点击的title和id的值。在onLoad()方法中获取。并存储到data中

  • /**
       * 生命周期函数--监听页面加载
       */
      onLoad(options) {
        this.setData({
          query: options
        })
      },
    
  • 在onReady()方法中调用。

 /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    wx.setNavigationBarTitle({
      title:this.data.query.title,
    })
  },

接口地址

  • https://applet-base-api-t.itheima.net/:cate_id/shop'
    
  • :cate_id动态参数

  • GET请求

  • 请求参数

  • _page表示请求第几页的数据 _limit表示请求几条数据

二十一、自定义组件

1、创建组件

  • 在项目的根目录中,创建components ->test文件夹。
  • 在新建的components ->test文件夹上,鼠标右键,点击”新建Component“
  • 键入组件的名称之后会回车,会生成组件对应的4个文件。.js .json .wxml .wxss

2、引用组件

  • 局部引用

  • //在页面的 .json文件中,引入组件
    {
        "usingComponents":{
            "my-test1":"/componrnts/test1/test1"
        }
    }
    
    //在页面的 .wxml文件中,使用组件。
    <my-test1></my-test1>
    
  • 全局引用app.json

3、组件和页面的区别

  • 组件的.json文件需要声明component:true属性
  • 组件js文件调用的是component()函数
  • 组件的事件处理函数需要定义到methods节点中

4、组件样式隔离-class

组件js文件中

Component({
    options:{
    styleIsoIlation:'isolated'
}
})


或者在json文件中
{
	"styleIsolation":"isolated"
}

image-20230614203340910

5、methods方法

6、properties属性

image-20230614203703280

区别

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

image-20230615083333344

7、数据监听器-watch

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

基本用法

Component({
	data: { n1: 0,n2: 0,sum: 0},// 数据节点
	methods: { // 方法列表
		addN1() ( this.setData(( n1: this .data.n1 + 1 }) 
		addN2() { this.setData({ n2: this.data.n2 + 1 }) 
	observers: {// 数据监听节点
    	'n1, n2': function(n1, n2) {// 监听 n1 和 n2 数据的变化
        	this.setData({ sum: n1 + n2 }) // 通过监听器,自动计算 sum 的值
    		}
		}
})

监听对象属性的变化

对象.属性A,对象.属性B

8、数据监听器案例

创建一个组件,全局引用。

image-20230615091827293

app.json,之后引用

"usingComponents":{
    "my-test1":"/components/test/test"
},

书写页面

<view style="background-color: rgb({{fullColor}});" class="colorBox">颜色值:
  {{fullColor}}</view>
<button size="mini" bindtap="changeR" type="default">R</button>
<button size="mini" bindtap="changeG" type="primary">G</button>
<button size="mini" bindtap="changeB" type="warn">B</button>
<view>{{rgb.r}}--{{rgb.g}}--{{rgb.b}}</view>

.colorBox{
  line-height: 200rpx;
  font-size: 24rpx;
  color: aliceblue;
  text-shadow: 0 0 2rpx black;
  text-align: center;
}

书写方法

// components/test/test.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {
    rgb: {
      r: 0,
      g: 0,
      b: 0
    },
    fullColor: '0,0,0'
  },

  /**
   * 组件的方法列表
   */
  methods: {
    changeR() { //修改rgb对象上的r属性的值
      this.setData({
        'rgb.r': this.data.rgb.r + 5 > 255 ? 255 : this.data.rgb.r + 5
      })
    },
    changeG() { //修改rgb对象上的g属性的值
      this.setData({
        'rgb.g': this.data.rgb.g + 5 > 255 ? 255 : this.data.rgb.g + 5
      })
    },
    changeB() { //修改rgb对象上的b属性的值
      this.setData({
        'rgb.b': this.data.rgb.b + 5 > 255 ? 255 : this.data.rgb.b + 5
      })
    }
  },
  // 监听器
  observers:{
    'rgb.r,rgb.g,rgb.b':function(r,g,b){
      this.setData({
        fullColor:`${r},${g},${b}`
      })
    }
  }
})

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

// 监听器
  observers:{
    'rgb.**':function(obj){
      this.setData({
        fullColor:`${obj.r},${obj.rg},${obj.rb}`
      })
    }
  }

9、纯数据字段

不用于界面渲染的data字段

有助于提升界面性能

使用规则

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

})

10、生命周期函数

image-20230615092917483

Component({
  lifetimes: {
    attached: function() {
      // 在组件实例进入页面节点树时执行
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
  },
  // 以下是旧式的定义方式,可以保持对 <2.2.3 版本基础库的兼容
  attached: function() {
    // 在组件实例进入页面节点树时执行
  },
  detached: function() {
    // 在组件实例被从页面节点树移除时执行
  },
})

11、组件所在页面,生命周期。

生命周期 参数 描述
show 组件所在的页面被展示时执行
hide 组件所在的页面被隐藏时执行
resize Object Size 组件所在的页面尺寸变化时执行
routeDone 组件所在页面路由动画完成时执行
Component({
  pageLifetimes: {
    show: function() {
      // 页面被展示
    },
    hide: function() {
      // 页面被隐藏
    },
    resize: function(size) {
      // 页面尺寸变化
    }
  }
})

12、插槽占位

封装

<view>
	<view>这是组件内部</view>
    <slot></slot>  /占位符/
</view>

使用者

<test>引用组件
	<view>这是填充插槽的内容</view>
</test>

启用多个插槽

Component({
  options: {
 	multipleSlots:true
  }
})
<view>
    <view>插槽1</view>
    <slot name="nini"></slot> 
	<view>插槽2</view>
    <slot name="mimi"></slot>  
</view>

使用

<test>引用组件
	<view slot="mimi">这是填充插槽的内容</view>
</test>

13、父子组件通信

  • 属性绑定

    • 用于父组件向子组件的指定属性设置数据,仅能设置JSON兼容的数据

      //子组件的properties节点
      properties:{
      	count:Number
      }
      //子组件的wxml结构,子组件使用父组件传递过来的值。
      <text>子组件:count值{{count}}</text>
      
      子组件
      <my-test1 count="{{count}}"></my-test1>
      
      
      在父组件中,通过属性绑定,将count的值,传递给子组件的值。
      父组件
      <view>父组件中,值为{{count}}</view>
      
  • 事件绑定

    • 用于子组件向父组件传递数据,可以传递任意数据

      1、在父组件的js中,定义一个函数,这个函数即将通过自定义事件的形式,传递给子组件
      2、在父组件的wxml中,通过自定义事件的形式,将步骤1中定义的函数引用,传递给子组件
      3、在子组件的js中,通过调用this.triggerEvent('自定义事件名',{参数对象}),将数据发送到父组件
      4、在父组件的js中,通过调用e.detail获取子组件传递过来的数据
      
      //父组件message.js中
      //在父组件的js中,定义一个函数,将函数传递给子组件。
      Page({
           data: {
           count:1
          },
        syncCount(e){
          console.log('e',e)
          this.setData({
            count:e.detail.value
          })
        },
      })
      
      //接受父组件的syncCount函数,将之起名sync
      <my-test2 count="{{count}}" bind:sync="syncCount"></my-test2>
      <view>父组件:{{count}}</view>
      
      //子组件test1.js,methods方法中
      methods: {
          addCount(){
            this.setData({
              count:this.properties.count + 1
            })
            //触发自定义事件,将数值同步给父组件
            this.triggerEvent('sync',{value:this.properties.count})
          }
        }
      

      image-20230615104505028

  • 获取组件实例

    • 父组件可以通过this.selectComponent()获取子组件实例对象.id和class选择器

    • 可以直接访问子组件的任意数据和方法

       <my-test2 count="{{count}}" bind:sync="syncCount" class="goodman" id="gM"></my-test2>
      
       <view>父组件:{{count}}</view>
      
       <button bindtap="getChild">获取子组件的实例对象</button>
      
      getChild(){
          const child = this.selectComponent('.goodman')
          console.log(child)
          child.setData({
             count:child.properties.count + 1
          })
         // child.addCount()
        },
      

      image-20230615110139374

14、Behaviors

//调用Behaviors()方法,创建实例对象
//并使用module.exports 将behaviors实例对象
module.exports = Behavior({
    //属性节点
    properties:{},
    //私有数据节点
    data:{username:'zs'},
    //事件处理函数和自定义方法节点
    methods:{}
})

使用,引入组件js中。

//1.使用require()导入需要的自定义behavior模块
const myBehavior = require('../../behaviors/my-behavior')

Component({
    //2.将导入的behavior实例对象,挂载到behaviors数组节点中,接口生效
    behaviors:[myBehavior]
})

使用,页面。

<view>用户名:{{username}}</view>

同名字段的覆盖和组合规则

  • 如果有同名的属性 (properties) 或方法 (methods):
    1. 若组件本身有这个属性或方法,则组件的属性或方法会覆盖 behavior 中的同名属性或方法;
    2. 若组件本身无这个属性或方法,则在组件的 behaviors 字段中定义靠后的 behavior 的属性或方法会覆盖靠前的同名属性或方法;
    3. 在 2 的基础上,若存在嵌套引用 behavior 的情况,则规则为:引用者 behavior 覆盖 被引用的 behavior 中的同名属性或方法。
  • 如果有同名的数据字段 (data):
    • 若同名的数据字段都是对象类型,会进行对象合并;
    • 其余情况会进行数据覆盖,覆盖规则为: 引用者 behavior > 被引用的 behavior靠后的 behavior > 靠前的 behavior。(优先级高的覆盖优先级低的,最大的为优先级最高)
  • 生命周期函数和 observers 不会相互覆盖,而是在对应触发时机被逐个调用:
    • 对于不同的生命周期函数之间,遵循组件生命周期函数的执行顺序;
    • 对于同种生命周期函数和同字段 observers ,遵循如下规则:
      • behavior 优先于组件执行;
      • 被引用的 behavior 优先于 引用者 behavior 执行;
      • 靠前的 behavior 优先于 靠后的 behavior 执行;
    • 如果同一个 behavior 被一个组件多次引用,它定义的生命周期函数和 observers 不会重复执行。

二十二、npm包

  • 不支持依赖于Node.js内置库的包
  • 不支持依赖于浏览器内置对象的包
  • 不支持依赖于C++插件的包

Vant Weapp

安装

npm i @vant/weapp@1.3.3 -S --production


将 app.json 中的 "style": "v2" 去除
工具 -> 构建 npm

使用,app.json

"usingComponents": {
  "van-button": "@vant/weapp/button/index"
}

页面

 <van-button type="warning">按钮</van-button>

定义css变量

html{
    --main-color:red
}

.box1{
    background-color: var(--main-color)
}

定制全局主题样式

在app.wxss中,写入css变量

page{
    --button-danger-background-color:#C00000
}

api Promise化

npm i --save miniprogram-api-promise@1.0.4      然后npm构建,miniprogram_npm文件夹中才有

使用,在app.js中

//在小程序入口文件中,只需调用一次promisifyAll()方法
//即可实现异步API的Promise化
import {promisifyAll} from 'miniprogram-api-promise'
const wxp = wx.p = {}

promisifyAll(wx,wxp)

页面调用

<button bindtap="getinfo">
    
</button>
async getInfo() {
    const {data:res} =await  wx.p.request({
      methods: 'GET',
      url: 'https://applet-base-api-t.itheima.net/api/get',
      data: {
        name: 'zs',
        age: 20
      }
    })
    console.log(res)
  },

image-20230615154102248

二十三、全局数据共享

mobx-miniprogram配合mobx-miniprogram-bindings。

  • mobx-miniprogram用来创建Store实例对象
  • mobx-miniprogram-bindings用来Store的共享数据或方法,绑定到组件或页面中使用。
npm i --save mobx-miniprogram@4.13.2 mobx-miniprogram-bindings@1.2.1

创建一个store文件夹--store.js

// 在这个JS文件中,专门来创建Store的实例对象
import {observable,action} from'mobx-miniprogram'

export const store = observable({
  nuA:1,
  numB:2
})

将Store中的成员绑定到页面中

// pages/message/message.js
import {createStoreBindings} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'
Page({

  /**
   * 页面的初始数据
   */
  data: {
    count: 1
  },
  syncCount(e) {
    // console.log('e',e)
    this.setData({
      count: e.detail.value
    })
  },
  getChild() {
    const child = this.selectComponent('.goodman')
    console.log(child)
    // child.setData({
    //   count:child.properties.count + 1
    // })
    child.addCount()
  },
   async getInfo() {
    const {data:res} =await  wx.p.request({
      methods: 'GET',
      url: 'https://applet-base-api-t.itheima.net/api/get',
      data: {
        name: 'zs',
        age: 20
      }
    })
    console.log(res)
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    this.storeBindings = createStoreBindings(this,{
      store,
      fields:['numA','numB','sum'],  //将这些字段绑定到this中
      actions:['updateNum1']
    })
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    this.storeBindings.destoryStoreBindings()
  },
})

在页面上使用Store中的成员

<!--message.wxml-->
<view>{{numA}}+{{numB}} = {{sum}}</view>
<van-button type="primary" bindtap="btnHander" data-step="{{1}}">num加1</van-button>
<van-button type="danger" bindtap="btnHander" data-step="{{-1}}">num减1</van-button>
btnHander(e) {
    this.updateNum1(e.target.dataset.step)
},

image-20230615164035015

将Store中的成员绑定到组件中

// components/test3/teste.js
import {storeBindingsBehavior} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'
Component({
  behaviors:[storeBindingsBehavior],//通过storeBindingsBehavior来实现自动绑定
  storeBindings:{
    store,//指定要绑定的store
    fields:{//指定要绑定的字段数据
      numA:'numA',
      numB:'numB',
      sum:'sum'
    },
    actions:{
      updateNum:"updateNum2"
    }
  },
})

在组件中使用Store中的成员--在组件teste.wxml中

<view>---------------------</view>
<view>{{numA}}+{{numB}} = {{sum}}</view>
 <van-button type="warning" bindtap="btnHander2" data-step="{{1}}">num加1</van-button>
 <van-button type="danger" bindtap="btnHander2" data-step="{{-1}}">num减1</van-button>
 <view>---------------------</view>

在teste.js

// components/test3/teste.js
import {storeBindingsBehavior} from 'mobx-miniprogram-bindings'
import {store} from '../../store/store'
Component({
  behaviors:[storeBindingsBehavior],//通过storeBindingsBehavior来实现自动绑定
  storeBindings:{
    store,//指定要绑定的store
    fields:{//指定要绑定的字段数据
      numA:'numA',
      numB:'numB',
      sum:'sum'
    },
    actions:{
      updateNum:"updateNum2"
    }
  },
  methods: {
    btnHander2(e) {
      // console.log(e)
      this.updateNum(e.target.dataset.step)
  }
  }
})

二十四、分包

分包:把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。

  • 优化小程序首次启动的下载时间
  • 多人团队共同开的时候,更好的解耦。

构成

image-20230615182507094

分包后:小程序项目有1个主包+多个分包组成

  • 主包:一般只包含项目的启动页面或TabBar页面、以及所有分包都需要用到的一些公共资源
  • 分包:只包含和当前分包有关的页面和私有资源

image-20230615183111894

分包的加载规则

  • 在小程序启动时,默认会下载主包并启动主包内页面
  • tabBar页面需要放在主包中
  • 当用户进入分包内某个页面时,客户端会把对应分包下载下来,下载完成后再进行展示
  • 非tabBar页面可以按照功能的不同,划分为不同的分包之后,进行按需下载
  • 分包大小不超过16M(主包+所有分包)
  • 单个分包/主包大小不能超过2M

配置方法

目录结构

|——————app.js
|——————app.json
|——————app.wxss
|——————pages   //主包的所有页面
|     |——————index
|     |——————logs
|——————packageA   //第一个分包
|     |——————pages
|           |——————cat
|           |——————dog
|——————packageA   //第二个分包
|     |——————pages
|           |——————apple
|           |——————banana
|------utils

app.json------在subpackage节点中声明分包的结构

{
    "pages":[
            "pages/home/home",
    		"pages/message/message",
    		"pages/contact/contact",
    ],
     "subpackage":[
         {
         "root":"packageA",//第一个分包的根目录
         "name": "p1",
         "page":[
         "pages/cat/cat",
         "pages/dog/dog"
         ]
         },
         {
         "root":"packageA",//第一个分包的根目录
             "name": "p1",
         "page":[
         "pages/apple/apple",
         "pages/banana/banana"
         ]
         },
         
     ]
}

独立分包

{
         "root":"packageA",//第一个分包的根目录
             "name": "p1",
         "page":[
         "pages/apple/apple",
         "pages/banana/banana"
         ],
             "independent":true
         },

分包预下载

app.json中

{
    "preloadRule":{//分包预下载规则
        "pages/contact/contact":{//触发分包预下载的页面路径
            //network表示在指定的网络模式下进行预下载
            //可选值:all(不限网络)和wifi
            //默认值wifi
            "network":"all",
            //packages表示进入页面后,预下载哪些分包
            //可以通过root或name指定预下载哪些分包
            "packages":["pakA"]
        }
        
    }
}

二十五、自定义tabBar

  • 配置信息
  • 添加tabBar代码文件
  • 编写tabBar代码

1. 配置信息

  • app.json 中的 tabBar 项指定 custom 字段,同时其余 tabBar 相关配置也补充完整。
  • 所有 tab 页的 json 里需声明 usingComponents 项,也可以在 app.json 全局开启。

示例:

{
  "tabBar": {
    "custom": true,
    "color": "#000000",
    "selectedColor": "#000000",
    "backgroundColor": "#000000",
    "list": [{
      "pagePath": "page/component/index",
      "text": "组件"
    }, {
      "pagePath": "page/API/index",
      "text": "接口"
    }]
  },
  "usingComponents": {}
}

2. 添加 tabBar 代码文件

在代码根目录下添加入口文件:

image-20230615201939363

custom-tab-bar/index.js
custom-tab-bar/index.json
custom-tab-bar/index.wxml
custom-tab-bar/index.wxss

3. 编写 tabBar 代码

用自定义组件的方式编写即可,该自定义组件完全接管 tabBar 的渲染。另外,自定义组件新增 getTabBar 接口,可获取当前页面下的自定义 tabBar 组件实例。

<van-tabbar active="{{ active }}" bind:change="onChange">
  <van-tabbar-item wx:for="{{list}}" wx:key="index" info="{{item.info ? item.info : ''}}">
    <image slot="icon" src="{{item.iconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />
    <image slot="icon-active" src="{{item.selectedIconPath}}" mode="aspectFit" style="width: 25px; height: 25px;" />
    {{item.text}}
  </van-tabbar-item>
</van-tabbar>
import { storeBindingsBehavior } from 'mobx-miniprogram-bindings'
import { store} from '../store/store'
Component({
  options: {
    styleIsolation: 'shared',
  },
  behaviors:[storeBindingsBehavior],
  storeBindings:{
    store,
    fields:{
      sum:'sum'
    },
    actions:{

    },
  },
  observers:{
    'sum':function(val){
      this.setData({
        'list[1].info':val
      })
    }
  },
  data: {
    active: 0,
    "list": [{
        "pagePath": "/pages/home/home.wxml",
        "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",
        info: 2
      },
      {
        "pagePath": "pages/contact/contact",
        "text": "联系我们",
        "iconPath": "/images/tabs/contact.png",
        "selectedIconPath": "/images/tabs/contact-active.png"
      }
    ]
  },
  methods: {
    onChange(event) {
      this.setData({
        active: event.detail
      });
    },
  }
})

image-20230615202741755

4、页面切换

  methods: {
    onChange(event) {
      this.setData({
        active: event.detail
      })
      wx.switchTab({
        url:this.data.list[event.detail].pagePath,
      })
    },
  }

5、选中项出错

将选中项的索引值,存放在store.js中

import { observable, action} from'mobx-miniprogram'
export const store = observable({
  numA:1,
  numB:2,
  activeTabBarIndex:0,   //索引值,初始为0
  //计算属性:get只读
  get sum(){
    return this.numB + this.numA
  },
  // actions方法,用来修改store中的数据
  updateNum1:action(function(step){
    this.numA += step
  }),
  updateNum2:action(function(step){
    this.numB += step
  }),
    //定义更新,索引值的方法。接受点击TabBar所产生的索引值。
  updateactiveTabBarIndex:action(function(index){
    this.activeTabBarIndex = index
  })
})

在index.js中引入activeTabBarIndex值和更新索引值的方法

  storeBindings:{
    store,
    fields:{
      sum:'sum',
      active:'activeTabBarIndex'
    },
    actions:{
      updateActive:'updateactiveTabBarIndex'
    },
  },

当点击tabBar的时候,所产生的索引值,传递到store中。

  methods: {
    onChange(event) {
        //调用更新索引值的方法,将点击的索引值传递过去
      this.updateActive(event.detail)
      wx.switchTab({
        url:this.data.list[event.detail].pagePath,
      })
    },
  }

页面使用

<van-tabbar active="{{active}}"  bind:change="onChange">
</van-tabbar>

6、修改选中项文字颜色

<van-tabbar active="{{active}}"  bind:change="onChange" active-color="#13A7A0">
</van-tabbar>

二十六、综合项目

1、开发工具

posted @ 2023-06-28 09:19  孤舟蓑衣客  阅读(173)  评论(0)    收藏  举报