Go to comments

微信小程序 入门

小程序准备工作

小程序开发指南 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等。


【指南】-【配置小程序】-【全局配置】- 点击详情页【小程序全局配置】

https://developers.weixin.qq.com/miniprogram/dev/framework/config.html#%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE


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}';
}

































Leave a comment 0 Comments.

Leave a Reply

换一张