微信小程序

小程序的开始

developers.weixin.qq.com/miniprogram...

js 复制代码
全新的邮箱注册;
AppID;
成员

开发者工具创建项目

  • AppID: 可以先用 测试号 进行体验
  • 后端服务:不使用云服务
  • 模板选择:不使用模板

项目目录介绍

arduino 复制代码
project-root/
├── pages/                  // 页面目录
│   ├── index/              // 首页
│   │   ├── index.js         // 页面逻辑
│   │   ├── index.json       // 页面配置
│   │   ├── index.wxml       // 页面结构
│   │   └── index.wxss       // 页面样式
│   └── logs/               // 日志页
│       ├── logs.js
│       ├── logs.json
│       ├── logs.wxml
│       └── logs.wxss
├── animal/           // 分包animal
│   └── pages/
│       ├── cat/
│   │   ├── cat.js         
│   │   ├── cat.json       
│   │   ├── cat.wxml       
│   │   └── cat.wxss      
├── utils/                  // 工具类目录
│   └── util.js             // 工具函数
├── app.js                  // 小程序逻辑
├── app.json                // 小程序公共配置
├── app.wxss                // 小程序公共样式
├── sitemap.json            // 小程序搜索索引配置
└── project.config.json     // 项目配置文件
app.js 小程序的主逻辑文件,定义小程序的全局生命周期函数和全局变量。
js 复制代码
// app.js
import {
  sleep
} from './utils/index'
App({
  onLaunch(options) {
    // 初始化应用 或者 小程序销毁 冷启动时执行的钩子
    console.log('App---onLaunch', options);
    this.getUserInfo()
  },
  onShow(options) {
    // 热启动  冷启动时执行 + 后台切到前台执行
    console.log('App---onShow', options);
  },
  onHide() {
    // 前台切到后台执行
    console.log('App---onHide');
  },
  onError(msg) {
    console.log('App---onError', msg);
  },
  // 获取用户信息并返回 Promise
  getUserInfo() {
    if (!this.globalData.userInfoPromise) {
      this.globalData.userInfoPromise = async () => {
        // 模拟请求接口
        await sleep(2000)
        return {
          id: "7979",
          userName: "zs"
        }
      }
      return this.globalData.userInfoPromise;
    }
  },
  globalData: {  // 整个应用公用的数据
    age: 19,
    user: {},
    userInfoPromise: null
  },
  randomId() {  // 整个应用公用的方法
  },
})


// 其他页面使用
const app = getApp()
Page({
  data: {
    num: 0,
    user: {},
  },
  onShow(){
    console.log('[index]:onShow---start.globalData', app.globalData);
    console.log('[index]:onShow---start---randomId', app.randomId());
    this.getUser()
  },
  async getUser(){
   const res =  await app.globalData.userInfoPromise()
   this.setData({ user: res })
  }
  
});

小程序JSON 配置

app.json

developers.weixin.qq.com/miniprogram...

小程序的所有页面路径、界面表现、网络超时时间、底部 tab 等

json 复制代码
{
  "pages": [
    // 应用根目录的页面路径
    "pages/index/index"
  ],
  "subPackages": [
    // 分包结构配置
    {
      "root": "animal", // 分包根目录
      "pages": ["pages/cat/cat"]
    },
    {
      "root": "fruit",
      "pages": ["pages/apple/apple"]
    }
  ],
  "tabBar": {
    // 底部 tab 栏的表现
    "list": [
      {
        "pagePath": "pages/index/index",
        "text": "首页"
      },
      {
        "pagePath": "pages/logs/index",
        "text": "日志"
      }
    ]
  },
  "window": {
    // 全局的默认窗口表现
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "",
    "navigationBarTextStyle": "black"
  },
  "usingComponents": {
    // 全局自定义组件配置
    "dialog": "/component/dialog/dialog",
    "van-toast": "@vant/weapp/toast/index"
  },
  "networkTimeout": {
    // 网络超时时间
    "request": 10000,
    "downloadFile": 10000
  },
  "requiredPrivateInfos": ["getLocation"],
  "debug": true
}
project.config.json 项目配置

developers.weixin.qq.com/miniprogram...

json 复制代码
 "appid": "xxx",
 "setting":{  // 可以开发者工具-详情-本地设置可以对应上
    "urlCheck": false,  // 是否检查安全域名和 TLS 版本
    "es6": true, // 是否启用 es6 转 es5
    "enhance": true, // es6 和 enhance 需同时为 true/false,对应于 将 JS 编译成 ES5
    "postcss": true, // 上传代码时样式是否自动补全
 }
page.json 页面配置

developers.weixin.qq.com/miniprogram...

js 复制代码
{
  "navigationStyle": "custom", // 自定义导航栏,只保留右上角胶囊按钮。
  "enablePullDownRefresh": true, // 开启当前页面下拉刷新
}

// 自定义导航栏返回和title盒子可能需要 获取菜单按钮(右上角胶囊按钮)的布局位置信息 以保持底部对齐
const { height, top } = wx.getMenuButtonBoundingClientRect() 
height + top 即右上角胶囊按钮的位置

WXML 模板

基础组件

developers.weixin.qq.com/miniprogram...

js 复制代码
view 
text    [selectable]
button  [type size plain disabled loading]
image   [src  mode lazy-load]
picker  普通选择器 | 多列选择器 | 时间选择器 | 日期选择器 | 省市区选择器
navigator [url open-type]
swiper swiper-item 
scroll-view 
web-view

事件 bindxxx="" catchxxx=""

developers.weixin.qq.com/miniprogram...

js 复制代码
<view id="tapTest" data-hi="Weixin" bindtap="tapName"> Click me! </view>

Page({
  tapName: function(event) {
    console.log(event)
  }
})

与 bind 不同, catch 会阻止事件向上冒泡

小程序语法

developers.weixin.qq.com/miniprogram...

  • 数据绑定
  • 列表渲染
  • 条件渲染
js 复制代码
<block wx:for="{{list}}" wx:key="index">
    <view bindtap='onTap' data-item="{{item}}">
    {{index}} --- {{item.text}}
    </view>
</block>

<view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>
<view wx:elif="{{view == 'APP'}}"> APP </view>
<view wx:else="{{view == 'MINA'}}"> MINA </view>

Page({
  data: {
    view: "APP",
    list:[
      {id:"11", text:"zs"},
      {id:"13", text:"ls"},
      {id:"14", text:"ww"},
    ]
  },
  onTap(event){
   console.log('onTap---event', event)
   const {item} = event.currentTarget.dataset
   console.log('onTap---item', item) //  {id:"14", text:"ww"}
  },
});
js 复制代码
  <view>{{num}}</view>
  <button bindtap="changeNum"> Change normal num </button>
  <view>{{array[0].text}}</view>
  <button bindtap="changeItemInArray"> Change Array data </button>
  <view>{{object.text}}</view>
  <button bindtap="changeItemInObject"> Change Object data </button>
  <view>{{newField.text}}</view>
  <button bindtap="addNewField"> Add new data </button>

  // index.js
Page({
  data: {
    num: 0,
    array: [{
      text: 'init data'
    }],
    object: {
      text: 'init data'
    }
  },
  changeNum: function () {
    this.data.num = 1
    this.setData({
      num: this.data.num
    })
  },
  changeItemInArray: function () {
    // 对于对象或数组字段,可以直接修改一个其下的子字段,这样做通常比修改整个对象或数组更好
    this.setData({
      'array[0].text': 'changed data'
    })
  },
  changeItemInObject: function () {
    this.setData({
      'object.text': 'changed data'
    });
  },
  addNewField: function () {
    // 并且不需要在 this.data 中预先定义
    this.setData({
      'newField.text': 'new data'
    })
  }
});

WXSS

developers.weixin.qq.com/miniprogram...

  • 尺寸单位 rpx(responsive pixel): 可以根据屏幕宽度进行自适应
  • 样式导入
css 复制代码
@import "common.wxss";  // @import后跟需要导入的外联样式表的相对路径,用;表示语句结束
.middle-p {
  padding:15px;
}
  • 内联样式
css 复制代码
<view style="color:{{color}};" />
  • 选择器 类 id 标签 并集

小程序运行机制

developers.weixin.qq.com/miniprogram...

特性 冷启动 热启动
启动条件 首次启动或销毁后重新启动 从后台切换到前台
资源加载 重新下载代码包和资源文件 无需重新加载资源
生命周期 触发 onLaunch onLoad onShow 仅触发 onShow(app和页面)
运行状态 完全重新初始化 保留之前的运行状态
启动速度 较慢 较快
适用场景 首次打开或长时间未使用后重新打开 从后台切换回小程序
  • 切后台的方式包括但不限于以下几种:

    点击右上角胶囊按钮离开小程序
    iOS 从屏幕左侧右滑离开小程序
    安卓点击返回键离开小程序
    小程序前台运行时直接把微信切后台(手势或 Home 键)
    小程序前台运行时直接锁屏

自定义组件

developers.weixin.qq.com/miniprogram...

组件基础

  • 组件的声明与使用
js 复制代码
在 组件名.json 中声明组件:
{
  "component": true
}
  • 组件的属性(Properties) 在微信小程序中,不能直接将一个方法作为属性值传递给子组件。属性值只能是基本类型(如字符串、数字、布尔值)或对象/数组等 JSON 兼容的数据结构,而不能直接传递函数。
js 复制代码
<slot name="before"></slot>
<view>{{ title }}</view>
<view>{{ count }}</view>
<slot name="after"></slot>

Component({
  behaviors:[require('../../behaviors/my-behavior.js')], // 类似mixins
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  properties: { // 接收父组件传递的属性
    title: {
      type: String, // 属性类型
      value: '默认标题', // 默认值
    },
    count: {
      type: Number,
      value: 0,
      observer(newValue, oldValue){ // 数据变化时触发
        console.log('count---observer---newValue', newValue, oldValue);
      }
    },
  },
  data: { // 组件内部数据
    kid: "97"
  },
  observers: { // 监听数据发生变化
    'kid'(newValue) {
      console.log('observers---kid', newValue);
    }
  },
  lifetimes: { // 组件生命周期
    attached() { 
      console.log('组件已挂载');
    },
    detached() {
      console.log('组件已卸载');
    },
  },
  methods: { // 组件内部方法
    onChangeKid() {
      console.log('myBehaviorData', this.data.myBehaviorData); // 获取 behaviors 中data数据
      this.sharedMethod() // 调用 behaviors 中的方法
      this.setData({
        kid: 100
      })
    },
    onTap() {
      const myEventDetail = {
        age: 19
      } 
      this.triggerEvent('myevent', myEventDetail)
    },
    _buttonMet() {
      console.log('_buttonMet---start');
    }
  },
});
  • 组件的插槽(Slot)
js 复制代码
// my-component 组件 默认插槽
<view>
  <slot></slot>
</view>

// 父组件
<my-component>
  <view>插入的内容</view>
</my-component>

// my-component 组件 具名插槽
<view>
  <slot name="header"></slot>
  <slot name="footer"></slot>
</view>

// 父组件
<my-component>
  <view slot="header">头部内容</view>
  <view slot="footer">底部内容</view>
</my-component>
  • 组件的数据监听器 observers
  • 组件的行为复用 behaviors
js 复制代码
// my-Behavior.js  
module.exports = Behavior({
  behaviors: [],
  properties: {
    myBehaviorProperty: {
      type: String
    }
  },
  data: {  
    myBehaviorData: {
      age:6
    }
  },
  attached: function(){},
  methods: {
    sharedMethod() {
      console.log('共享方法');
    },
  }
})
  • 组件的外部样式 externalClasses
  • 组件的样式隔离
js 复制代码
  options: {
    styleIsolation: 'isolated', // 样式隔离
  },

组件的通信

developers.weixin.qq.com/miniprogram...

  • 父组件向子组件传递数据 [属性传递 + 父组件获取子组件实例并调用子组件内的方法]
  • 子组件向父组件传递数据 [定义自定义事件并 triggerEvent]
js 复制代码
// 父组件
<my-button user="{{user}}" count="{{count}}" bind:myevent="onMyevent" id="my-button"></my-button>
<button bindtap="onDataToChild">获取子组件实例并调用子实例方法传递数据</button>

const app = getApp()
Page({
  data: {
    count: 1,
    user: { age: 19, name: "bwf"},
  },
  onMyevent(event){
    // 父组件自定义事件接收子组件传递的数据
    console.log('onMyevent---detail', event.detail); // { age: 999, name: "zs" }
  },
  onDataToChild(){
    // selectComponent() 获取子组件实例对象 这样就可以直接访问组件的任意数据和方法
    const child = this.selectComponent('#my-button'); 
    child.onShow(this.data.user) 
  },
});


// 子组件
<view>user.name:{{user.name}}</view>
<view>count:{{count}}</view>
<view bind:tap="onTap">向父组件传递数据</view>

Component({
  options: {
    multipleSlots: true // 在组件定义时的选项中启用多slot支持
  },
  properties: { // 组件的属性列表
    user: {
      type: Object,
      observer(newValue, oldValue) {
        console.log('user---observer---newValue', newValue, oldValue);
      }
    },
    count: {
      type: Number,
    },
  },

  methods: {
    onTap() {
      const myEventDetail = { age: 999, name: "zs" } 
      // triggerEvent触发父组件自定义的事件,并传递数据
      this.triggerEvent('myevent', myEventDetail) 
    },
    onShow(data){
      console.log('onShow---data', data) // { age: 19, name: "bwf" }
    }
  },
})

app.js 和 页面xx.js 和 组件.js 配置上的区别

  • app.js App 是整个小程序的入口,用于定义全局的配置和行为
js 复制代码
App({
  onLaunch(options) { ... },  // 小程序初始化时触发
  onShow(options) { ... },    // 小程序启动或从后台进入前台时触发
  onHide() { ... },           // 小程序从前台进入后台时触发
  globalData: { ... },        // 全局数据
  aFn(){},                    // 自定义全局方法
});
  • 页面xx.js Page 用于定义单个页面的配置和行为。
js 复制代码
Page({
  data: { ... },              // 页面数据
  onLoad(options) { ... },    // 页面加载时触发
  onShow() { ... },           // 页面显示时触发
  onReady() { ... },          // 页面初次渲染完成时触发
  onHide() { ... },           // 页面隐藏时触发
  onUnload() { ... },         // 页面卸载时触发
  customMethod() { ... },     // 自定义方法
});
  • 组件xx.js Component
js 复制代码
Component({
  properties: { ... },     // 组件接收父传递过来的属性
  data: { ... },           // 组件内部数据
  methods: { ... },        // 组件方法(必须放在 methods 中)
  lifetimes: {      // 组件生命周期
    created() {},   // 组件实例刚被创建时触发(不能调用 setData)
    attached() {},  // 组件实例进入页面节点树时触发
    ready() {},     // 组件布局完成(类似页面的 onReady)
    moved() {},     // 组件实例被移动到节点树另一个位置时触发
    detached() {},  // 组件实例从页面节点树移除时触发
  },     
  pageLifetimes: {  // 页面生命周期(仅在组件所在页面触发)
    show() {},      // 页面显示时触发
    hide() {},      // 页面隐藏时触发
  },  
});

网络服务

网络请求 API:wx.request

js 复制代码
wx.request({
  url: 'https://api.example.com/data', // 请求地址
  method: 'GET', // 请求方法(GET、POST 等)
  data: { // 请求参数
    key1: 'value1',
    key2: 'value2',
  },
  header: { // 请求头
    'Content-Type': 'application/json',
  },
  success(res) { // 请求成功回调
    console.log(res.data); // 返回的数据
  },
  fail(err) { // 请求失败回调
    console.error('请求失败', err);
  },
  complete() { // 请求完成回调(无论成功或失败)
    console.log('请求完成');
  },
});

封装网路请求

js 复制代码
// utils/request.js
const request = (url, method = 'GET', data = {}, header = {}) => {
  
  // 请求拦截:添加 token
  const token = wx.getStorageSync('token');
  if (token) {
    header.Authorization = `Bearer ${token}`;
  }

  return new Promise((resolve, reject) => {
    wx.request({
      url: `https://api.example.com${url}`,
      method,
      data,
      header: {
        'Content-Type': 'application/json',
        ...header,
      },
      success(res) {
        // '0000' 为自定义的业务成功码,可根据实际情况替换
        if (res.statusCode === 200 && res.data.code === '0000') {
          resolve(res.data.data);
        } else {
          reject(res.data);
        }
      },
      fail(err) {
        reject(err);
      },
    });
  });
};

// GET 请求封装
const get = (url, data = {}) => {
  return request(url, 'GET', data);
};

// POST 请求封装
const post = (url, data = {}) => {
  return request(url, 'POST', data);
};

module.exports = { get, post };

文件上传

js 复制代码
wx.uploadFile({
  url: 'https://api.example.com/upload',
  filePath: '文件路径',
  name: 'file',
  formData: { // 其他表单数据
    key: 'value',
  },
  header: {},
  success(res) {
    console.log(res.data);
  },
  fail(err) {
    console.error('上传失败', err);
  },
});

注意点

域名限制:小程序只能请求已配置到 request 合法域名列表中的地址。 HTTPS:小程序要求请求的地址必须是 HTTPS。 并发限制:小程序最多同时发起 10 个网络请求。 在小程序后台配置合法域名,否则无法发起网络请求。 开发阶段:在开发者工具中勾选「不校验合法域名、web-view(业务域名)、TLS 版本以及 HTTPS 证书」

rust 复制代码
微信公众平台 「开发」->「开发设置」 在「服务器域名」中配置 request 合法域名

存储

developers.weixin.qq.com/miniprogram...

  • 存储 对本地缓存进行读写和清理 wx.setStorage/wx.setStorageSync、wx.getStorage/wx.getStorageSync、wx.clearStorage/wx.clearStorageSync,wx.removeStorage/wx.removeStorageSync

  • 隔离策略 同一个微信用户,同一个小程序 storage 上限为 10MB。storage 以用户维度隔离,同一台设备上,A 用户无法读取到 B 用户的数据;不同小程序之间也无法互相读写数据。

分包

developers.weixin.qq.com/miniprogram...

页面间跳转

  • wx.navigateTo
js 复制代码
用途:保留当前页面,跳转到新页面(页面栈新增一层)。[当前页面的数据并不会被清空重置]
特点:可通过返回按钮回到原页面。

wx.navigateTo({
  url: '/pages/detail/detail?id=123&name=bwf'
})

// detail接收参数
Page({
  onLoad(options) {
    const { id, name } = options; // 123  bwf
  }
})
  • wx.redirectTo
js 复制代码
用途:关闭当前页面,跳转到新页面(替换当前页面栈)。
特点:无法返回原页。
  • wx.redirectTo
js 复制代码
用途:关闭当前页面,跳转到新页面(替换当前页面栈)。
特点:无法返回原页。
  • wx.switchTab
js 复制代码
用途:跳转到 tabBar 页面(需在 app.json 中定义)。
特点:会清空页面栈,只能跳转 tabBar 页面。
  • wx.reLaunch
js 复制代码
用途:关闭所有页面,打开新页面(重置页面栈)。
场景:如用户登录后重置整个应用状态。
  • wx.navigateBack
js 复制代码
用途:返回上一页面或多层页面。
参数:通过 delta 指定返回层数。
wx.navigateBack({
  delta: 1 // 返回上一层
})

导航栏与交互

js 复制代码
// 设置导航栏标题 ,在页面 .json 文件中设置
{
  "navigationBarTitleText": "详情页"
}

// 动态修改:使用 wx.setNavigationBarTitle
wx.setNavigationBarTitle({
  title: '新标题'
})

// 自定义返回按钮
{
  "navigationStyle": "custom"
}

第三方UI vant-weapp

vant-ui.github.io/vant-weapp/...

npm 安装

kotlin 复制代码
如果项目没有 package.json,先运行 npm init -y 初始化
npm install @vant/weapp

构建 npm 包

css 复制代码
打开微信开发者工具,点击菜单栏的 工具 -> 构建 npm。
确保项目根目录下生成 miniprogram_npm 文件夹,里面包含 @vant。

app.json 或 页面.json 中注册组件

js 复制代码
{
  "usingComponents": {
    "van-button": "@vant/weapp/button/index"
  }
}

使用 Vant 组件

js 复制代码
<van-button type="primary" bind:click="onClick">点击我</van-button>
<van-toast id="van-toast" />

onClick(){
  console.log('onClick');
  Toast('我是提示文案,建议不超过十五字~');
},

web-view

developers.weixin.qq.com/miniprogram... 在微信小程序中使用 web-view 组件可以嵌入网页内容

  • 配置业务域名
js 复制代码
在小程序后台 开发管理 -> 开发设置 -> 业务域名 中添加网页的 HTTPS 域名(需下载校验文件并部署到域名根目录)。
本地调试时,可在开发者工具中勾选 不校验合法域名(仅限开发环境)。
  • 在 .wxml 文件中嵌入网页:
js 复制代码
<web-view src="https://example.com?user_id=123&token=abc" bindmessage="onWebMessage"></web-view>

Page({
  onWebMessage(e) { // 在特定时机触发并收到消息:小程序后退、组件销毁、分享、复制链接
    console.log('收到网页消息:', e.detail.data); // data是多次 postMessage 的参数组成的数组
  }
});

// h5网页内代码
document.title = '新标题'; // h5网页设置小程序标题

import wx from 'weixin-js-sdk'
wx.miniProgram.postMessage({ data: { action: 'login' } });
  • 网页向小程序发送消息
css 复制代码
小程序 向 h5页面 传递数据:通过url后缀参数,h5通过地址栏解析参数获取
h5页面 向 小程序 传递数据:h5通过postMessage, 小程序通过 bindmessage 获取

数据共享

  • 在 app.js 中定义 globalData,通过 getApp() 获取全局数据
js 复制代码
// app.js
App({
  globalData: {
    userInfo: null,
  },
});

// page.js
const app = getApp();
Page({
  onLoad() {
    console.log(app.globalData.userInfo);
  },
});
  • 本地存储(Storage)wx.setStorageSync 和 wx.getStorageSync 进行数据存储和读取
  • 页面间通信 过路由跳转时传递参数(wx.navigateTo 或 wx.redirectTo)。
js 复制代码
// 页面 A
wx.navigateTo({
  url: '/pages/pageB?data=' + JSON.stringify(data),
});

// 页面 B
Page({
  onLoad(options) {
    const data = JSON.parse(options.data);
  },
});
  • 组件间通信 通过 【父向子】属性+子组件实例;【子向父】自定义方法 + triggerEvent
  • 第三方库MobX
第三方库MobX
js 复制代码
npm i mobx-miniprogram mobx-miniprogram-bindings

// store.js
import { observable, action } from 'mobx-miniprogram';
export const useUserStore = observable({
  count: 2,
  user: null,
  increment: action(function () {
    this.count++;
  }),
  setUser: action(function (user) {
    this.user = user
  }),
});

// page.js
import {
  createStoreBindings
} from 'mobx-miniprogram-bindings';
import {
  useUserStore
} from '../../stores/useUserStore';

Page({
  data: { },
  onLoad(options) {
    this.storeBindings = createStoreBindings(this, {
      store: useUserStore,
      fields: ['count', "user"],
      actions: ['increment', 'setUser'],
    });
  },
  onUnload() {
    // 解除绑定
    this.storeBindings.destoryStoreBindings()
  },
  onAdd() {
    console.log('onAdd', this.data.count); // store中的count
    this.increment()
  },
  onSetUser() {
   this.setUser({ name:"zs", id:"99" })
  },
});

//page.wxml
<view>
  <view>index.wxml</view>
  <view>store---count:{{count}}</view>
  <button bind:tap="onAdd">add count</button>
  <view>store---user.id:{{user.id}}</view>
  <button bind:tap="onSetUser">set user</button>
</view>

vConsole

点击屏幕右上角的按钮打开的菜单里选择「打开调试」。此时小程序/小游戏会退出,重新打开后右下角会出现一个 vConsole 按钮。点击 vConsole 按钮可以打开日志面板。

核心api

fail can only be invoked by user TAP gesture:须用户授权才可以调用此api [如点击弹窗中的确认才可以获取]

碰到api官方文档提示用户授权 :则需要 wx.getSetting 和弹窗确认后 wx.openSetting({}) 打开对应的权限开关,才可调用正常 developers.weixin.qq.com/miniprogram...

异步 API 支持 callback & promise 两种调用方式。当接口参数 Object 对象中不包含 success/fail/complete 时将默认返回 promise,否则仍按回调方式执行,无返回值。【碰到授权情况,不可使用 await 等模式,尽量使用 callback 模式

网络请求

wx.request

上传文件

wx.uploadFile

数据存储

wx.setStorage / wx.setStorageSync wx.removeStorage / wx.removeStorageSync wx.clearStorage / wx.clearStorageSync

界面交互

  • wx.showToast
js 复制代码
wx.showToast({
  title: '操作成功',
  icon: 'success',
  duration: 2000,
});
  • wx.showModal
js 复制代码
async onTap() {
  const res =  await wx.showModal({
    title: '提示',
    content: '确定删除吗?',
  });
  console.log('res', res);
  if (res.confirm) {
    console.log('用户点击确定');
  }
},
  • wx.showLoading / wx.hideLoading
js 复制代码
wx.showLoading({ title: '加载中' });
setTimeout(() => { wx.hideLoading(); }, 2000);
  • wx.showActionSheet 显示操作菜单
js 复制代码
async onTap() {
  const res = await wx.showActionSheet({
    itemList: ['A', 'B', 'C'],
  });
  console.log('res', res.tapIndex);
},

路由与导航

wx.navigateTo wx.redirectTo wx.switchTab wx.navigateBack

wx.onNetworkStatusChange

监听网络状态变化

媒体与文件

  • wx.chooseMedia 从相册或相机选择图片
  • wx.previewImage 预览图片
  • wx.saveImageToPhotosAlbum 下载保存到相册
  • 以下示例:上传/预览/下载
js 复制代码
<view>
  <view>index.wxml</view>
  <image src="{{src}}" mode="" bind:tap="onPreview"/>
  <button bind:tap="onChooseImage">chooseImage</button>
  <button bind:tap="onSaveImageToPhotosAlbum">saveImageToPhotosAlbum</button>
</view>

Page({
  data: {
    src: ""
  },
  async onChooseImage() {
    const res = await wx.chooseMedia()
    this.setData({
      src: res.tempFiles[0].tempFilePath
    })
  },
  onPreview() {
    wx.previewImage({urls: [this.data.src],});
  },
  async onSaveImageToPhotosAlbum() {
    const res = await wx.saveImageToPhotosAlbum({
      filePath: this.data.src
    }).catch(async error => {
      console.error('error', error);
      const { authSetting } = await wx.getSetting()
      if (!authSetting['scope.writePhotosAlbum']) {
        wx.showModal({
          title: '是否授权图片保存到相册',
          content: '请在设置中打开授权',
          success: async res => {
            if (res.confirm) {
              // openSetting需要放到showModal里面,否则无法打开设置权限页面
              const { authSetting } = await wx.openSetting({})
              console.log('openSetting---authSetting', authSetting);
              if (authSetting['scope.writePhotosAlbum']) {
                await wx.saveImageToPhotosAlbum({
                  filePath: this.data.src
                })
              }
            }else{
              wx.showToast({
                title: '此操作需要摄像头权限',
                icon:"none"
              })
            }
          }
        })
      }
      throw new Error(error)
    })
    console.log('saveImageToPhotosAlbum---end---res', res);
  }
});

map openLocation 位置与地图

js 复制代码
<map id="myMap" bindtap="onMap" latitude="{{latitude}}" longitude="{{longitude}}" markers="{{markers}}" bindmarkertap="onMarkerTap" style="width: 100%; height: 500px;"></map>

Page({
  data: {
    latitude: 39.90469,
    longitude: 116.40717,
    markers: [ // 标记点数组
      {
        id: 1,
        latitude: 39.90469,
        longitude: 116.40717,
        name: '北京',
        // iconPath: '/images/marker.png',
      },
    ],
    polyline: [
      {
        points: [ // 路线数组
          { latitude: 39.90469, longitude: 116.40717 },
          { latitude: 39.90469, longitude: 116.41370 },
        ],
        color: '#FF0000',
        width: 2,
      },
    ],
  },
  onMarkerTap(e) {
    console.log('标记点被点击', e.markerId);
  },
  onReady() {
    const mapCtx = wx.createMapContext('myMap');
    mapCtx.moveToLocation();
  },
  onMap(){
    wx.openLocation({ // 打开地图
      latitude: this.data.latitude,
      longitude: this.data.longitude,
    })
  },
});

login getUserProfile 用户信息

js 复制代码
<button bindtap="onGetUser">user</button>

Page({
  data: {},
  async onGetUser() {
    const { code } = await wx.login({});
    console.log('code', code);
    // fail can only be invoked by user TAP gesture 须用户点击弹窗中的确认才可以获取
    wx.showModal({
      title: '提示',
      content: '用于完善会员资料',
      success: async(res) => {
        if (res.confirm) {
          const {
            userInfo
          } = await wx.getUserProfile({
            desc: '用于完善会员资料',
          });
          console.log('userInfo', userInfo);
        }
      }
    })

  }
});

scanCode 扫码

js 复制代码
wx.scanCode({
  success(res) {
    const productId = res.result; // 获取商品 ID
    // wx.navigateTo({
    //   url: `/pages/productDetail/productDetail?id=${productId}`,
    // });
  },
});

拍照 camera takePhoto uploadFile

js 复制代码
<view class="container">
  <!-- 摄像头 -->
  <camera device-position="back" flash="off" binderror="error" style="width: 100%; height: 80vh;"></camera>
  <!-- 按钮 -->
  <view class="button-container">
    <view class="progress-ring" style="{{progressStyle}}"></view>
    <view class="button" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd">按住拍照</view>
  </view>
</view>

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100vh;
}
.button-container {
  position: relative;
  width: 100px;
  height: 100px;
}
.progress-ring {
  position: absolute;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: transparent;
  border: 10px solid rgba(0, 0, 0, 0.1); /* 默认背景 */
  border-top: 10px solid #4caf50; /* 进度条颜色 */
  animation: none; /* 动画初始化 */
}
.button {
  position: absolute;
  top: 10px;
  left: 10px;
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background-color: #ffffff;
  color: #4caf50;
  font-size: 14px;
  line-height: 100px;
  text-align: center;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

Page({
  data: {
    progressStyle: '', // 控制进度条样式
    timer: null, // 定时器
    progress: 0, // 当前进度
  },

  onTouchStart() {
    this.setData({ progress: 0 }); // 初始化进度
    this.startProgress(); // 开始进度条动画
  },

  onTouchEnd() {
    this.stopProgress(); // 停止进度条动画
  },

  startProgress() {
    const MAX_PROGRESS = 360; // 总进度
    const DURATION = 4000; // 总时间(4秒)
    let currentProgress = this.data.progress;

    this.setData({
      timer: setInterval(() => {
        if (currentProgress >= MAX_PROGRESS) {
          this.stopProgress(); // 达到最大进度,停止
          this.takePhoto(); // 拍照
        } else {
          currentProgress += (MAX_PROGRESS / (DURATION / 100)); // 每次增加的角度
          this.setData({
            progressStyle: `transform: rotate(${currentProgress}deg);`,
          });
        }
      }, 100), // 每100ms更新一次
    });
  },

  stopProgress() {
    clearInterval(this.data.timer); // 清除定时器
    this.setData({ timer: null, progressStyle: '' }); // 重置样式
  },

  takePhoto() {
    const ctx = wx.createCameraContext();
    ctx.takePhoto({
      quality: 'high',
      success: (res) => {
        console.log('照片路径:', res.tempImagePath);
        this.uploadFile(res.tempImagePath); // 上传图片
      },
      fail: (err) => {
        console.error('拍照失败:', err);
      },
    });
  },

  uploadFile(filePath) {
    wx.uploadFile({
      url: 'https://example.com/upload', // 替换为你的服务器地址
      filePath: filePath,
      name: 'file',
      success: (res) => {
        console.log('上传成功:', res);
      },
      fail: (err) => {
        console.error('上传失败:', err);
      },
    });
  },
});
相关推荐
SunshineBrother8 分钟前
iOS项目,shell脚本,从大到小打印图片占用内存大小
前端
二川bro8 分钟前
前端内存优化实战指南:从内存泄漏到性能巅峰
前端
疏狂难除20 分钟前
基于SeaORM+MySQL+Tauri2+Vite+React等的CRUD交互项目
前端·react.js·前端框架
onejason22 分钟前
如何使用PHP爬虫获取Shopee(虾皮)商品详情?
java·前端
赵大仁25 分钟前
深入解析前后端分离架构:原理、实践与最佳方案
前端·架构
学不动学不明白29 分钟前
PC端项目兼容手机端
前端
无名之逆29 分钟前
Hyperlane:轻量、高效、安全的 Rust Web 框架新选择
开发语言·前端·后端·安全·rust·github·ssl
wkj00136 分钟前
js给后端发送请求的方式有哪些
开发语言·前端·javascript
最新资讯动态43 分钟前
“RdbStore”上线开源鸿蒙社区 助力鸿蒙应用数据访问效率大幅提升
前端
magic 24544 分钟前
JavaScript运算符与流程控制详解
开发语言·前端·javascript