微信小程序

微信小程序账号注册

  • 访问【微信公众平台】,注册一个微信小程序账号

https://mp.weixin.qq.com/

  • 申请账号需要准备一个邮箱,该邮箱要求:

    • 未被微信公众平台注册
    • 未被微信开放平台注册
    • 未被个人微信号绑定过
    • 如果被绑定了需要解绑 或 使用其他邮箱
  • 获取 小程序id

AppID(小程序ID)	     wxd63f21a664e8009b
AppSecret(小程序密钥)   513e6cd6ea1a2692c9727004af729f1c

创建项目

  • 下载【微信开发工具】--需要联网才能使用

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

  • 本地开发支持http

小程序默认只支持https,我们需要做如下配置,让其支持http,方便我们本地开发

image-20240523145341780

项目目录结构

介绍

# 1 项目主配置文件
	项目主配置文件必须放到项目的根目录下,控制整个项目
    	- app.js:  小程序入口文件
    	- app.json:小程序的全局配置文件
    	- app.wxss:小程序的全局样式
    	-app.js 和 app.json 文件是必须的,不能没有
        
# 2 页面文件
	小程序有一个个页面,每个页面所需的文件,都存放在 pages 目录下,一个页面一个文件夹
        -xx.js:  页面逻辑  js代码存放位置
        -xx.wxml:页面结构  类html文件存放位置
        -xx.wxss:页面样式  css存放位置
        -xx.json:小页面配置 
        -xx.js 文件和 xx.wxml 文件是必须的,不能没有

        
# 3 相关配置文档
https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/app.html

结构

├── components                  【页面中使用的组件】
├── pages   					【页面文件目录】
│   ├── index					【页面】
│   │   ├── index.js				【页面JS】
│   │   ├── index.json				【页面配置】
│   │   ├── index.wxml				【页面HTML】
│   │   └── index.wxss				【页面CSS】
│   └── logs					【页面】
│       ├── logs.js					...
│       ├── logs.json				...
│       ├── logs.wxml				...
│       └── logs.wxss				...
├── utils						【自定义工具】
│	└── utils.js					【功能的定义】
├── app.js						【全局JS】
├── app.json					【全局配置】
├── app.wxss					【全局CSS】
├── project.config.json			【开发者工具默认配置】
├── project.private.config.json	【开发者工具用户配置,在这里修改,优先用这个,可以删除】
├── .eslintrc.js				【ESlint语法检查配置】
├── sitemap.json				【微信收录页面,用于搜索,上线后,搜索关键字就可以搜到我们】

常用组件

# 参考地址:
https://developers.weixin.qq.com/miniprogram/dev/component/

text,类似于span

<text>Justin</text>

view,类似于div

<view>
    <view>Python山顶会</view>
    <view>Justin</view>
    <view>微信:616564099</view>
</view>

image,类似于img标签

<image src="/images/1.png" style="width: 750rpx;height: 400rpx;"></image>

icon

<icon type="success" size='198rpx' color="red"/>
<icon type="download" size='198rpx' color="#ddd"/>
success, success_no_circle, info, warn, waiting, cancel, download, search, clear

跳转,类似于a标签

<navigator class="menu" url="/pages/login/login">
    <label class="fa fa-superpowers" style="color:#32CD32"></label>
  <view>登录</view>
</navigator>

绑定事件,在js中跳转:

<view bindtap="clickMe" data-nid="123" >点我跳转</view>
Page({

  clickMe:function(e){
    var nid = e.currentTarget.dataset.nid;
    console.log(nid);
    wx.navigateTo({
      url: '/pages/login/login'
    })
  }
})

跳转到其他页面之后,可以在onLoad中获取参数

wx.navigateTo({
	url: '/pages/login/login?name=justin'
})
Page({
  onLoad: function (options) {
    console.log(options);
  }
})

尺寸单位 和样式

  • rpx 可以根据不同的手机屏幕进行自动调整,自适应缩放
  • 无论什么手机--》屏幕宽度都是 750rpx
  • 局部样式: xxx.wxss
  • 全局样式: app.wxss

tabbar配置

"tabBar": {
    "selectedColor": "#b4282d",
    # 放置位置只有两个,top:顶部;bottom:底部
    "position": "bottom", 
    # list是数组,里面的tabbar至少2个至多5个
    "list": [
        {
            # 页面的路径
            "pagePath": "pages/index/index", 
             # 文字的内容
            "text": "首页",
            # 默认图标路径
            "iconPath": "images/home.png", 
            #选中的图标路径
            "selectedIconPath": "images/home_select.png"
        },
        ...
    ]
},

实现轮播图 swiper+swiper-item

<swiper 
autoplay 
interval="2000" 
indicator-dots 
indicator-color="#00FF00"
indicator-active-color="#70DB93"
circular
>
  <swiper-item>
    <image src="/images/banner1.jpg" mode="widthFix"/>
  </swiper-item>
  <swiper-item>
    <image src="/images/banner2.png" mode="widthFix"/>
  </swiper-item>
  <swiper-item>
    <image src="/images/banner3.jpg" mode="widthFix"/>
  </swiper-item>
</swiper>

引入矢量图标库

https://www.iconfont.cn/

# 1 搜索想要的图标
	-加入购物车
    -在购物车中添加至项目
    
# 2 我的项目--项目设置--》打开base64

# 3 选择font class --》生成代码--》点击链接地址打开

# 4 把打开的链接地址内容复制到项目中
	-static/css/iconfont.wxss
    
# 5 在app.wxss中引入
@import "/static/css/iconfont.wxss";
   
# 6 在想用图标的位置,加入text组件
<text class="iconfont icon-anquan">

事件绑定

  • bind:tab bindtab
# 1 方式一
<view bind:tab="showLog"></view>
# 2 方式二
<view bindtab="showLog"></view>

# 3 js中写方法
  showLog(){
    console.log("我被点了")
  }

阻止事件冒泡

catch:tap

<view style="height:300rpx;display: flex;justify-content: center;align-items: center; background-color: orange;" bind:tap="handleView">
<button type="primary" plain catch:tap="handleButton">阻止事件冒泡</button>
</view>
  handleView() {
    console.log("view被点了")
  },
  handleButton() {
    console.log("button被点了")
  },

事件对象和传参

data-*方案
mark:自定义属性
target :事件触发者                   :dataset  data定义的属性
currentTarget:事件绑定者             :dataset  data定义的属性

页面跳转

  • 使用 navigator 组件实现跳转

open-type :跳转方式

navigate:保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面redirect: 关闭当前页面,跳转到应用内的某个页面。但不能跳转到 tabbar 页面
switchTab:跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
reLaunch:关闭所有页面,打开到应用内的某个页面
navigateBack:关闭当前页面,返回上一页面或多级页面

wxml语法

#  1 在页面 xx.js 的 Page() 方法的 data 对象中进行声明定义
#  2 在xx.wxml 中使用 {{}} 包裹,显示数据
#  3 可以显示如下,不能编写js语句或js方法
	-变量
	-算数运算
	-三元运算
	-逻辑判断
    
# 4 只是单纯通过赋值,js中变量会变化,但是wxml中的页面不会变化,没有联动效果,需要使用setData()方法修改

setData案例 修改对象

data: {
        name: 'justin',
        age: 19,
        userinfo: {
          name: 'qcc',
          age: 99
        }
      },

  handleChangeName() {
    // 增加数据
    this.setData({
      'userinfo.hobby': '篮球'
    })
    // 修改数据
    this.setData({
      'userinfo.name': '彭于晏'
    })

    // 修改多个数据--》简便方案--》展开运算符
      
    // const userinfo = {
    //   ...this.data.userinfo,
    //   name: '新名字',
    //   hobby: '乒乓球'
    // }
    // this.setData({
    //   // userinfo:userinfo
    //   userinfo //简写形式
    // })
    // 修改多个数据--》简便方案-->assign
    const userinfo = Object.assign(this.data.userinfo, {
      name: 'xxzz',
      hobby: 'aa'
    })
    this.setData({
      // userinfo:userinfo
      userinfo //简写形式
    })

    //删除数据-->单个
    delete this.data.userinfo.name // 页面删除不了,需要用setData更新
    this.setData({
      userinfo:this.data.userinfo
    })

    //删除数据-->多个--解构赋值
    const {name,age,...res}=this.data.userinfo
    this.setData({
      userinfo:res
    })

  },

setData 修改数组

data: {
    names:['刘亦菲','迪丽热巴','古力娜扎','马尔扎哈']
  },
    
   handleChangeList(){
    //1 增加再设置值
    this.data.names.push('xxx')
    this.setData({
      names:this.data.names
    })

    // 1.2 通过数组拼接
    const newList=this.data.names.concat("aaa")
    	this.setData({
    	names:newList
    })

    // 1.3 通过解构赋值
    const newList=[...this.data.names,"李白"]
    this.setData({
      names:newList
    })

    // 2 修改数组
    this.setData({
      'names[1]':'justin'
    })

    // 3 删除数组
    this.data.names.slice(1)
    this.setData({
      names:this.data.names.slice(1)
    })
  },

双向数据绑定:input checkbox

  <input type="text" model:value='{{name}}'/>
  <checkbox model:checked="{{isCheck}}"/>

列表渲染

  • 默认每个对象是item,默认每个下标是index
  • wx:key 提升性能,不写会警告 可以用 index或 *this:代指item本身 要唯一
<view wx:for="{{List}}" wx:key="*this">
{{item}}</text> -->
</view>

修改wx:for-index wx:for-item

  <view wx:for="{{List}}" wx:key="*this" wx:for-item="info">
<text>{{info}}</text>
</view>

条件渲染 wx:if wx:elif wx:else

<view>
  <input type="text" model:value='{{score}}' style="border:orange solid 1rpx"/>
  <view wx:if="{{score>=90&&score<=100}}">优秀</view>
  <view wx:elif="{{score>=80&&score<90}}">良好</view>
  <view wx:elif="{{score>=60&&score<80}}">及格</view>
  <view wx:else>不及格</view>
</view>

发送网络请求

发送网络请求的域名,必须在微信公众平台配置

 handleLoadData(){
    wx.showLoading({
      title: '加载中,稍后',
      mask:true  // 显示透明蒙层
    })
    wx.request({
      url: 'http://192.168.71.100:5000',
      method:'GET',
      data:{},
      header:{},
      success:(res)=>{
        wx.hideLoading()
        console.log(res.data)
        this.setData({
          userinfo:res.data,
        })
        console.log(this.data.name)
      },
      fail:(err)=>{},
      complete:(res)=>{}

    })
  },

loading提示框

# 显示
 wx.showLoading({
      title: '加载中,稍后',
      mask:true  // 显示透明蒙层
    })
    
    
#关闭
 wx.hideLoading()

对话框

模态对话框

##### wxml
<button type="default" size="mini" bind:tap="showModel">弹出模态框</button>
### js ###
showModel(){
    wx.showModal({
        title: '这是标题',
        content: '这是内容部分~~',
        complete: (res) => {
            if (res.cancel) {
                console.log('用户取消了')
            }

            if (res.confirm) {
                console.log('用户确认了')
            }
        }
    })
}

消息对话框

#### wxml
<button type="default" size="mini" bind:tap="showToast">弹出消息框</button>
### js
showToast(){
    wx.showToast({
        title: '恭喜您,秒杀成功',
        icon:"success",
        duration:2000
    })
}



存储

#### wxml####
<button type="default" plain bind:tap="handleSave">存储数据</button>
<button type="primary" plain bind:tap="handleGet">获取数据</button>
<button type="default" plain bind:tap="handleDelete">删除数据</button>
<button type="primary" plain bind:tap="handleClear">清空数据</button>
###js### 同步####
handleSave() {
    wx.setStorageSync('name', "justin")
    wx.setStorageSync('userinfo', {name:'lqz',age:19})
},
handleGet() {
    const name=wx.getStorageSync('name')
    const userinfo=wx.getStorageSync('userinfo')
    console.log(name)
    console.log(userinfo)
},
handleDelete() {
    wx.removeStorageSync('name')
},
handleClear() {
    wx.clearStorageSync()
}

###js### 异步####
handleSave() {
    wx.setStorage({
        key:'name',
        data:"justin"
    })
    wx.setStorage({
        key:'userinfo',
        data:{name:'lqz',age:19}
    })
},

async handleGet() {
    const name= await wx.getStorage({key:'name'})
    const userinfo= await wx.getStorage({key:'userinfo'})
    console.log(name)
    console.log(userinfo)
},
handleDelete() {
    wx.removeStorage({key:'name'})
},
handleClear() {
    wx.clearStorage()
}

上拉下拉加载

方式一

###### js####
// index.js
Page({
    data: {
        page: 1,
        goods: []
    },
    refresh(page) {
        wx.showLoading({
            title: '加载中',
            mask: true
        })
        wx.request({
            url: 'http://127.0.0.1:8000/api/v1/course/actual/?page=' + page,
            method: 'GET',
            success: res => {
                console.log(res.data.code == 100);
                if (page == 1) {
                    this.setData({
                        goods: res.data.results
                    })
                } else {
                    const resData = this.data.goods.concat(res.data.results)
                    this.setData({
                        goods: resData
                    })
                }
            },
            complete: () => {
                wx.hideLoading()
            }
        })
    },
    onLoad() {
        this.refresh(this.data.page)
    },
    onReachBottom() {
        this.data.page++
        console.log('上拉了');
    },
    onPullDownRefresh() {
        this.data.page = 1
        this.refresh(this.data.page)
        if (this.data.goods.length == 3) {
            wx.stopPullDownRefresh()
        }
    }
})
####wxml#####

<view wx:for="{{goods}}" wx:key="index">{{item.name}}</view>

### wxss###
view{
  height: 400rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}
/* 奇数 */
view:nth-child(odd){
  background-color: pink;
}
/* 偶数 */
view:nth-child(even){
  background-color: green;
}

#### json####
{
  "usingComponents": {},
  "onReachBottomDistance": 50,
  "enablePullDownRefresh": true,
  "backgroundColor": "#efefef",
  "backgroundTextStyle":"dark"
}

方式二 scroll-view

##### wxml####
<scroll-view 
class="scroll"
scroll-y
lower-threshold="100"
bindscrolltolower="handleGetData"


refresher-enabled="true"  
refresher-default-style="black"
refresher-background="#f0f0f0"
bindrefresherrefresh="handleReload"
refresher-triggered="{{isRefresh}}"

enable-back-to-top="true"
>
  <view wx:for="{{goods}}" wx:key="index">{{item.name}}</view>
</scroll-view>
### wxss####
.scroll{
  /* 100vh就是指元素的高度等于当前浏览器的视窗高度,即浏览器内部的可视区域的高度大小 */
  height: 100vh; 
  background-color: grey;
}

view{
  height: 400rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}
/* 奇数 */
view:nth-child(odd){
  background-color: pink;
}
/* 偶数 */
view:nth-child(even){
  background-color: green;
}
    
### js#####
// pages/my/my.js
Page({
    data: {
        page: 0,
        goods: [],
        isRefresh: false
    },
    refresh(page) {
        wx.showLoading({
            title: '加载中',
            mask: true
        })
        wx.request({
            url: 'http://127.0.0.1:8000/api/v1/course/actual/?page=' + page,
            method: 'GET',
            success: res => {
                if (page == 1) {
                    this.setData({
                        goods: res.data.results
                    })
                } else {
                    const resData = this.data.goods.concat(res.data.results)
                    this.setData({
                        goods: resData
                    })
                }
            },
            complete: () => {
                wx.hideLoading()
            }
        })
    },
    handleGetData() {
        this.data.page++
        console.log('上拉了')
        this.refresh(this.data.page)

    },
    handleReload() {
        console.log('下拉刷新了')
        wx.showToast({
            title: '下拉刷新',
        })
        this.data.page = 1
        this.refresh(this.data.page)
        this.setData({
            isRefresh: false
        })
    }
})

更新

强制更新

  • 访问小程序,微信会将小程序代码包,下载到微信本地,打开使用
  • 当小程序更新版本后,微信会检查小程序版本有没有更新,并下载最新小程序
  • 更新方式:启动时同步更新,启动时异步更新
### 同步更新####
启动时同步更新:微信运行时,会定期检查最近使用的小程序是否有更新。如果有更新,下次小程序启动时会同步进行更新,更新到最新版本后再打开小程序。如果 用户长时间未使用小程序时,会强制同步检查版本更新
-如果更新失败,还是会使用本地版本
-新版本发布24小时后,基本会覆盖全部用户
### 异步更新####
启动时异步更新:在启动前没有发现更新,小程序每次 冷启动 时,都会异步检查是否有更新版本。如果发现有新版本,将会异步下载新版本的代码包,将新版本的小程序在下一次冷启动进行使用,当前访问使用的依然是本地的旧版本代码
## 强制更新###
在启动时异步更新的情况下,如果开发者希望立刻进行版本更新,可以使用 wx.getUpdateManager API 进行处理。在有新版本时提示用户重启小程序更新新版本

在app.js中加入

App({
  // 生命周期函数,启动小程序就会执行
  onLaunch(){
    const update=wx.getUpdateManager()
    update.onUpdateReady(function(){
      wx.showModal({
        title: '发现新版本',
        content: '重启应用,更新版本新版本?',
        success:(res)=>{
          if(res.confirm){
            update.applyUpdate()
          }
        }
      })
    })
  }
})

image-20240527145927505

生命周期

应用生命周期

// app.js
App({

  /**
   * 当小程序初始化完成时,会触发 onLaunch(全局只触发一次)
   */
  onLaunch: function () {
    console.log('小程序启动了')
    
  },

  /**
   * 当小程序启动,或从后台进入前台显示,会触发 onShow
   */
  onShow: function (options) {
    console.log('后台切前台了')
  },

  /**
   * 当小程序从前台进入后台,会触发 onHide
   */
  onHide: function () {
    console.log('进后台了')
  },

})

页面生命周期

Page({

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

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    console.log('3 初次渲染完成')
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {
    console.log('2 页面显示')
  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {
    console.log('4 页面隐藏')
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    console.log('5 页面卸载')
  },


})

转发给朋友

方式一:通过右上方 ...

Page({
    onShareAppMessage() {
        return {
          title:"是朋友就点一下",
          query: 'name=justin&age=19',
          imageUrl:'/images/b.jpg'
        }
      },
})

方式二:通过按钮, 需要给button设置 open-type="share"

####wxml####
<button open-type="share">转发</button>
####js####
  onShareAppMessage() {
    return {
      title:"是朋友就点一下",
      path:"/pages/my/my", //当前转发的页面
      imageUrl:'/images/b.jpg'
    }

  },

分享到朋友圈

  • 必须有分享给朋友
onShareTimeline(){
    return {
        title:"这是一个神奇的页面",
        query:'name=justin&age=19',
        imageUrl:'/images/b.jpg'
    }
},

获取头像

#### js###
Page({
  data:{
    phono: '/static/img/b.jpg'
  },
  choosePhoto(event){
    console.log(event.detail.avatarUrl)
    this.setData({
      phono:event.detail.avatarUrl
    })

  }
})

#####wxml###
<button class="btn" open-type="chooseAvatar" bindchooseavatar="choosePhoto">
<image src="{{phono}}" class="photo"/>
</button>

###wxss###
.btn{
  /* 透明的 */
  background-color: transparent;
}
/* 去掉边框 */
.btn::after{
  border: none;
}
.photo{
  height: 250rpx;
  width: 250rpx;
  border-radius: 50%;
}

获取昵称

### wxml###
<input  type="nickname" placeholder="输入或获取昵称" model:value="{{username}}"/>
<button type="primary" plain bind:tap="showName">提交</button>
    
###js####
Page({
  data:{
    username:"",
  },
  showName(){
    console.log(this.data.username)
  }
})


###wxss##
input {
  border: 1rpx solid pink;
  border-radius: 10rpx;
  padding: 10rpx;
  margin: 10rpx;
}

手机号快速验证

# 步骤1:需要将 button 组件 open-type 的值设置为 getPhoneNumber,当用户点击并同意之后,通过 bindgetphonenumber 事件获取回调信息;

# 步骤2:将 bindgetphonenumber 事件回调中的动态令牌code传到开发者后台,并在开发者后台调用微信后台提供的 phonenumber.getPhoneNumber 接口,消费code来换取用户手机号。每个code有效期为5分钟,且只能消费一次。


# 步骤3:后端拿到code --》调用getuserphonenumber 换取手机号
https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html

# 步骤4:去咱们自己用户表中查
	-能查到---之前用过,注册了--》签发token
    -查不到--》第一次用--执行注册--》签发token

手机号实时验证

# 步骤1:需要将 button 组件 open-type 的值设置为 getRealtimePhoneNumber,当用户点击并同意之后,通过 bindgetrealtimephonenumber 事件获取回调信息;

# 步骤2:将 bindgetrealtimephonenumber 事件回调中的动态令牌code传到开发者后台,并在开发者后台调用微信后台提供的 phonenumber.getPhoneNumber 接口,消费code来换取用户手机号。每个code有效期为5分钟,且只能消费一次
###wxml###
<button  type="warn" open-type="getPhoneNumber" 
bindgetphonenumber="getPhoneNumber">快速手机号</button>
<button  type="default" plain open-type="getRealtimePhoneNumber"
bindgetrealtimephonenumber="getRealPhoneNumber"
>快速手机号</button>


###js###
getPhoneNumber(event) {
    console.log(event)
    // 通过获取手机号返回的code--传递给后端--后端调用:POST https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=ACCESS_TOKEN -->获取手机号--》后端签发token给前端

    云调用
    wx.request({
        url: '我们后端地址',
        method:'POST',
        data:{
            code:event.detail.code
        },
        success:(res)=>{
            //在此返回登录信息,用户登录
        }

    })
},
getRealPhoneNumber(event) {
    console.log(event)
}

客服功能

微信为小程序提供客服消息能力,以便小程序用户可以方便快捷地与小程序服务提供方进行沟通

https://developers.weixin.qq.com/miniprogram/introduction/custom.html

## wxml##
<button type="default" plain open-type="contact">联系客服</button>

vant-app

https://vant-ui.github.io/vant-weapp/#/home

使用npm包

  • 项目根目录,打开终端【在内建终端打开】
npm init -y  # 会生成package.json文件
  • 安装vant
npm i @vant/weapp -S  
# package.json 能看到下载完成,项目目录下有node_modules
#(可以使用cnpm:npm install -g cnpm --registry=https://registry.npm.taobao.org)
  • 将 app.json 中的 "style": "v2" 去除,小程序的新版基础组件强行加上了许多样式,难以覆盖,不关闭将造成部分组件样式混乱

  • project.config.json 的settings中加入

"packNpmManually": true,
"packNpmRelationList": [
  {
    "packageJsonPath": "./package.json",
    "miniprogramNpmDistDir": "./"
  }
]
  • 构建 工具---》构建npm
posted @ 2024-06-13 15:36  蓝幻ﹺ  阅读(32)  评论(0编辑  收藏  举报