XingYun blog
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具

XingYun

冲!
  • JS基础

    • 图解js原型链
    • JS Event Loop
    • 对象的底层数据结构
    • 让你的JavaScript代码简单又高效
    • 函数参数按值传递
    • 判断数据类型
    • 浮点数精度问题和解决办法
    • 常用方法snippet
    • 实现Promise
    • 防抖和节流
    • 巧用sort排序
  • CSS && HTML

    • CSS也需要性能优化
    • class命名规范
    • em、px、rem、vh、vw 区别
    • CSS揭秘阅读笔记
  • 浏览器

    • 浏览器是如何渲染页面的
    • 重排和重绘
    • BOM浏览器对象模型
    • DOM事件
    • 浏览器存储
  • 数据结构

    • JS实现链表
    • JS实现栈与栈应用
    • JS实现常见排序
    • 哈夫曼编码
    • MD5算法
  • vue原理浅析

    • Vue虚拟dom与Diff算法
    • 前端打包文件的缓存机制
    • vue数组为什么不是响应式
    • v-for为什么不能用index做key
  • 前端工程化

    • 浏览器是如何渲染页面的
    • 前端打包需要gzip压缩吗
    • 前端打包文件的缓存机制
    • webpack loader和plugin
  • 轮子&&组件库

    • 实现水波浪进度球
  • 文字转语音mp3文件
  • 文件上传前后端实现
  • moment.js给定时间获取自然月、周的时间轴
  • 实现文件上传功能
  • 批量下载照片
  • leaflet改变坐标原点
  • 网络

    • 有了MAC地址 为什么还需要IP地址
    • 为什么IP地址老是变
    • 我们为什么需要IPV6
    • TCP与UDP
  • 计算机组成原理

    • ASCII、Unicode、UTF-8和UTF-16
  • VSCode

    • VSCode图片预览插件 Image preview
    • rsync:linux间的高效传输工具
  • leaflet改变坐标原点
  • 补间动画gsap与tween
  • 文字转语音mp3文件
  • JavaScript引入
  • JavaScript高级程序设计阅读笔记
  • Javascript函数参数按值传递传递
  • JS防抖和节流
  • 手写JS常用方法
  • 手写Promise
  • JS Event Loop
  • 重排和重绘
  • em、px、rem、vh、vw 区别
  • css也需要性能优化
  • 图解 js 原型链
  • js函数参数按值传递
  • BOM浏览器对象模型
  • DOM
  • 事件
  • js对象数组sort按需排序
  • 文件上传功能技术选型和前后端实现
  • 前端图片处理
  • 让你的JavaScript代码简单又高效
  • BEM:class命名规范
  • 前端规范-CSS属性那么多(杂),怎么排序
  • TypeScript Tips
  • jsx
  • canvas基础
  • 前端日志
  • 浏览器存储
  • CSS世界阅读笔记
  • CSS揭秘阅读笔记
  • js变量命名常用规范词
  • 你不知道的JavaScript阅读笔记
  • js对象的底层数据结构
  • js判断数据类型
  • JS浮点数精度问题和解决办法
  • js作用域
  • js堆栈溢出和内存泄漏
  • 浏览器是如何渲染页面的
  • 疑难杂症和踩坑问题合集
  • 免费在线API收集
  • 原生JS实现Ajax请求
  • cookie、session、localStorage、sessionStorage的区别
  • Sass与Less
  • arrayBuffer、blob、file对象
  • TypeScript基础
  • 前端
XingYun
2023-07-20
目录

微信小程序基础

# 微信登录

https://developers.weixin.qq.com/ebook?action=get_post_info&docid=000cc48f96c5989b0086ddc7e56c0a

已有的互联网产品在接入小程序会面临一些和登录态相关的问题:怎么获取微信登录态;怎么把微信帐号和自己的帐号进行打通

# 小程序登录流程图

%

# 为什么不直接获取微信用户唯一 id

说到登录,我们可能很正常地想到一个做法:通过 wx.login 直接拿到微信用户的 id 编号[5],再把这个 id 传到自己的后台,从而知道是哪个微信用户在使用我的服务。而我们上述微信登录的流程中并不是通过 wx.login 直接获取微信用户的 id,那直接获取微信用户 id 的做法有什么问题呢?

假设现在我们有个接口,通过 wx.request 请求 https://test.com/getUserInfo?id=1 拉取到微信用户 id 为 1 在我们业务侧的个人信息,那么黑客就可以通过遍历所有的 id,把整个业务侧的个人信息数据全部拉走,如果我们还有其他接口也是依赖这样的方式去实现的话,那黑客就可以伪装成任意身份来操作任意账户下的数据,想想这给业务带来多大的安全风险。

为了避免这样的风险,wx.login 是生成一个带有时效性的凭证,就像是一个会过期的临时身份证一样,在 wx.login 调用时,会先在微信后台生成一张临时的身份证,其有效时间仅为 5 分钟[6]。 然后把这个临时身份证返回给小程序方,这个临时的身份证我们把它称为微信登录凭证 code。如果 5 分钟内小程序的后台不拿着这个临时身份证来微信后台服务器换取微信用户 id 的话,那么这个身份证就会被作废,需要再调用 wx.login 重新生成登录凭证。

由于这个临时身份证 5 分钟后会过期,如果黑客要冒充一个用户的话,那他就必须在 5 分钟内穷举所有的身份证 id,然后去开发者服务器换取真实的用户身份。显然,黑客要付出非常大的成本才能获取到一个用户信息,同时,开发者服务器也可以通过一些技术手段检测到 5 分钟内频繁从某个 ip 发送过来的登录请求,从而拒绝掉这些请求。

开发者服务器和微信服务器通信也是通过 HTTPS 协议,微信服务器提供的接口地址是:

https://api.weixin.qq.com/sns/jscode2session?appid=<AppId>&secret=<AppSecret>&js_code=<code>&grant_type=authorization_code
1

URL 的 query 部分的参数中 , , 就是前文所提到的三个信息,请求参数合法的话,接口会返回以下字段。

我们暂时只要关注前两个字段即可

openid: 就是前文一直提到的微信用户 id,可以用这个 id 来区分不同的微信用户。

session_key: 则是微信服务器给开发者服务器颁发的身份凭证,开发者可以用 session_key 请求微信服务器其他接口来获取一些其他信息,由此可以看到,session_key 不应该泄露或者下发到小程序前端。

# 获取手机号

https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/user-info/phone-number/getPhoneNumber.html

仅针对企业用户开放

<button
  open-type="getPhoneNumber"
  @getphonenumber="getPhoneNumber"
  @click="jump"
>
  立即授权
</button>
1
2
3
4
5
6
7
Page({
  getPhoneNumber(e) {
    console.log(e.detail.code)
  }
})
1
2
3
4
5

通过 code 获取手机号

POST https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=ACCESS_TOKEN
1

返回参数解析:

# 全局配置与页面配置

全局配置

小程序根目录下的 app.json 文件用来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。

完整配置项说明请参考小程序全局配置

以下是一个包含了部分常用配置选项的 app.json :

{
  "pages": ["pages/index/index", "pages/logs/index"],
  "window": {
    "navigationBarTitleText": "Demo"
  },
  "tabBar": {
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页"
      },
      {
        "pagePath": "pages/logs/index",
        "text": "日志"
      }
    ]
  },
  "networkTimeout": {
    "request": 10000,
    "downloadFile": 10000
  },
  "debug": true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

页面配置

每一个小程序页面也可以使用同名 .json 文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json 的 window 中相同的配置项。

完整配置项说明请参考小程序页面配置

例如:

{
  "navigationBarBackgroundColor": "#ffffff",
  "navigationBarTextStyle": "black",
  "navigationBarTitleText": "微信接口功能演示", // 更改title
  "backgroundColor": "#eeeeee",
  "backgroundTextStyle": "light"
}
1
2
3
4
5
6
7

# App:小程序的唯一示例

每个小程序都需要在 app.js 中调用 App 方法注册小程序实例,绑定生命周期回调函数、错误监听和页面不存在监听函数等。

// app.js
App({
  onLaunch(options) {
    // Do something initial when launch.
  },
  onShow(options) {
    // Do something when show.
  },
  onHide() {
    // Do something when hide.
  },
  onError(msg) {
    console.log(msg)
  },
  globalData: 'I am global data'
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

整个小程序只有一个 App 实例,是全部页面共享的。开发者可以通过 getApp 方法获取到全局唯一的 App 实例,获取 App 上的数据或调用开发者注册在 App 上的函数。

// xxx.js
const appInstance = getApp()
console.log(appInstance.globalData) // I am global data
1
2
3

# 小程序页面 Page

对于小程序中的每个页面,都需要在页面对应的 js 文件中进行注册,指定页面的初始数据、生命周期回调、事件处理函数等。

使用 Page 构造器注册页面

简单的页面可以使用 Page() 进行构造。

//index.js
Page({
  data: {
    text: 'This is page data.'
  },
  onLoad: function (options) {
    // 页面创建时执行
  },
  onShow: function () {
    // 页面出现在前台时执行
  },
  onReady: function () {
    // 页面首次渲染完毕时执行
  },
  onHide: function () {
    // 页面从前台变为后台时执行
  },
  onUnload: function () {
    // 页面销毁时执行
  },
  onPullDownRefresh: function () {
    // 触发下拉刷新时执行
  },
  onReachBottom: function () {
    // 页面触底时执行
  },
  onShareAppMessage: function () {
    // 页面被用户分享时执行
  },
  onPageScroll: function () {
    // 页面滚动时执行
  },
  onResize: function () {
    // 页面尺寸变化时执行
  },
  onTabItemTap(item) {
    // tab 点击时执行
    console.log(item.index)
    console.log(item.pagePath)
    console.log(item.text)
  },
  // 事件响应函数
  viewTap: function () {
    this.setData(
      {
        text: 'Set some data for updating view.'
      },
      function () {
        // this is setData callback
      }
    )
  },
  // 自由数据
  customData: {
    hi: 'MINA'
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 使用 Component 构造器构造页面

Page 构造器适用于简单的页面。但对于复杂的页面, Page 构造器可能并不好用。

此时,可以使用 Component 构造器来构造页面。 Component 构造器的主要区别是:方法需要放在 methods: { } 里面。

代码示例:

Component({
  data: {
    text: 'This is page data.'
  },
  methods: {
    onLoad: function (options) {
      // 页面创建时执行
    },
    onPullDownRefresh: function () {
      // 下拉刷新时执行
    },
    // 事件响应函数
    viewTap: function () {
      // ...
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

这种创建方式非常类似于 自定义组件 ,可以像自定义组件一样使用 behaviors 等高级特性。

# 小程序的 Store: behaviors

页面可以引用 behaviors 。 behaviors 可以用来让多个页面有相同的数据字段和方法。

// my-behavior.js
module.exports = Behavior({
  data: {
    sharedText: 'This is a piece of data shared between pages.'
  },
  methods: {
    sharedMethod: function () {
      this.data.sharedText === 'This is a piece of data shared between pages.'
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
// page-a.js
var myBehavior = require('./my-behavior.js')
Page({
  behaviors: [myBehavior],
  onLoad: function () {
    this.data.sharedText === 'This is a piece of data shared between pages.'
  }
})
1
2
3
4
5
6
7
8

# 页面路由

在小程序中所有页面的路由全部由框架进行管理。

注意事项

  • navigateTo, redirectTo 只能打开非 tabBar 页面。
  • switchTab 只能打开 tabBar 页面。
  • reLaunch 可以打开任意页面。
  • 页面底部的 tabBar 由页面决定,即只要是定义为 tabBar 的页面,底部都有 tabBar。
  • 调用页面路由带的参数可以在目标页面的 onLoad 中获取。

# 事件列表

事件分类
事件分为冒泡事件和非冒泡事件:

  • 冒泡事件:当一个组件上的事件被触发后,该事件会向父节点传递。
  • 非冒泡事件:当一个组件上的事件被触发后,该事件不会向父节点传递。

WXML 的冒泡事件列表:

注:除上表之外的其他组件自定义事件如无特殊声明都是 非冒泡事件,如 form 的 submit 事件,input 的 input 事件,scroll-view 的 scroll 事件

# 绑定并阻止事件冒泡

除 bind 外,也可以用 catch 来绑定事件。与 bind 不同, catch 会阻止事件向上冒泡。

例如在下边这个例子中,点击 inner view 会先后调用 handleTap3 和 handleTap2 (因为 tap 事件会冒泡到 middle view,而 middle view 阻止了 tap 事件冒泡,不再向父节点传递),点击 middle view 会触发 handleTap2,点击 outer view 会触发 handleTap1。

<view id="outer" bindtap="handleTap1">
  outer view
  <view id="middle" catchtap="handleTap2">
    middle view
    <view id="inner" bindtap="handleTap3"> inner view </view>
  </view>
</view>
1
2
3
4
5
6
7

# 获取界面上 dom 节点信息

const query = wx.createSelectorQuery()
query.select('#the-id').boundingClientRect(function (res) {
  res.top // #the-id 节点的上边界坐标(相对于显示区域)
})
query.selectViewport().scrollOffset(function (res) {
  res.scrollTop // 显示区域的竖直滚动位置
})
query.exec()
1
2
3
4
5
6
7
8

# 样式穿透:让 css 影响子组件样式

Component({
  options: {
    styleIsolation: 'shared'
  }
})
1
2
3
4
5

# 小程序监听数据变化

 observers: {
    inputName: function (e) {
      // 使用 setData 设置 this.data.some.subfield 时触发
      console.log('inputName', e)
    },
    dateText: function (e) {
      console.log('dateText', e)
    }
  },
1
2
3
4
5
6
7
8
9

# 小程序利用 wxs 实现类似 computed 计算属性

// utils.wxs
module.exports = {
  msg: 'hello world',
  handleMatchStatus: function (source) {
    switch (source) {
      case '111':
        return '已支付'
      case '222':
        return '支付失败'
      case '333':
        return '退款中'
      default:
        return 'other'
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- .wxml -->
<wxs module="utils" src="./game-qr-utils.wxs"></wxs>
<view class="computed-data">
  {{utils.msg}}{{utils.handleMatchStatus(selectedPlayer)}}
</view>
1
2
3
4
5
// .ts文件
Page({
  data: {
    userInfo: {},
    playerList: [],
    selectedPlayer: '111'
  }
})
1
2
3
4
5
6
7
8

这样标签 computed-data 里的内容就可以根据 data 中的 selectedPlayer 数据实时变化

# 小程序路由携带参数

//more...
//假设当前页面路由为'/pages/demo/demo?a=1&b=2'
onLoad: function (options) {       //options用于接收上个页面传递过来的参数
    console.log(options.a, options.b); // =>1, 2
})
//more...

1
2
3
4
5
6
7

# 小程序 下载上传文件资源

  test() {
    wx.downloadFile({
      url: 'http://172.27.15.109/img/system-logo.d3c30f52.png', //仅为示例,并非真实的资源
      success(res) {
        // 只要服务器有响应数据,就会把响应内容写入文件并进入 success 回调,业务需要自行判断是否下载到了想要的内容
        if (res.statusCode === 200) {
          wx.saveImageToPhotosAlbum({
            filePath: res.tempFilePath,
            success(res) {
              console.log('保存成功')
            }
          })
        }
      }
    })
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

上传

wx.chooseImage({
  success(res) {
    const tempFilePaths = res.tempFilePaths
    wx.uploadFile({
      url: 'https://example.weixin.qq.com/upload', //仅为示例,非真实的接口地址
      filePath: tempFilePaths[0],
      name: 'file',
      formData: {
        user: 'test'
      },
      success(res) {
        const data = res.data
        //do something
      }
    })
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 小程序:调用手机振动

wx.vibrateShort({ type: 'light' })

wx.vibrateLong()
1
2
3

# 微信小程序配置 ts import alias

%

使用 resolveAlias 配置项用来自定义模块路径的映射规则。

配置了之后,会对 require 里的模块路径进行规则匹配并映射成配置的路径。

如果命中多条映射规则,则取最长的命中规则。

如果需要修改映射名

需要更改更改 tsconfig.json 和 app.json 两个地方的配置

  1. app.json
{
  "resolveAlias": {
    "@/*": "/*"
  }
}
1
2
3
4
5
  1. tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./miniprogram/*"]
    }
  }
}
1
2
3
4
5
6
7

# 微信小程序-设置全局的颜色变量

  1. 在全局 app.wxss 样式中 设置 变量颜色
/* 主题颜色 通过变量来实现 */
page {
  --themeColor: #e33e33;
}
1
2
3
4
  1. 使用
.searchinput {
  //使用 全局定义的变量 颜色
  background-color: var(--themeColor);
}
1
2
3
4
上次更新: 2023/07/15, 08:37:32
最近更新
01
JavaScript-test
07-20
02
二维码的原理
07-20
03
利用ChatGPT优化代码
07-20
更多文章>
Theme by Vdoing | Copyright © 2021-2023 XingYun | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式