微信小程序 入门
小程序准备工作
小程序开发指南 https://developers.weixin.qq.com/ebook?action=get_post_info&docid=0008aeea9a8978ab0086a685851c0a
微信开放文档 https://developers.weixin.qq.com/miniprogram/dev/framework/
申请一个账号
注册的邮箱不能是之前用过的,最好专门用一个新邮箱申请
注册账号后,有一个非常重要的东西 AppID
搜索,微信公众平台 https://mp.weixin.qq.com/
左边栏 </>开发 - 开发管理 -> 左边 开发设置 下面看到 AppID
安装微信开发者工具,选择 稳定版 Stable Build
项目资源的初始化目录
|- pages 页面文件夹(我们关心的)
| |- index
| | |- index.js 页面的逻辑
| | |- indwx.json 页面的配置信息
| | |- index.wxml 全称 wei xin markup language 微信标记语言,
| | | 类似于超文本标记语言,语言基本和html一样,但不能使用html里面的标签,
| | | 使用的是小程序为我们提供的组件,比如view(div)、text(span)
| | |- index.wxss 全称 wei xin style sheets 负责样式的,基本上和css是一样的
| |
| |- log
| |- log.js
| |- log.json
| |- log.wxml
| |- log.wxss
|
|- utils 工具文件夹(是我们要关注的)
|- .eslintrc.js 代码规范风格的配置文件(是我们要关注的)
|- app.js 项目入口文件,相当于Vue里面的main.js(是我们要关注的)
|- app.json 全局的配置文件,可以修改标题、底部的 tabBar、navigation等,就是对应整个小程序做一个全局的配置(是我们要关注的)
|- app.wxss 全局的样式(是我们要关心的)
|- project.config.json
|- project.private.config.js
|- sitemap.json 搜索微信小程序时候配置文件
一、wxml
微信官方文档 WXML 语法参考
https://developers.weixin.qq.com/miniprogram/dev/reference/wxml/
|- pages
| |- index
| |- index.wxml
| |- index.js
|
|- templates
|- megitem.wxml
|- header.wxml
pages/index/index.wxml
<!-- 数据绑定 基本语法和Vue非常类似 大小写是敏感的 undefined 不会被输出到wxml中 --> <view> <text>我的名字是:{{name}}</text> </view> <view> <text>当前时间:{{time}}</text> </view> <!-- 逻辑语法 --> <view> <text>{{a > b ? '数字a大' : '数字b大'}}</text> <text>{{a + b}}</text> </view> <!-- 条件逻辑 --> <view wx:if="{{length > 5}}">1</view> <view wx:if="{{length > 2}}">2</view> <view wx:else>3</view> <!-- block逻辑似于vue里面的template,表示要渲染的一整块内容 --> <block wx:if="{{container}}"> <view> <text>列表1</text> </view> <view> <text>列表2</text> </view> </block> <!-- 列表渲染 --> <view wx:for="{{fruits}}" wx:key="*this"> <text>{{index}}</text>-<text>{{item}}</text> </view> <!-- Now you can provide attr 'wx:key' 现在你可以提供一个属性 Now you can provide attr 'wx:key' for a 'wx:for' 给 wx: key 提供一个属性 Now you can provide attr 'wx:key' for a 'wx:for' to improve performance 提升性能 --> <!-- key用index --> <view wx:for="{{fruits}}" wx:key="index"> <text>{{index}}</text>-<text>{{item}}</text> </view> <!-- 模板 import 注意有一个作用域的问题 include 用于静态模板,实际上就替换操作 --> <import src="../../templates/msgitem"/> <template is="msgItem" data="{{index: '这是索引', item: '这是值', time:time}}"/> <include src="../../templates/header"/> <include src="../../templates/footer"/> <!-- 公共的属性 --> <view hidden="true"> <text>当前时间:{{time}}</text> </view> <!-- 共同属性 id 组件的唯一标识,整个页面唯一的 class 组件的样式,对应wxss文件的样式 style 组件的内联样式 hidden 组件是否显示 data-* 自定义组件,组件触发事件时候,会发给事件处理函数 bind*/catch* 组件事件 -->
pages/index/index.js
Page({ data: { motto: 'Hello World', name: '张三', time: (new Date()).toString(), a: 20, b: 15, length: 1, container: true, fruits: ["苹果", "香蕉", "菠萝"], }, })
templates/msgitem.wxml
<template name="msgItem"> <view> <text>{{index}} - {{item}}</text> <text>Time:{{time}}</text> </view> </template>
templates/header.wxml
<view> <text>这是一个头部</text> </view>
二、wxss
wxss 全称 Wei Xin Style Sheets
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=000c44c49141887b00864fbba5100a
1、文件组成
|-mod
| |- common.wxss 其它样式可以被项目公共样式和页面样式引用
| |- tabBar.wxss
|
|-page
| |-index 每一个页面是一个文件夹,每个文件里面基本上有四个文件
| |- wxml 结构,必须的
| |- wxss 样式,可选
| |- js 逻辑,必须的
| |- json 配置,可选
|
|- app.wxss 项目公共样式位于根目录,它会被注入到小程序的每个页面
2、尺寸单位
在 wxss 中引入的了 rpx 全称 responsive pixel(responsive 响应式的意思)
小程序编译后,rpx会做一次px换算,
以 375个物理像素为基准,也就是说一个宽度为375物理像素的屏幕下 1rpx = 1px
举个例子:
iPhone6屏幕宽度为375px,共750个物理像素,那么 1rpx = 375 / 750 px = 0.5px
3、wxss引用
@import './test.wxss';
基本上和css相同,使用@import来引用,
和原生css的区别是,由于wxss会被编译到打包的目标文件中,用户只需下载一次,不会因为样式引用而产生多余的文件请求
4、内联样式
wxss内联样式与原生css一样,注意单位是 rpx
<view style="color:red;font-size:48rpx"></view>
小程序支持动态的内联样式
<!-- Page({ data: { time: (new Date()).toString(), eleColor:'red', eleFontsize: '48rpx' }, }) --> <view style="color:{{eleColor}};font-size:{{eleFontsize}}">{{time}}</view>
5、选择器
类选择 .class
id选择器 #id
元素选择器 element 选择所有的view组件和checkbox组件
伪元素选择器 view::after 后面插入
伪元素选择器 view::before 前面插入
6、官方样式库
微信小程序官方提供的一套组件库
WeUI for 小程序,为微信小程序量身设计
https://github.com/Tencent/weui-wxss
三、事件
如何绑定一个事件,如何触发事件,如何获取事件对象(如何不做错事???)
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=000846df9a03909b0086a50025180a
bind + 事件类型 例如 bindtap 就是绑定一个 tap 类型的事件
<view bindtap="tapName">click</view>
1、事件类型
touchstart 手指触摸动作开始
touchmove 手指触摸后移动
touchcancel 手指触摸动作被打断,如来电提醒,弹窗
touchend 手指触摸动作结束
tap 手指触摸后马上离开,有点类似于click
longpress 手指触摸后,超过350ms再离开,如果指定了事件回调函数并触发了这个事件,tap事件将不被触发
longtap 手指触摸后,超过350ms再离开(推荐使用longpress事件代替)
longtap 和 logpress 事件的区别
<!-- 按住不放触发logtap事件,手指抬起后触发了tap事件 --> <view bindtap="tapName" bindlongtap="longtapHandle">longtap</view> <!-- 按住不放超过350ms,只触发了logpress事件,抬起手指tap不会触发了 --> <view bindtap="tapName" bindlongpress="longpressHandle">longpress</view> <!-- Page({ data: { time: (new Date()).toString(), eleColor:'red', eleFontsize: '48rpx' }, tapName: function(event){ console.log('tap事件',event); }, longtapHandle(){ console.log('按住不放 longtap'); }, longpressHandle(){ console.log('按住不放 logpress'); } }); -->
2、事件对象
detail 属性获取坐标信息
<view bindtap="tapName">click</view> Page({ tapName(e){ console.log(e.detail); // {x: 29.5, y: 10.75} console.log(e.detail); // {x: 29.5, y: 10.75} }, })
target 和 currentTarget 的区别,就是原生js里面 e.target 和 this 的区别
target 触发该事件的源头组件
currentTarget 当前事件绑定的组件
e.dataset 获取的 data-id 自定义属性
外层绑定 tap 事件,而点击的是内层 inner 红色
<view class="outter" bindtap="tapHandle" data-id="outter"> <view class="inner" data-id="inner"></view> </view> .outter{ width: 400rpx; height: 350rpx; border: 1rpx solid; margin: 0 auto; } .inner{ width: 300rpx; height: 200rpx; background-color: red; margin: 0 auto; } Page({ tapHandle(e){ console.log('target: ', e.target.dataset); // {id: "inner"} console.log('currentTarget: ', e.currentTarget.dataset); // {id: "outter"} }, });
e.currentTarget.dataset
当前绑定事件元素上的 dataset-id 属性值
3、事件冒泡
通过 bind 绑定的事件会冒泡
点击 inner 一直冒泡到 outter
触发了inner上事件
触发了middle上的事件
触发了outter上事件
<view class="outter" bindtap="tapOutterHandle"> <view class="middle" bindtap="tapMiddleHandle"> <view class="inner" bindtap="tapInnerHandle"></view> </view> </view> // .js Page({ tapInnerHandle(){ console.log('触发了inner上事件'); }, tapMiddleHandle(){ console.log('触发了middle上的事件'); }, tapOutterHandle(){ console.log('触发了outter上事件'); }, }); // .wxss .outter{ width: 400rpx; height: 350rpx; border: 1rpx solid; margin: 0 auto; } .middle{ width: 300rpx; height: 200rpx; margin: 10rpx auto; border: 1rpx solid; } .inner{ width: 100rpx; height: 100rpx; background-color: red; margin: 10rpx auto; }
通过 catch 绑定的事件不会冒泡,点击 inner 只冒泡到 middle,就不会往上冒泡了
<view class="outter" bindtap="tapOutterHandle"> <view class="middle" catchtap="tapMiddleHandle"> <view class="inner" bindtap="tapInnerHandle"></view> </view> </view>
自基础版1.5.0,bind 和 catch 后面可以加冒号,含义是不变的
<view class="outter" bind:tap="tapOutterHandle"> <view class="middle" catch:tap="tapMiddleHandle"> <view class="inner" bind:tap="tapInnerHandle"></view> </view> </view>
4、事件捕获
capture-bind 绑定的是事件捕获
点击红色方块变成了从外层向内捕获
触发了outter上事件
触发了middle上事件
触发了inner上事件
<view class="outter" capture-bind:tap="tapOutterHandle"> <view class="middle" capture-bind:tap="tapMiddleHandle"> <view class="inner" capture-bind:tap="tapInnerHandle"></view> </view> </view>
四、程序构造器App() 与 页面构造器Page()
第3章 理解小程序宿主环境 -> 3.2 程序与页面
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=0004eec99acc808b00861a5bd5280a
App() 程序构造器在 app.js 里面,整个小程序应用只有这一个
Page() 页面构造器在每一个页面js文件下面,每一个页面的js文件都有Page构造函数
1、程序构造器 App()
App() 程序构造器有两个配置项
1. 生命周期钩子函数
2. 获取全局数据
1. 在 App() 构造器中,我们能够使用的声明周期钩子函数
onLaunch 当小程序初始化完成(全局只能触发一次)
onShow 当小程序启动,或从后台返回到到前台时触发
onHide 当小程序进入后台状态
onError 当小程序发生脚本出错的时候
什么叫进入后台状态?
当用户点击右上角的关闭按钮,或者按设备的 Home 键离开小程序,
此时小程序并没有销毁,这种情况叫进入后台状态
触发顺序
一开始会先触发 onLaunch,就是启动的时候,Launch是启动的意思
接下来渲染出来的时候触发 onShow,
点击关闭的时候触发 onHide,回到小程序重新触发 onShow
// app.js App({ onLaunch() { console.log('小程序启动时 onLaunch'); }, onShow(){ console.log('onShow'); }, onHide(){ console.log('onHide'); } })
事件对象
打开小程序的方式有很多,有些时候根据不同的打开方式做一些不同的业务处理,
通过 onLaunch 和 onShow 两个钩子函数接收的一个参数,可以知道是通过那种方式打开的
// app.js App({ onLaunch(options){ console.log('onLaunch', options); }, onShow(options){ console.log('onShow', options); } })
{
apiCategory: "default"
mode: "default"
path: "pages/index/index" 打开小程序的的页面路径
query: {} 打开小程序的页面参数
referrerInfo: {}
scene: 1001 打开小程序的场景值
}
2. 全局数据
通过 App 构造器中的 globalData 共享全局数据
// app.js App({ onLaunch(options){ console.log('onLaunch', options); }, onShow(options){ console.log('onShow', options); }, globalData: { userName: '谢老师' } })
在其他 js 页面通过 getApp() 获取整个 app() 的实例,从而获取实例中的共享数据
// pages/index/index.js var appInstance = getApp(); console.log('共享数据:', appInstance.globalData); // 共享数据: {userName: "谢老师"} Page({ })
2、页面构造器 Page()
Page() 构造器配置项
1. data
2. 声明周期钩子函数
data: 指定页面中一些动态的数据
着重看下面五个
onLoad: 页面销毁之前会调用一次,当页面加载好了,第1个触发
onReady: 页面销毁之前会调用一次,初次渲染完成的时候触发,第3个被触发
onShow: 每次页面显示的时候触发,第2个触发
onHide:
onUnload: 页面卸载的时候
下面是用户行为
onPullDownRefresh: 下拉刷新的时候
onReachBottom: 页面触底底部的时候
onShareAppMessage: 点击右上角转发的时候
onPageScroll: 页面滚动的时候
什么是页面销毁?
当页面使用 wx.redirectTo 或 wx.navigateBack 返回到其他页时,页面会被销毁回收,onUnload方法被调用。
按照触发顺序
// pages/index/index.js Page({ tapInnerHandle(){ console.log('触发了inner上事件'); }, tapMiddleHandle(){ console.log('触发了middle上的事件'); }, tapOutterHandle(){ console.log('触发了outter上事件'); }, // 按照触发顺序 onLoad(){ console.log('onLoad'); }, onShow(){ console.log('onShow'); }, onReady(){ console.log('onReady'); }, });
在 onLoad 函数中可以接收参数,参数是上一个页面的 get 请求的信息
// pages/list/list.js wx.navigateTo({url: '/pages/detail/detail?id=1&other=abc'}) // pages/detail/detail.js page({ onLoad: function(option){ console.log(option.id); console.log(option.other); } })
必须通过 this.setData( 新数据, callback ) 修改data配置里面的数据
1. 点击触发事件
2. 在事件函数里面调用 this.setData,然后可以设置第二个参数 callback
// .js Page({ data:{ test: '这是一个数据', }, editTestHandle(){ this.setData({ test: 'this is a test', },function(){ console.log('修改完毕,页面已经更新了'); }); }, }) // .wxml <view>{{test}}</view> <button bind:tap="editTestHandle">修改数据</button>
注意,不要把数据 value 设置为 undefault,会引起一些bug
五、路由
先补充一个app.json 文件配置 tab 的知识点
1、关于 app.json 中的配置
根目录的 app.json 文件是对小程序的全局配置,比如页面文件的路径、窗口表现、网络超时时间、tab等。
【指南】-【配置小程序】-【全局配置】- 点击详情页【小程序全局配置】
app.json 的重要配置
|- page 配置小程序里面的页面,小程序是由一个一个的页面组成的,有哪些页面在这里配置
| 新增一个 detail,文件里面自动就出现了新的detail页面了
|
|- windw 配置和导航相关的
| |- navigationBarBackgroundColor 背景颜色,仅支持十六进制颜色
| |- navigationBarTitleText 小程序标题,比如翻译小程序
| |- navigationBarTextStyle 只能填这两个颜色 black/white
| |- backgroundColor 仅支持十六进制颜色
| |- backgroundTextStyle Light
|
|- entryPagePath 默认启动首页
|
|- tabBer 配置底部tab栏
|- list 配置是一个数组,数组里面是对象,最少要必须要有两个对象/最多5个(必须要设置的)
| |- text 显示的文本
| |- pagePath 页面路径 pages/index/index
| |- iconPath 图标 "img/icon.png"
| |- selectedIconPath 选中时候的图标路径 "img/sel-icon.png"
|
|- position 仅支持 buttom/top
|- borderStyle 上边框的颜色,仅支持 black/white
|- color 颜色,仅支持十六进制颜色
|- selectedColor 文字选中后的颜色,仅支持十六进制颜色
{ "pages": [ "pages/index/index", "pages/logs/logs", "pages/detail/detail", "pages/test/test" ], "window": { "navigationBarTextStyle": "black", "navigationBarTitleText": "我的小程序", "navigationBarBackgroundColor": "#ffffff" }, "tabBar": { "position": "bottom", "borderStyle": "white", "color": "#bfbfbf", "selectedColor": "#1c1b21", "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/logs/logs", "text": "日志" }, { "pagePath": "pages/detail/detail", "text": "详情" } ] }, "style": "v2", "componentFramework": "glass-easel", "sitemapLocation": "sitemap.json", "lazyCodeLoading": "requiredComponents" }
2、路由的跳转
【第3章 理解小程序宿主环境】-【程序与页面】-【页面】-【6.页面跳转和路由】
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=0004eec99acc808b00861a5bd5280a
页面栈
["pageA", "pageB", "pageC"]
pageA 在最底下
pageC在最上面
小程序页面栈最大层级为10层
API
wx.navigateTo({ url: 'pageD' }) 向页面栈推入一个pageD [ pageA, pageB, pageC, pageD ]
wx.navigateBack() 出页面栈的最顶上页面 [ pageA, pageB, pageC ]
wx.redirectTo({ url: 'pageE' }) 替换当前页变成 pageE [ pageA, pageB, pageE ]
wx.switchTab({ url: 'pageF' }) 原来的页面栈会被清空 [ pageF ] 除了已经声明为Tabbar页pageA外其他页面会被销毁,
此时点击Tab1切回到pageA时,pageA不会再触发onLoad,因为pageA没有被销毁。
wx.reLaunch({ url: 'pageH'}) 重启小程序的时候,并且打开pageH ["pageH"]
示例
wx.navigateTo({url: '/pages/test/test?id=1'}) 向页面栈新推入一个页面 ["index", "test"]
<!-- pages/index/index.wxml --> <button bind:tap="goToTest">跳转到test页面</button> // pages/index/index.js Page({ goToTest(){ wx.navigateTo({ url: '/pages/test/test?id=1' }); } })
wx.navigateBack() 当前页面出栈(就是返回) ["index"]
<!-- pages/test/test.wxml --> <text>pages/test/test.wxml</text> <button bindtap="backIndex">返回</button> // pages/test/test.js Page({ backIndex(){ wx.navigateBack({ delta:0, // 返回的页面数,如果大于现有页面数,则返回到首页 }); }, })
wx.redirectTo({url: '/pages/test/test'}) 替换当前的页面 ["index"] 替换为 ["test"]
1. 当页面达到10层没法再增加时,就用使用 redirectTo 进行页面跳转
2. 这时候在 test 页面按返回就不会有作用了
<!-- pages/index/index.wxml --> <button bind:tap="goToTest">跳转到test页面</button> // pages/index/index.js Page({ goToTest(){ wx.redirectTo({ url: '/pages/test/test' }) } })
补充一下,
wx.navigateTo 和 wx.redirectTo 只能打开非 TabBar 页面,wx.switchTab 只能打开 Tabbar 页面
如果页面设置了 tabBar,在跳转报错 errMsg: "navigateTo:fail can not navigateTo a tabar page"
wx.switchTab(url: "/pages/logs/logs") 负责 tabBar 的切换,使用 tabBar 时原来的页面栈会被清空
1. 先从首页使用 wx.navigateTo 跳转到 test ["index", "test"]
2. 再从 test 使用 switchTab 到 logs 页,之前页面栈被清空 ["logs"]
<!-- pages/test/test.wxml --> <text>pages/test/test.wxml</text> <button bindtap="tapHandle">返回</button> // pages/test/test.js Page({ tapHandle(){ wx.switchTab({ url: "/pages/logs/logs" }); }, })
注意,
页面路由跳转,必然涉及到页面的显示与隐藏,会涉及到页面声明周期函数的调用
页面触发方式及页面生命周期函数的对应关系
路由方式 触发时机 路由前页面 路由后页面
初始化 小程序打开的第一个页面 onLoad, onShow
打开新页面 调用 wx.navigateTo onHide onLoad, onShow
页面重定向 调用 wx.redirectTo onUnload onLoad, onShow
页面返回 调用 wx.navigateBack onUnload onShow
Tab 切换 调用 wx.switchTab 请参考表3-6 请参考表3-6
重启动 调用 wx.reLaunch onUnload onLoad, onShow
tabBar 切换的时候对应的生命周期如下
表格省略
六、发起HTTPS网络通信
4.4 发起HTTPS网络通信
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=000ee27c9c8d98ab0086788fa5b00a
1、wx.request() 发送网络请求
参数是一个配置对象,url请求地址,success请求成功之后的回调对象,和 $.ajax 基本上是一样的
wx.request({ url: "https://study.duyiedu.com/api/citylist", success: function(res){ console.log(res); // res是服务器的响应信息 } })
详细参数
url 服务器接口地址,必填
data 请求的参数,Object/String
header 设置请求头,默认 header['content-type'] = 'application/json'
method 请求方法,默认GET(需大写)
dataType 回包的内容格式,默认json
success 请求成功后的回调函数,参数是一个Object
fail 接口调用失败的回调函数
complete 接口调用成功/失败都会执行
2、关于接口
请求的地址
1. 必须是 https 接口
2. 必须在小程序管理平台配置
登陆微信公众平台 -【</>开发】-【开发管理】-【开发设置】-【服务器域名】- request合法域名
谢老师课程里的一些域名
https://api.map.baidu.com;https://apis.map.qq.com;https://fanyi-api.baidu.com
在开发环境,可以不校验请求地址
开发工具 - 工具栏【详情】- 【本地设置】 - 打钩【不校验合法域名】
3、关于参数
GET
url上的参数需要拼接到字符串里,参数需要做一次urlEncode,1024字节限制
建议使用 data 传递数据
POST
必须使用 data
// 通过url参数传递数据 wx.request({ url: "https://test.com/getinfo?id=1&version=1.0.0", success: function(res){ console.log(res); } }) // 通过data参数传递数据 wx.request({ url: "https://test.com/getinfo, data: {id:1, verson:'1.0.0'}, success: function(res){ console.log(res); } })
4、关于回包
服务器的响应数据
data Object/String 数据
statusCode NumberHTTP 状态码
header Object 响应头 HTTP Response Header
5、使用技巧
1. 设置超时时间
在根目录 app.json 文件里面设置超时时间,默认超时时间是 60 秒
"networkTimeout": { "request": 3000 },
2. 请求前后的状态
服务器通信时候的 loading 框
wx.showLoading() 显示loading框
wx.hideLoading() 隐藏loading框
wx.showToast({title: '系统错误'}) 如果处理失败,显示的提示
6、练习
根目录的 app.json
设置 3 秒后还没收到回包就给用户一个明确的提示
{ "pages": [ "pages/index/index", "pages/logs/logs", "pages/detail/detail", "pages/test/test", "pages/register/register", "pages/login/login" ], "entryPagePath": "pages/register/register", "networkTimeout": { "request": 3000 }, "window": { "navigationBarTextStyle": "black", "navigationBarTitleText": "我的小程序", "navigationBarBackgroundColor": "#ffffff" }, "tabBar": { "position": "bottom", "borderStyle": "white", "color": "#bfbfbf", "selectedColor": "#1c1b21", "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/logs/logs", "text": "日志" }, { "pagePath": "pages/detail/detail", "text": "详情" }, { "pagePath": "pages/register/register", "text": "注册" }, { "pagePath": "pages/login/login", "text": "登陆" } ] }, "style": "v2", "componentFramework": "glass-easel", "sitemapLocation": "sitemap.json", "lazyCodeLoading": "requiredComponents" }
register.js
设置 data 里面对应的数据
设置请求网络前后的状态
// pages/register/register.js Page({ data:{ loginId: "", password: "" }, sendGet(){ wx.showLoading({ title: '加载中...' }); wx.request({ url: "http://localhost/mycode/001.php", data: { loginId: this.data.loginId, password: this.data.password }, success: function(res){ console.log(res.data); }, fail(){ // 设置失败 wx.showToast({ title: '请求超时,失败了', icon: 'error' }) }, complete(){ wx.hideLoading(); } }) }, sendPost(){ wx.request({ url: "http://localhost/mycode/001.php", method: "POST", data: { loginId: this.data.loginId, password: this.data.password }, success: function(res){ console.log(res.data); } }) }, })
register.mxml
数据双向绑定 model:value="{{password}
<!--pages/register/register.wxml--> <text>pages/register/register.wxml</text> <view> <text>账号</text> <input type="text" name="" id="" class="input" model:value="{{loginId}}"/> <text>密码</text> <input type="password" name="" id="" class="input" model:value="{{password}}"/> <button bindtap="sendGet">发送 get 请求</button> <button bindtap="sendPost">发送 post 请求</button> </view> /* pages/register/register.wxss */ .input{ border: 1rpx solid; } button{ margin:10rpx; }
PHP 接口文件
ini_set("error_reporting","E_ALL & ~E_NOTICE"); sleep(10); if($_GET){ echo '{"name": "Mon", "age": "17.9"}'; exit; } $data = file_get_contents('php://input'); $data = json_decode($data, true); // 检查解析后的数据是否为空 if (!empty($data)) { // 对接收到的POST数据进行处理或存储操作 echo $data['loginId'] ."_". $data['password']; } else { // 如果数据为空,进行相应的错误处理 echo '没有接收到post'; } /* 在方法一中,使用了$_POST全局变量来获取POST数据。可以直接将接收到的POST数据存储在变量$data中,然后进行进一步的处理或存储操作。如果数据为空,可以进行相应的错误处理。 在方法二中,使用了file_get_contents('php://input')来获取POST的原始数据。由于该方法直接获取原始数据,需要进行进一步的处理,例如使用json_decode将数据转换成数组格式。然后,对解析后的数据进行处理或存储操作。如果数据为空,可以进行相应的错误处理。 请注意,以上代码仅为示例,并未包含对POST数据的安全验证和过滤处理。在实际应用中,为了防止安全问题和减少风险,请对接收到的数据进行适当的验证和过滤操作。 https://www.baidu.com/s?ie=utf-8&f=3&rsv_bp=1&tn=68018901_3_dg&wd=php%E6%8E%A5%E6%94%B6post%E6%95%B0%E6%8D%AE&oq=php%2520%25E8%25A7%25A3%25E6%259E%2590%2520json&rsv_pq=8f5bce540007d11d&rsv_t=1ec4b%2BG%2FU320GC0LUismqJhwtFrMKLfSRDs2xGC56OAQgdwATVGy6Cr7VpP0URWyNHof2g&rqlang=cn&rsv_dl=ts_0&rsv_enter=1&rsv_sug3=15&rsv_sug1=16&rsv_sug7=100&rsv_sug2=0&rsv_btype=t&prefixsug=php%2520%25E6%258E%25A5%25E6%2594%25B6%2520post&rsp=0&inputT=6348&rsv_sug4=7078 */
七、本地数据存储
小程序本地存储和 localStorage 是类似的
https://developers.weixin.qq.com/ebook?action=get_post_info&docid=000a2c7c9f4a981b0086bd31e5b40a
读取本地缓存
wx.getStorage(异步)
wx.getStorageSync(Sync表示同步接口)
写数据到缓存
wx.setStorage
wx.setStorageSync
1、读取数据
异步读取,
参数是一个配置对象
key 是要读取的数据,
success 因为是异步读取的结果要传给回调函数,
fail 异步读取失败的函数
complete 异步读取无论成功还是失败都会进到这里
wx.getStorage({ key: 'key1', success: function(res) { // 异步接口在success回调中才能拿到返回值 var value1 = res.data }, fail: function() { console.log('读取key1发生错误') } })
同步的读取,直接取出值
try{ var value = wx.getStorageSync('key'); // 没有读取到值,会一直在这卡着 }catch (e) { console.log('读取key发生错误') }
2、写入数据
参数:
key
data
success 异步的
fail 异步的
complete 异步的
encrypt 从2.21.3版本开始本地存储可以加密,注意只有异步的支持加密
异步写入
// 异步接口在success/fail回调才知道写入成功与否 wx.setStorage({ key: "key", data: "value" // 类型是any success: function() { console.log('写入value成功'); }, fail: function() { console.log('写入value1发生错误'); } })
同步写入,
传两个参数 key 和 value
try{ wx.setStorageSync('key', 'value'); // 因为是同步的,会一直卡在这里等写入完成在执行下一行 console.log('写入value成功') }catch (e) { console.log('写入value发生错误') }
3、缓存限制和隔离
可以打开很多的小程序,不同的小程序本地缓存是分开的
考虑到同一个设备可以登陆不同微信用户,既同一个小程序,不同的用户之间的缓存也是隔离的
每个小程序缓存的空间有 10MB 的上限,如果到达上限会触发 fail 回调
本地缓存,在换设备后就无法读取了,建议把数据放到服务器进行持久存储
4、其他方法
从本地缓存移除指定的key
wx.removeStorage
wx.removeStorageSync
获取storage相关的信息
vx.getStorageInfo
vx.getStorageInfoSync
清空本地数据缓存(和remove的区别是,remove可以指定key)
wx.clearStorage
wx.clearStorageSync
5、例子
register.wxml
双向数据绑定
<!--pages/register/register.wxml--> <text>pages/register/register.wxml</text> <view> <text>账号</text> <input type="text" name="" id="" class="input" model:value="{{loginId}}"/> <text>密码</text> <input type="password" name="" id="" class="input" model:value="{{password}}"/> <button bindtap="sendPost">post 请求注册</button> </view> /* pages/register/register.wxss */ .input{ border: 1rpx solid; } button{ margin:10rpx; }
register.js
// pages/register/register.js Page({ data:{ loginId: "", password: "" }, sendPost(){ wx.showLoading({ title: '加载中...', mask: true, }); wx.request({ url: "http://localhost/mycode/001.php", method: "POST", data: { loginId: this.data.loginId, password: this.data.password }, success: (res) => { // 这里将提交的数据缓存到本地存储 wx.setStorageSync('loginId', this.data.loginId); wx.setStorageSync('passwork', this.data.password); wx.showToast({ title: '注册成功', }); console.log(res.data); }, fail(){ wx.showToast({ title: '请求超时,失败了', icon: 'error', }); }, complete(){ wx.hideLoading(); } }); }, });
login
<!--pages/login/login.wxml--> <text>pages/login/login.wxml</text> <view> <text>账号</text> <input type="text" name="" id="" class="input" model:value="{{loginId}}"/> <text>密码</text> <input type="text" name="" id="" class="input" model:value="{{password}}"/> <button bindtap="sendPost">登陆</button> </view> // pages/login/login.js Page({ data:{ loginId: "", password: "" }, // 生命周期函数--监听页面显示 onShow() { // 取出仓库数据 const storLoginIdLoginId = wx.getStorageSync('loginId'); const storagePassword = wx.getStorageSync('passwork'); if(storLoginIdLoginId){ this.setData({ loginId: storLoginIdLoginId, }); } if(storagePassword){ this.setData({ password: storagePassword, }); } }, })
php
$data = file_get_contents('php://input'); $data = json_decode($data, true); sleep(3); // 检查解析后的数据是否为空 if (!empty($data)) { $response = ['msg'=>'','code'=>0,'data'=>$data]; echo json_encode($response); } else { echo '{"msg":"这是错误信息","code":406,"data":null}'; }