微信原生小程序学习笔记

小程序笔记

跨平台框架

  • uni-app
    • 使用 Vue 开发,可以发布到多端,ios,安卓,web,各种小程序
  • taro
    • 支持 React/Vue/Nerv 等框架
    • 更加灵活

小程序的配置和架构

双线程模型

web-view 和 jsCore,渲染层和逻辑层

  • WXML 和 WXSS 运行于渲染层,使用 WebView 渲染
  • JS 运行于逻辑层,使用 JsCore 运行
  • 两个线程都会经由微信客户端进行中转交互

生命周期

面试官:说说微信小程序的生命周期函数有哪些? | web 前端面试 - 面试官系列 (vue3js.cn)

生命周期 | 微信开放文档 (qq.com)

小程序生命周期

双线程

App.js

获取进入小程序的方式

场景值

场景值列表

在 onLaunch 和 onShow 生命周期回调函数中,有 options 参数,其中有 scene 值,可以用于判断

onShow(options) {
console.log("onShow");
console.log(options);
// 判断进入小程序的方式
console.log(options.scene);
}

定义全局数据

// app.js
globalData: {
token: "11111",
userInfo: {
avatarUrl: "avatarUrl",
city: "city",
country: "country",
},
},

使用:

//其他页面.js
onLoad() {
const app = getApp();
const token = app.globalData.token;
const userInfo = app.globalData.userInfo;
console.log(token, userInfo);
this.setData({ userInfo });
},

初始化操作

  • 登录操作
  • 读取本地数据,如 token
  • 请求所需数据
// 从本地获取数据
const token = wx.getStorageSync('token')
const userInfo = wx.getStorageSync('userInfo')
console.log('Storage:', token, userInfo)
if (!token || !userInfo) {
// 将数据存到Storage
wx.setStorageSync('token', 'token in storage')
wx.setStorageSync('userInfo', { nickname: 'juns', level: 100 })
}
// 存入全局数据
this.globalData.token = token
this.globalData.userInfo = userInfo

Page 函数

注册时一般要做的

  • 在生命周期函数中发送网络请求
  • 初始化数据
  • 监听事件绑定

常见组件等

获取用户信息

getUserInfo() {
wx.getUserProfile({
desc: "test",
}).then((res) => {
console.log(res.userInfo);
});
},

获取用户手机号,不对个人开发者开放

<t-button
theme="light"
size="large"
open-type="getPhoneNumber"
bindgetphonenumber="getPhoneNumber"
>
获取手机号
</t-button>
getPhoneNumber(e) {
console.log(e);
},

图片常用属性,占满给的宽度(默认 w320,h240),高度会自动计算

<image
src="...."
mode="widthFix"
/>

展示用户本地图片

<view class="container">
<view class="imgContainer">
<image
src="{{chooseImgUrl}}"
mode="widthFix"
></image>
</view>
<t-button bindtap="chooseImg">选择图片</t-button>
</view>
Page({
data: {
chooseImgUrl: '',
},
chooseImg() {
wx.chooseMedia({
mediaType: 'image',
}).then(res => {
console.log(res)
const url = res.tempFiles[0].tempFilePath
this.setData({ chooseImgUrl: url })
})
},
})

数据双向绑定

<input
class="input1"
placeholder="请输入文字"
model:value="{{inputVal}}"
/>
<text>{{inputVal}}</text>

WXSS 尺寸单位

rpx(responsive pixel):可以根据屏幕宽度自适应,规定屏幕宽度是 750rpx

iPhone6 中:1px===2rpx

WXML 语法

  • v-if 变成了

    • wx:if
    • wx:elif
    • wx:else
  • v-show 变成了hidden

  • block 就是用来包裹的,不加 class,id

WXS

小程序的脚本语言,在 WXML 中不能直接调用 Page 里面的函数,所以用 WXS 来解决

在 WXML 内写法:

<wxs module="format">
function formatPrice(price){ return "¥"+price; } module.exports={
formatPrice:formatPrice }
</wxs>
<view class="container">
<block
wx:for="{{list}}"
wx:key="*this"
>
<view>{{format.formatPrice(item)}}</view>
</block>
</view>

引入写法

//WXS
function formatPrice(price) {
return '¥' + price
}
module.exports = {
formatPrice: formatPrice,
}
<wxs
module="format"
src="/utils/format.wxs"
></wxs>

<view class="container">
<block
wx:for="{{list}}"
wx:key="*this"
>
<view>{{format.formatPrice(item)}}</view>
</block>
</view>

事件处理

参数传递

data-name="why",然后 js 里面用 event 传递,event.target.dataset

mark 也可以传递数据,会向上冒泡合并,上面的需要是 currentTarge

<view mark:name="nael"> </view>

组件化开发

  • 需要在 json 里面注册使用

样式

  • 组件内不能id属性标签选择器

  • 外部的标签选择器会对组件内样式产生影响,其他不会

  • Component对象里面可以传入options属性,其中有styleIsolation属性

    • isolated表示启用样式隔离,组件内外 class 指定的样式不会影响
    • apply-shared表示页面可以影响组件,反过来不会
    • shared表示双向影响
    // components/section-info/section-info.ts
    Component({
    options: {
    styleIsolation: 'apply-shared',
    },
    })

通信

数据 properties

使用的页面<section-info title="www" desc="哇哦哇哦" />

// components/section-info/section-info.ts
Component({
properties: {
title: {
value: '默认标题',
type: String,
},
desc: {
value: '默认描述',
type: String,
},
},
})

样式 externalClasses

组件 wxml

<view class="container">
<h1>{{title}}</h1>
<h3 class="info">{{desc}}</h3>
</view>

组件 js

// components/section-info/section-info.ts
Component({
properties: {
title: {
value: '默认标题',
type: String,
},
desc: {
value: '默认描述',
type: String,
},
},
externalClasses: ['info'],
})

页面 wxml<section-info title="www" desc="哇哦哇哦" info="test" />

页面 css

.test {
background-color: slateblue;
}

插槽

slot,但是小程序不支持默认值

  • 单插槽
<view class="container">
<view class="header">Header</view>
<view class="content">
<slot></slot>
</view>
<view class="footer">Footer</view>
</view>
<my-slot>
<t-button>按钮</t-button>
</my-slot>
  • 多个插槽,需要给slot加上name属性,用的地方要slot=""组件 js 里面也要选择使用多插槽
<view class="container">
<view class="left">
<slot name="left"></slot>
</view>
<view class="center">
<slot name="center"></slot>
</view>
<view class="right">
<slot name="right"></slot>
</view>
</view>
// components/mul-slot/mul-slot.ts
Component({
options: {
multipleSlots: true,
},
})
<mul-slot>
<text
slot="left"
class="left"
>我是左边</text
>
<text
slot="center"
class="center"
>我是中间</text
>
<text
slot="right"
class="right"
>我是右边</text
>
</mul-slot>

混入

behaviors,就像 vue 以前的mixins一样,现在叫hooks的多

生命周期

  1. created
  2. attached
  3. ready,官方说除了这个的三个比较重要
  4. detached
  5. 更多见文档

总结

Component构造器

  • properties : 定义传入的属性
  • data : 定义内部属性
  • methods : 定义方法
  • options : 额外配置
  • externalClasses : 引用外部样式
  • observers : 属性和数据监听
  • pageLifetimes : 组件所在页面的生命周期
  • lifetimes : 组件生命周期

API 调用

网络请求

wx.request

RequestTask

onLoad() {
// 发送网络请求
wx.request({
url: "https://v1.hitokoto.cn/",
success: (res) => {
const data = res.data;
// @ts-ignore
this.setData({ sentence: data.hitokoto });
},
fail: (err) => {
console.log("err:", err);
},
});
}

域名配置

生产环境需要配置只能向固定的域名发动请求,要去小程序后台设置

注意点

  • 只支持 https 和 wss
  • 不能用 IP 地址
  • 可以配置端口,但只能那一个端口了
  • 不配置端口的话,请求的 url 中也不能有端口
  • 域名要备案
  • 不支持配置父域名

封装请求

Promise 封装使用

函数封装
// 封装成函数
export function myRequest(options) {
return new Promise((resolve, reject) => {
wx.request({
...options,
success: res => {
resolve(res.data)
},
fail: reject,
})
})
}

常规使用

// 使用
import { myRequest } from '../../service/index'

Page({
data: {},
onLoad() {
myRequest({
url: 'https://v1.hitokoto.cn/',
}).then(res => {
console.log(res)
})
},
})

async/await 使用,但是不如 promise,必须等前面的请求结束了后面的才发送,效率不高

import { myRequest } from '../../service/index'

Page({
data: {},
async onLoad() {
const res = await myRequest({ url: 'https://v1.hitokoto.cn/' })
console.log(res)
},
})

把请求封装到函数里面,不会堵塞

import { myRequest } from '../../service/index'

Page({
data: {},
onLoad() {
this.getData()
},
async getData() {
const res = await myRequest({ url: 'https://v1.hitokoto.cn/' })
console.log(res)
},
})
类封装
// 封装成类
class HYRequest {
constructor(baseURL) {
this.baseURL = baseURL
}

request(options) {
const { url } = options
return new Promise((resolve, reject) => {
wx.request({
...options,
url: this.baseURL + url,
success: res => {
resolve(res.data)
},
fail: reject,
})
})
}

get(options) {
return this.request({ ...options, method: 'get' })
}

post(options) {
return this.request({ ...options, method: 'post' })
}
}

export const hyRequest = new HyRequest()

弹窗调用

showToast,showModol,showLoading,showActionSheet

微信文档

分享回调

onShareAppMessage,监听用户点击转发按钮(button open-type="share"),或者右上角菜单的转发,并自定义内容

需要return一个Object自定义转发内容

// 转发
onShareAppMessage() {
return {
title: "转发",
path: "/pages/index/index",
imageUrl: "自定义图片路径,可不选",
};
},

获取设备信息

用户信息

// 获取用户信息1
onGetUserInfo() {
wx.getUserInfo({
success: (res) => {
console.log(res);
},
});
},
// 获取用户信息2
onGetUserProfile() {
wx.getUserProfile({
desc: "test",
success: (res) => {
console.log(res);
},
fail: (err) => {
console.log(err);
},
});
},
// 获取用户设备信息
// 获取手机基本信息
onGetSystemInfo() {
wx.getSystemInfo({
success: (res) => {
console.log(res);
},
});
},
// 获取手机位置信息(需要开通权限才有用)
onGetLocation() {
wx.getLocation({
success: (res) => {
console.log(res);
},
});
},

Storage 存储

同步存取数据:执行完上一行才执行下一行

  • wx.setStorageSync(string key, any data)
  • wx.getStorageSyne(string key)
  • wx.removeStorageSync(string key)
  • wx.clearStorageSync()

异步存取:适用于一个地方存,另一个地方取

  • wx.setStorage(Object objece)
  • wx.getStorage(Object objece)
  • wx.removeStorage(Object objece)
  • wx.clearStorage(Object objece)
Page({
// 同步
onLocalStorage() {
wx.setStorageSync('name', 'die')
wx.setStorageSync('age', 18)
wx.setStorageSync('work', ['die', 'for'])
},
onClearStorage() {
wx.clearStorageSync()
},
// 异步
onLocalStorageAsync() {
wx.setStorage({
key: 'books',
data: ['vue', 'react'],
success: res => {
console.log(res)
},
})
},
onClearStorageAsync() {
wx.clearStorage()
},
})

页面跳转

名称 功能说明
wx.switchTab 跳转到 tabBar 页面,关闭其他所有非 tabBar 页面
wx.reLaunch 关闭所有页面,打开到应用内的某页面
wx.redirectTo 关闭当前页面,跳转到新页面
wx.navigateTo 保留当前页面,跳转到新页面
wx.nabitageBack 关闭当前页面,返回上个页面或多级页面

navigateTo

  • ==不能跳到 tabBar 页面==
  • ==页面栈最多十层==
onNextPage() {
const data = "sss";
wx.navigateTo({
url: `/pages/10_learn/index?data=${data}`,
});
},

数据传递