web前端学习(三):微信小程序基于H5规范,开发Android应用程序

发布于:2023-01-04 ⋅ 阅读:(556) ⋅ 点赞:(0)

前言:

  1. 微信小程序开发框架的目标是通过尽可能简单,高效的方式让开发者可以在微信中开发具有原生APP体验的服务。
  2. 整个小程序框架系统分为两部分,逻辑层,视图层,小程序提供了自己的视图层描述语言, WXMLWxss ,以及基于javascript的逻辑层框架, 并在视图层与逻辑层间提供了数据传输和事件系统,让开发者能够专注于数据与逻辑。

优点:

  1. 微信用户量大,开发门槛低,推广成本低,跨平台,无需安装。

  2. 微信小程序开发门槛低,可以实现消息通知,线下扫码,公众号关联等七大功能

  3. 同类型的小程序: 支付宝小程序,qq小程序。

微信小程序APP(ID): xxxxx

1.配置环境

1.应用配置

1.项目结构

|----|---index /首页
        |---index.js /首页逻辑文件
        |---index.json //首页配置文件
        |---index.wxml /首页视图文件
        |---index.Wxss //首页样式文件
|----|----1ogs“日志页面
        |---logs.js
        |---1ogs.json
        |---logs.wxml
        |---logs.wxss
|---utils /1工具文件夹
    |--util.js
|---app.js    //全局入口文件
|---app.json //全局配置文件
|---app.NXss  //全局样式文件
|---project.config.json //项目配置文件
|---sitemap.json //索引配置文件

2.app.json应用配置项

小程序根目录下的 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
}

其中 list 接受一个数组,只能配置最少 2 个、最多 5 个 tab。tab 按数组的顺序排序,每个项都是一个对象,其属性值如下:

属性 类型 必填 说明
pagePath string 页面路径,必须在 pages 中先定义
text string tab 上按钮文字
iconPath string 图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 positiontop 时,不显示 icon。
selectedIconPath string 选中时的图片路径,icon 大小限制为 40kb,建议尺寸为 81px * 81px,不支持网络图片。 positiontop 时,不显示 icon。

2.页面配置

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

{
  "navigationBarBackgroundColor": "#ffffff",
  "navigationBarTextStyle": "black",
  "navigationBarTitleText": "微信接口功能演示",      // 页面导航标题
  "backgroundColor": "#eeeeee",
  "backgroundTextStyle": "light"
  "enablePullDownRefresh":true,           // 上拉刷新,开启后onPullDownRefresh才有效
  "backgroundTextStyle": "dark",          // 上拉刷新的等待图标
  "usingComponents": {                    // 引入组件
       ...
   }
}

2.小程序生命周期

1.应用级生命周期

属性 类型 默认值 必填 说明 最低版本
1.onLaunch function 生命周期回调——监听小程序初始化。
2.onShow function 生命周期回调——监听小程序启动或切前台。
3.onHide function 生命周期回调——监听小程序切后台。
onError function 错误监听函数。
onPageNotFound function 页面不存在监听函数。 1.9.90
onUnhandledRejection function 未处理的 Promise 拒绝事件监听函数。 2.10.0
onThemeChange function 监听系统主题变化 2.11.0
其他 any 开发者可以添加任意的函数或数据变量到 Object 参数中,用 this 可以访问
// app.js
App({
   /*  1.监听小程序的初始化  */
   // 获取用户信息
   onLaunch(){
      console.log("onLaunch")
   },

   /* 2.监听小程序启动或者切换前台   */
   // 对页面的数据和效果进行重置
   onShow(){
     console.log("onShow")
   },
   /* 3.监听小程序切后台 */
   // 清除定时器
   onHide(){
      console.log("onHide")
   },
 
 
   
   /* 错误监听函数  */
   // 收集错误,通过异步请求发送服务器
   onError(e){
      console.log(e)
   }, 
   /*
    * 页面不存在监听函数
    * 启动时的入口文件不存在时才触发
    * 一般多用于扫码进入页面时的处理
    */
   onPageNotFound(){
     // 当页面不存在的时候,进行重定向,跳转到存在的页面
     console.log("onPageNotFound")
     wx.navigateTo({
       url: '/pages/page3/page3',
     })
   }

  
})

app.js中有一个 globalData, 可以用于放置全局变量或者常量。

在其它js文件中使用以下代码,获取数据。

const app = getApp();
const baseUrl = app.globalData.baseUrl;

2.页面级生命周期

注意:前台、后台定义: 当用户点击左上角关闭,或者按了设备 Home 键离开微信,小程序并没有直接销毁,而是进入了后台;当再次进入微信或再次打开小程序,又会从后台进入前台。只有当小程序进入后台一定时间,或者系统资源占用过高,才会被真正的销毁。

属性 类型 说明
data Object 页面的初始数据
1.onLoad(mounted) function 生命周期回调—监听页面加载
2.onReady function 生命周期回调—监听页面初次渲染完成
3.onShow function 生命周期回调—监听页面显示
4.onHide function 生命周期回调—监听页面隐藏
5.onUnload(unmounted) function 生命周期回调—监听页面卸载
6.onPullDownRefresh function 监听用户下拉动作
7.onReachBottom function 页面上拉触底事件的处理函数
8.onTabItemTap function 当前是 tab 页时,点击 tab 时触发
onShareAppMessage function 用户点击右上角转发
onShareTimeline function 用户点击右上角转发到朋友圈
onAddToFavorites function 用户点击右上角收藏
onPageScroll function 页面滚动触发事件的处理函数
onResize function 页面尺寸改变时触发,详见 响应显示区域变化
onSaveExitState function 页面销毁前保留状态回调
其他 any 开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问。这部分属性会在页面实例创建时进行一次深拷贝
Page({

  /*  页面的初始数据 */
  data: {

  },
  
  /* 1.生命周期函数--监听页面加载 */
  // 发送异步请求,初始化页面数据
  // 一个页面只会调用一次。
  // 接收页面参数 可以获取wx.navigateTo和wx.redirectTo及中的 query。
  onLoad: function (options) {
      console.log("onLoad")
  },

  /* 2.生命周期函数--监听页面初次渲染完成 */
  onReady: function () {
      console.log("onReady")
  },

  /* 3.生命周期函数--监听页面显示 */
  // 每次打开页面都会调用一次。**tabBar切换无效
  onShow: function () { 
    console.log("onShow")
  },

  /* 4.生命周期函数--监听页面隐藏 */
  onHide: function () { 
    console.log("onHide")
  },

  /* 5.生命周期函数--监听页面卸载 */
  // 当redirectTo或navigateBack的时候调用。 (navigateTo无效)
  onUnload: function () { 
    console.log("onUnload")
  },



  /* 1.页面相关事件处理函数--监听用户下拉动作 */ 
  onPullDownRefresh: function () { 
    console.log("onPullDownRefresh")
  },

  /* 2.页面上拉触底事件的处理函数 */
  // 上拉加载数据
  onReachBottom: function () { 
    console.log("onReachBottom")
  },
  
   /* 3.切换tab页 */
   // 当前是 tab 页时,点击 tab 时触发
  onTabItemTap: function () { 
    console.log("onReachBottom")
  },
 


})

3.组件生命周期

​ 组件的生命周期,指的是组件自身的一些函数,这些函数在特殊的时间点或遇到一些特殊的框架事件时被自动触发。其中,最重要的生命周期是 created attached detached ,包含一个组件实例生命流程的最主要时间点。

  • 组件实例刚刚被创建好时, created 生命周期被触发。此时,组件数据 this.data 就是在 Component 构造器中定义的数据 data此时还不能调用 setData 通常情况下,这个生命周期只应该用于给组件 this 添加一些自定义属性字段。
  • 在组件完全初始化完毕、进入页面节点树后, attached 生命周期被触发。此时, this.data 已被初始化为组件的当前值。这个生命周期很有用,绝大多数初始化工作可以在这个时机进行。
  • 在组件离开页面节点树后, detached 生命周期被触发。退出一个页面时,如果组件还在页面节点树中,则 detached 会被触发。

1.组件的生命周期

生命周期 参数 描述 最低版本
1.created 在组件实例刚刚被创建时执行 1.6.3
2.attached (mounted) 在组件实例进入页面节点树时执行 1.6.3
3.ready 在组件在视图层布局完成后执行 1.6.3
4.moved(update) 在组件实例被移动到节点树另一个位置时执行 1.6.3
5.detached (unmounted) 在组件实例被从页面节点树移除时执行 1.6.3
error Object Error 每当组件方法抛出错误时执行 2.4.1

代码示例:

Component({
  // 自小程序基础库版本 [2.2.3](https://developers.weixin.qq.com/miniprogram/dev/framework/compatibility.html) 起,组件的的生命周期也可以在 `lifetimes` 字段内进行声明(这是推荐的方式,其优先级最高)。
  lifetimes: {
    created: function() {
      // 在组件实例进入创建节点树时执行
    },
    attached: function() {
      // 在组件实例进入页面节点树时执行
    },
    ready: function() {
      // 在组件实例进入创建节点树时执行
    },
    moved: function() {
      // 在组件实例进入创建节点树时执行
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
  },  
})

2.组件所在页面的生命周期

还有一些特殊的生命周期,它们并非与组件有很强的关联,但有时组件需要获知,以便组件内部处理。这样的生命周期称为“组件所在页面的生命周期”,在 pageLifetimes 定义段中定义。其中可用的生命周期包括:

生命周期 参数 描述 最低版本
1.show 组件所在的页面被展示时执行 2.2.3
2.hide 组件所在的页面被隐藏时执行 2.2.3
resize Object Size 组件所在的页面尺寸变化时执行 2.4.0

代码示例:

Component({
  pageLifetimes: {
    show: function() {
      // 页面被展示
    },
    hide: function() {
      // 页面被隐藏
    },
    resize: function(size) {
      // 页面尺寸变化
    }
  }
})

3.wxml的使用

1."{{ }}"数据绑定

注意: 在标签中使用变量,必需使用双括号和引号共同作用,才能进行数据的绑定。

使用方式 和vue类似,都可以在双括号内使用变量,进行数据绑定。

双括号内可以进行三元运算、和算术运算, 组成新的数据, 但唯一不允许构造成对象使用

1.数据绑定


<!-- 在标签中的属性使用变量,需要双括号和引号共同使用 -->
<view data-msg="{{msg}}">{{obj.age}}</view>

<view wx:if="{{num == 1}}">{{ [msg,num] }}</view>

2.表单数据的双向绑定

// vant组件中使用model进行绑定
<van-cell-group>
  <van-field model:value="{{ value }}"
    placeholder="请输入用户名"  border="{{ false }}"  />
</van-cell-group>

2.wx:for列表循环

使用方法也与vue相同, 但是需要添加wx的专属属性绑定和数据绑定


 <!-- 1.简写模式 -->
 <view wx:for="{{arr}}"  wx:key="*this">{{item}}</view>

 <!-- 2.完整模式 --> 
 <!-- (1.遍历数组 -->
<!-- 默认列表项是item,索引是index, 可以省略 -->
<view wx:for="{{persons}}" 
  wx:for-item="item"          // wx:for-item是默认的
  wx:for-index="index"        // wx:for-index是默认的
  wx:key="id">                // wx:key 关键区分字段
    <view>索引:{{index}}</view>
    <view>姓名:{{item.name}}</view>
</view>
 
 <!-- (2.遍历对象 -->
 <view wx:for="{{obj}}"
     wx:key="*this"              // *this表示当前的item数据项
     wx:for-item="value"
     wx:for-index="key" >
    <view>对象的key:{{key}}     </view>
    <view>对象的value:{{value}} </view>
  </view>

3.wx:if条件渲染

小程序是wx:elif,vue是v-else-if

  • wx:if是惰性的,hidden是活动的。
  • hidden就类似于v-show,它始终会被渲染,只是简单的控制显示与隐藏
  • wx:if是惰性的,如果在初始渲染条件为false,则不会有任何变化。如果条件为真,则才会开始局部渲染。
  • 也可以用 wx:elifwx:else 来添加一个 else 块:

<!-- if条件判断 --> 
<view wx:if="{{num == 1}}">{{ [msg,num] }}</view>

<!-- if..elif..条件判断 --> 
<view wx:if="{{length > 5}}"> 1 </view>
<view wx:elif="{{length > 2}}"> 2 </view>
<view wx:else> 3 </view>

<!-- wx:for列表渲染 -->

4.wx模板和引用

1.创建模板

模板拥有自己的作用域,只能使用 data 传入的数据以及模板定义文件中定义的 <wxs /> 模块。

  • 方法一:组件内定义模板
  • 方法二:组件外定义模板,使用import导入 wxml文件。 (使用方法比组件更简单)
<!-- 定义模板 -->
<template name="msgItem">
  <view>
    <text> {{index}}: {{msg}} </text>
    <text> Time: {{time}} </text>
  </view>
</template> 

<!-- 使用模板 -->
<template is="msgItem" data="{{...item}}"/>
<template is="msgItem" data="{{index:item.index, msg:item.msg, time:item.time}}"/>

2.引用模板

  1. import方式: 可以在文件中使用目标文件定义的template
<!-- item.wxml -->
<template name="odd">
  <text> 单数</text>
</template>
<template name="even">
  <text> 复数</text>
</template>


<!-- 引入模板 -->
<import src="item.wxml"/> 
<block wx:for="{{[1,2,3,4,5]}}" wx:key="*this"> 
  <text>{{item}}</text>
  <template is="{{item % 2 == 0 ? 'even' : 'odd'}}"  />
</block>


  1. include可以将目标文件除了 外的整个代码引入,相当于拷贝代码
<!-- index.wxml -->
<include src="header.wxml"/>
<view> body </view>
<include src="footer.wxml"/>

<!-- header.wxml -->
<view> header </view>


3.使用实例

<!--pages/components/load/load.wxml-->
 
<!-- 加载模板, 1.组件内模板,2.组件外模板, -->
<!-- 作用:可以有效因页面加载缓慢,而导致的空数据 -->
<template name="loadMask">
   <view wx:if="{{judge}}" class="mask"></view> 
</template>


<!-- 使用方法 -->
<!-- 1.组件内模板 -->
<!-- 
<template name="loadMask">
   <view wx:if="{{judge}}" class="mask"></view> 
</template>
 -->
<!-- 2.import导入模板, 引入wxss无效,需要组件内自定义 -->
<!-- 
<import src="../components/load/load.wxml"/>
<template is="loadMask" data="{{judge:!like_goods.length}}"/>
 -->
<!--2.1 wxss 样式
.mask{
  width: 100vw;
  height: 100vh;
}
 -->

5.bind事件绑定

  • bindtap, bindchange, bindinput 是原生 小程序的事件绑定

  • bind:click , bind:change, 是vant组件常用的事件绑定方式

  • catchtap 禁用事件冒泡,一般设置为中间层


<-- 监听点击事件-->
<view bind:tap="onHandleClick()"> </view>

<-- 阻止冒泡事件-->
<view catchtp >
	<view bind:tap="onHandleClick()"> </view>
</view>

6.获取文档节点(略)

通过api获取当前页面对象,再使用select方法查找节点

警告:微信小程序,不是非常支持修改页面。所以,不建议获取页面文档,也无法做到浏览的复杂渲染的页面。因为这种基于数据绑定的应用,本身就脱离了页面的直接控制。

(1.selectorComponent方法

vant组件中的选择节点方法。


const checkbox = this.selectComponent(`.checkboxes-${index}`);
checkbox.toggle();           // 执行实例的方法

(2.SelectorQuery方法

  • SelectorQuery.in (对应的组件)
    • 将选择器的选取范围更改为自定义组件 component 内
    • 初始时,选择器仅选取页面范围的节点,不会选取任何自定义组件中的节点
  • SelectorQuery.select(string selector)
    • 在当前页面下选择第一个匹配选择器 selector 的节点
  • SelectorQuery.selectAll()
    • 在当前页面下选择匹配选择器 selector 的所有节点。
  • SelectorQuery.selectViewport()
    • 选择显示区域
    • 用于获取显示区域的尺寸、滚动位置等信息
  • SelectorQuery.exec(function callback)
    • 执行所有的请求
    • 请求结果按请求次序构成数组,在callback的第一个参数中返回
let query = wx.createSelectorQuery() 
query.select('#payTicketBtm').boundingClientRect().exec(function(res) {
     console.log("rect",res[0].height)
     //res就是 所有标签为payTicketBtm的元素的信息 的数组
})

4.js数据源的使用

1.函数传值

  1. 获取input输入的值

    使用 bindinput 绑定输入事件, 可以通过 事件中的事件参数 e.detail.value获取输入的值

    使用bindtap绑定点击事件,

  2. 点击按钮执行求和

    改变data中的属性,相当于改变组件中的状态。需要使用this.setData({count:11})

  3. 处理事件的函数不能传参

    要通过组件属性的形式 data- 和 e.currentTarget.dataset.name

  4. // react中是setState, 小程序是setData, 类似react中的组件状态, this.setState

 // vue,react中是target.value, 小程序是detail.value 

 // vue是this.xx 小程序是this.data.xx
--page4.js文件

    ...
      /**
       * 页面的初始数据
       */
      data: {
        count:0,
        inputValue:''
      },
       // 处理事件函数
       handleInput(e){
         console.log(e, e.detail.value)
         this.setData({
           inputValue:e.detail.value
         })
       },

      //  处理点击进行求和
       handleClick(e){
         this.setData({
           count: this.data.inputValue + 1
         })
       },
      //  处理事件传参
      handleParams(e){
         console.log("传入的参数是", e)
      },
    ...

----page4.wxml文件

    <input bindinput="handleInput" style="border:1px solid red"/>

    <button bindtap="handleClick">点我加一</button>

    <view>求和的结果是:{{count}}</view>

    <button bindtap="handleParams" data-name="Tome">点我传参</button>

2.阻止冒泡事件

微信小程序的冒泡事件

  • 微信小程序的事件,并非是浏览器的事件,所以不能使用event.stopPropagation阻止 事件冒泡
  • 使用 捕获事件的方式阻止冒泡向外扩散
  • vant组件采用catch:tap 禁用默认的事件。

1.基本方法catchtap

// 添加一个中间层,捕获冒泡事件
<view  catchtap="handleStopPropagation">
   <view bind:change="xxx">xxxx</view>
</view>

 // 捕获事件冒泡,防止向父层扩散
  handleStopPropagation(){
     // 不执行任何数据
  },
  

2.vant组件的 catch修饰

 
 // vant checkbox组件的默认切换事件, 使用catch修饰tap方法
  <view class=" check-item" data-check="{{item.id}}" bindtap="handleCheck"  >
  		<van-checkbox name="{{item.id}}"  class="checkboxes-{{ item.id }}" catch:tap="handleStopPropagation"/> 
  </view>

3.滚动事件监听

  • scroll-view组件,常用于组件中内容的滚动监听

  • 我们只需要将滑动报错的标签上加上一个样式即可 touch-action: none;
    touch-action :当你触摸并按住触摸目标时候,禁止或显示系统默认菜单。
    touch-action取值有一下两种
    none:系统默认菜单被禁用
    default:系统默认菜单不被禁用

  • 添加样式更改,将滑动报错的标签样式添加: touch-action: none;

或者设置全局公共样式: *{touch-action: none;}

4.空白加载处理

  • 可以使用wx:if + 加载数据标记判断数据
  • 可以使用hidden + 延迟显示标记方式
  • 添加占位空白页面 + 加载数据标记判断数据

5.wxs公有模块


var hello = function(str){
  return 'hello' + str;
}
module.exports = {
  hello:hello
}

<!-- 使用wxs -->
<!-- 方法一:引入wxs文件,并重命名模块 -->
<wxs src="./../comm.wxs" module="tools"/>
<view>{{tools.hello("Tom")}}</view>

<!--方法二:直接在当前文件定义模块 -->
<wxs module="getAge">
   var age = 12;
   module.exports = {
     age:age
   }
</wxs>
<view >{{getAge.age}}</view> 

5.wxss样式的使用

尺寸单位

  • rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。
设备 rpx换算px (屏幕宽度/750) px换算rpx (750/屏幕宽度)
iPhone5 1rpx = 0.42px 1px = 2.34rpx
iPhone6(建议) 1rpx = 0.5px 1px = 2rpx
iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx

使用方法

  • 使用方法和网页一样,都可以使用class

  • 引入css模块:

      @import "./../comm.wxss";
    
  • 内联样式:

    <!--动态样式-->
    <view style="color:{{color}};" />
    
    
  • style:静态的样式统一写到 class 中。style 接收动态的样式,在运行时会进行解析,请尽量避免将静态的样式写进 style 中,以免影响渲染速度

1.vant的icon图标

(1. 方法一

使用icon组件: 略

(2.方法二

使用icon标签属性,标签属性值在icon组件中查找,可以不需要添加组件

  • 一般线框风格是 xxx-o, 实底风格是xxx
/*修改goods-icon组件中的icon标签属性*/
.van-icon.van-icon-star {
  color:red; 
}

2.vant样式的覆盖

vant支持原选择器的样式覆盖,但不支持更换其它选择器的样式覆盖

比如:在原选择器前添加一个(类、id选择器),则样式覆盖无效

此时可以考虑vant文档中是否有 给根节点添加类名的选项 + 把覆盖样式写在 app.css中,添加层级

--无效的样式
.page-item .van-loading__spinner.van-loading__spinner--spinner,.van-loading__dot 
 {
  width: 60px!important;
  height: 60px!important; 
} 
--有效的样式
 .van-loading__spinner.van-loading__spinner--spinner,.van-loading__dot 
 {
  width: 60px!important;
  height: 60px!important; 
} 


<!-- 页面加载器 -->
// vant组件 可以使用 添加前缀**custom-**,给根节点添加类名。
<view  class="page-item"> 
  <van-loading type="spinner" custom-class="inner-spinner"/>
</view>

3.普通样式覆盖

  • page, view , swiper, text 微信小程序基础组件,都是作为标签使用, vant组件, 一般不使用组件名称作为选择器使用

  • **常用方式:**page + xxxx选择器, 可以极大地减少!important的使用。

  • page .address-item{
       width:100rpx!important;
    }
    
  • 全局样式写在app.wxss里面,所有页面共享文件里的样式

  • - 根节点无法与普通节点共同作用,无法找到索引。
    // 选择器无效的示例,找不到子节点
      .submit-item  .van-button { 
          height:160rpx;
      }
    
    // 选择器有效示例 , 找到具体的子节点
     .submit-item van-button .van-button--normal{
       height:160rpx;
    }
    
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PV3tdTVB-1661414245340)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220212125130885.png)]

6.视图容器(组件)

1.view基础组件

  • view组件, 代替div

  • 
    <view hover-class="bg-red">视图容器组件</view>
    
    
  • **text组件,**代替span

  • 
    <text user-select decode>文本组件 &nbsp;hello</text>
    
  • **image **图片组件

    • mode属性可以设置图片的裁剪方式
      scaleToFill默认, 宽高拉伸满,占满容器
      aspectFit长边拉伸满, 短边自适应,常用
      aspectFill短边拉伸满,长边会裁剪,不常用
      widthFix 宽度100%,高度自适应,常用
  • 
    <image class="image" mode="aspectFill" src="https://res.wx.qq.com/wxdoc/dist/assets/img/0.4cb08bb4.jpg"></image>
    
  • button表单组件

    • open-type按钮的开放能力
      contact 打开微信客服,只能在正式appid的真机测试下运行
      share转发朋友,不能发送朋友圈
      getPhoneNumber 获取用户手机号,配合bindgetphonenumber事件来使用,返回的是一个加密的数据
      getUserInfor 获取用户信息。小程序建议使用getUserProfile, 具有弹窗提示
      launchApp 打开app, 只能加回跳到app
      openSetting 打开授权设置页
      feedback 打开意见反馈页面, 需要真机测试
  •     
       <button size="mini" type="primary" loading="{{true}}">按钮</button>
       <button open-type="contact">contact</button>
       <button open-type="share">share</button>getUserInfo
       <button open-type="getPhoneNumber" bindgetphonenumber="bindgetphonenumber">getPhoneNumber</button>
       <button open-type="getUserInfo" bindgetuserinfo="bindgetuserinfo">bindgetuserinfo</button>
       <button bindtap="getUserInfo" >获取用户信息</button>
       <button open-type="launchApp" >launchApp</button>
       <button open-type="openSetting" >打开授权页</button>
       <button open-type="feedback" >打开反馈页面</button>
    
  • block组件,是一个包装元素,只接受控制属性,也不会在页面中做任何渲染。类似于template标签。

  • 
    <block wx:if="{{true}}">
      <view> view1 </view>
      <view> view2 </view>
    </block>
    
    

2.input表单组件

  • input组件
  • radio组件 + radio-group
  • checkbox组件 + checkbox-group
  • form组件,
用户名:
<input placeholder="请输入用户名" bindinput="handleUsername"/>
密码:
<input placeholder="请输入密码" bindinput="handlePassword"/>
性别:
<radio-group bindchange="handleRadio">
  <radio value="男"/>男
  <radio value="女"/>女
</radio-group>
爱好:
<checkbox-group bindchange="handleHobby">
  <checkbox value="打篮球" checked="{{true}}"/>打篮球
  <checkbox value="乒乓球"/>乒乓球
  <checkbox value="羽毛球"/>羽毛球
</checkbox-group>

<p>
  <view>用户名:{{username}}</view>
  <view>密码:{{password}}</view>
  <view>性别:{{sex}}</view>
  <view>爱好:{{hobby}}</view>
</p>

<button form-type="submit">提交 </button>

3.navigator高级组件

  • navigator组件,导航跳转

    • target跳转目标,默认是当前小程序open-type跳转的方式
      navigate默认,跳转之后,可以返回
      redirect关闭当前页面,跳转之后不能返回
      switchTab跳转到tabBar页面,并关闭其他所有非tabBar 页面, 设置为tabBar的页面专属
      reLaunch 关闭所有页面,打开到应用内的某个页面
      navigateBack关闭当前页面,返回上一页面
  • <navigator url="/pages/page3/page3" >跳转page3</navigator>
    <navigator url="/pages/page3/page3" open-type="redirect">redirect 跳转page3</navigator>
    <navigator url="/pages/index/index" open-type="switchTab">redirect 跳转index</navigator>
    <navigator url="/pages/index/index" open-type="reLaunch">redirect 跳转index</navigator>
    
  • 这个常用于当作跳转的路由方法。 也可以带参数使用。可以后退,相当于navigatorTo

  • 
    <navigator url="/pages/goods/goods?id={{itemm.id}}"> </navigator>
    
    onLoad: function (options) {
    	const {id} = options;
        // 通过options获取跳转路由的参数
        console.log("参数是",id)  
    },
    
    
  • swiper组件 ,轮播图展示

    • ​ 1.swiper默认的宽高,宽100%, 高150px
      ​ 2.images默认宽320px,高240px
      ​ 3.让swiper的高通过使用的图片的宽高计算出来
      ​ s_height = s_width * i_height / i_width
      ​ height:calc(750rpx * 240 / 320 )
      ​ 4.常用属性
      ​ autoplay自动播放
      ​ interval 指定播放间隔
      ​ indicator-dots 指示切换点
  •  
    <swiper autoplay="{{true}}" 	indicator-dots>
      <swiper-item wx:for="{{images}}" wx:key="*this" wx:for-item="url">
        <image src="{{url}}"/>
      </swiper-item> 
    </swiper>
    
    
  • rich-text组件,解析html

  •  page4.js文件
     
        html_1:'<p style="background:red">hello</p>',
        html_2:[
          {
            name:"p",
            attrs:{
              style:"color:red"
            },
            children:[
              {
                type:'text',
                text:'hello'
              }
            ]
          }
    
  • 
    <!-- 5.rich-text属性渲染html -->
    <rich-text nodes="{{html_1}}"></rich-text>
    <rich-text nodes="{{html_2}}"></rich-text>
    
  • scroll-view组件,常用于组件中内容的滚动监听

  • 
        <scroll-view scroll-y="true" style="height: 100%" bindscrolltolower="onScrollBottom" >   
        
        </scroll-view>
    
  • web-view组件,在微信小程序中浏览网页

  • 注意: 需要在微信开发者选项中添加允许访问的业务网站 的域名

  • <web-view src="https://www.xxxxxxxxx.com/index.html" />
    
  • 微信小程序内嵌网页

7.components组件

1.创建组件

定义一个components组件,在组件wxss中不应使用ID选择器、属性选择器和标签名选择器。

1.component组件


-- person.js文件
Component({
  /*  组件的接收属性数据 */
  properties: {
    //  设置接收数据的类型
      persons:{
        type:Array,
        value:[]
      }
  },

  /* 组件的初始数据 */
  data: {
    title:"我是自定义组件",
    msg:"我是子组件中的数据",
    //  persons:[
    //    {id:1,name:"Tom",age:10},
    //    {id:2,name:"mike",age:11},
    //  ]
  },

  /*  组件的方法列表  */
  methods: {
      handleClick(){
         console.log("点击了自定义组件中的事件")
      },
      handleMsg(){
        //  派发一个自定义事件, 相当于$emit
         this.triggerEvent("getMsg",{msg:this.data.msg})
      }
  },
  
  /*监听数据的变化*/
  Observe:{
     showPay: function(newShowPay) { 
       console.log("111111",newShowPay)
    }
  },
  
  // 勾子函数,组件的生命周期
  lifetimes: {
    created: function() {
      // 在组件实例进入创建节点树时执行
    },
    attached: function() {
      // 在组件实例进入页面节点树时执行
    },
    ready: function() {
      // 在组件实例进入创建节点树时执行
    },
    moved: function() {
      // 在组件实例进入创建节点树时执行
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
    },
  },  
})

-- person.wxml文件

<view class="main"> 
  <view>这里是组件的内部节点</view>
  <slot></slot>

  <view>{{title}}</view>
  <view class="item" wx:for="{{persons}}" wx:key="id">
    <view>姓名:{{item.name}}</view>
    <view>年龄:{{item.age}}</view>
  </view>
  <button bindtap="handleClick">点击触发自定义组件中的事件</button>
  <button bindtap="handleMsg">传递给父组件</button>
</view>

2.page页面

---page.json文件引入组件

{
  "usingComponents": {
    "Persons":"../../components/Persons/Persons"
  }
}

---page.wxml文件

<view>Page5中使用自定义组件</view>
<Persons persons="{{persons}}" bindgetMsg="getMsg" >
    这里的内容会显示在自定义组件中的slot占位
</Persons>

下面使用的方法与vue类似

2.property父传子

  • page页面向组件传递数据,使用标签属性
  • 子组件可以在properties 中设置传递的数据类型
  • 子组件可以自由使用传递的数据

3.triggerEvent子传父

  • 子组件在点击事件触发后,在methods选项中定义点击事件的方法,方法里面再使用 this.triggerEvent("getMsg",{msg:this.data.msg}) 派发一个自定义事件。triggerEvent很类似$emit
  • 父组件绑定是子组件派发的自定义事件(bindgetMsg=“handleMsg”)

4.slot 插槽标签

  • 在使用组件的位置,可以在内部定义slot内容
  • 而组件可以设置slot标签 的位置
  • 如果没有传递参数, 设置 default数据无效

注意:

  1. vant组件中也可以直接使用wx:for ,等模板语法。(tab组件)。

  2. vant组件的也有slot标签属性(goods-action组件)

    
    <van-cell value="内容" > 
        <view slot="title"> 
           	把title标签属性的内容作为需要插入的数据
        </view>
    </van-cell>
    
  3. vant组件也可以不添加任何属性,直接在标签体内添加内容,即可成为插槽内容(cell单元格)

  <van-cell title="设置为默认地址" >
        <van-switch checked="{{ checked }}" size="24px" />
  </van-cell>

5.observe监听器

  • 监听的数据,可以是不添加引号的键名。
Component({
  ...
  observers: {
  // 监听单个数据
    showPay: function(newShowPay) { 
       console.log("111111",newShowPay)
    }
    
    
  // 1. 监听多个数据
    'numberA, numberB': function(numberA, numberB) {
      // 在 numberA 或者 numberB 被设置时,执行这个函数
      this.setData({
        sum: numberA + numberB
      })
    },
    
    // 2.监听对象的子数据
    'some.subfield': function(subfield) {
      // 使用 setData 设置 this.data.some.subfield 时触发
      // (除此以外,使用 setData 设置 this.data.some 也会触发)
      subfield === this.data.some.subfield
    },
    
    // 3.监听列表的子数据
    'arr[12]': function(arr12) {
      // 使用 setData 设置 this.data.arr[12] 时触发
      // (除此以外,使用 setData 设置 this.data.arr 也会触发)
      arr12 === this.data.arr[12]
    },
    
    // 4.监听所有子数据的变化, 使用双通配符 “**”
    'some.field.**': function(field) {
      // 使用 setData 设置 this.data.some.field 本身或其下任何子数据字段时触发
      // (除此以外,使用 setData 设置 this.data.some 也会触发)
      field === this.data.some.field
    },
  }
  ...
})

8.常用API: wx.—

1.navigateTo路由跳转

(1. 路由跳转的参数都是串行形式, navigator组件和wx.路由api的效果相同。

(2.网络请求的参数,可以为串行和请求体两种形式

(1.跳转api

  • 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。使用 wx.navigateBack 可以返回到原页面。小程序中页面栈最多十层。

  • 关闭当前页面“,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面

  • //  wx.redirectTo({ 
    //    url: '/pages/page5/page5',
    //  })
    
  • 关闭所有页面“,打开到应用内的某个页面, 允许跳转到tabbar页面

  • 一般 用于扫码跳转主页面

  • //  wx.reLaunch({ 
    //    url: '/pages/page2/page2',
    //  })
    
  • 从tab页面,跳转其它 ”所有“ 页面

  •  //  wx.navigateTo({ 
     //    url: '/pages/page5/page5',  
     //  })
    
  • 关闭其他所有非 tabBar 页面“, 允许跳转到 tabBar 页面

  • // wx.switchTab({ 
    //   url: '/pages/page2/page2',
    // })
    
  • 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。

  • // wx.navigateBack({
    //   delta: 0,
    // })
    

(2.获取当前页面

  • getCurrentPages() 函数用于获取当前页面栈的实例,以数组形式按栈的顺序给出,第一个元素为首页,最后一个元素为当前页面。

  • let pages = getCurrentPages();
    let currPage = null;
    if (pages.length) {
       currPage = pages[pages.length - 1];
    }
    console.log(currPage.route) 
    

2.showToast交互

  • 显示消息提示框

  •    wx.showToast({
          title: '成功',
          icon: 'success',
          duration: 2000
        }) 
        // 隐藏提示框, 一般与showToast配对使用
        setTimeout(()=>{
          wx.hideToast( )
        },1000)
          
    
  • 显示 loading 提示框。需主动调用 wx.hideLoading 才能关闭提示框

  • 
        wx.showLoading({
          title: '加载中',
        }) 
        setTimeout(function () {
          wx.hideLoading()
        }, 2000) 
    
    
  • 显示模态对话框

  • 
        wx.showModal({
          title: '提示',
          content: '这是一个模态弹窗',
          success (res) {
            if (res.confirm) {
              console.log('用户点击确定')
            } else if (res.cancel) {
              console.log('用户点击取消')
            }
          }
        })
    
    

3.request网络请求

  • 请求数据

  • 注意:get请求的参数,可以写在data上, 可以串行和请求体的方式

  • vue是有data和params的区分

  •  const requestTask= wx.request({
          url: 'https://api.shop.eduwork.cn/api/index', //仅为示例,并非真实的接口地址 
          method:'get',
          data:{
              title:'java',
              sort:'price'
          },
          success (res) {
            if(res.statusCode == 200){ 
                console.log(res.data)
            }
          }
        })
    
  • 中断请求

  • 
        // requestTask.abort();
    
  • 监听 HTTP Response Header 事件。会比请求完成事件更早

  •   requestTask.onHeadersReceived(()=>{
           console.log("onHeadersReceived")
        })
    

4.storage数据缓存

  • 异步存储

  • // 异步存储数据
        wx.setStorage({
          key:"key",
          data:"value"
        })
        // 异步获取缓存中的数据
        wx.getStorage({
          key: 'key',
          success (res) {
            console.log(res.data)
          }
        })
        // 异步获取当前的缓存信息
        wx.getStorageInfo({
          success (res) {
            console.log(res.keys)
            console.log(res.currentSize)
            console.log(res.limitSize)
          }
        })
        // 异步移除本地缓存
        wx.removeStorage({
          key: 'key',
          success (res) {
            console.log(res)
          }
        })
        // 异步清空本地缓存
        wx.clearStorage({
          success: (res) => {},
        })
    
  • 同步缓存

  •  wx.setStorageSync('age', 12)
     const res = wx.getStorageInfoSync( )
     console.log( res.keys)
     console.log( res.currentSize)
     console.log( res.limitSize)
     const age = wx.getStorageSync('age')
     console.log(age)
     wx.removeStorageSync('age')
     wx.clearStorageSync()
    

区别:

  1. 调用异步api之后。不会等待执行结果,程序继续向下运行
  2. 调用同步api, 需要等待执行结果,程序暂停运行。

注意:

  • 微信小程序没有其它的缓存处理,所以一般使用同步缓存,并且storage可以不需要使用JSON.stringify处理,可以直接缓存对象。
  • 用户信息,token, openid都是存放在storage中
  • 微信小程序没有多线程和async,一般都是同步的。即使有如同react的组件状态,却依然是同步执行。

5.wx.-开放接口

  • wx.login

  • 调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成

  • wx.getUserProfile(Object object)

  • 获取用户信息。页面产生点击事件(例如 buttonbindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo。该接口用于替换 wx.getUserInfo

6.wx.-设备接口

  • wx.getClipboardDatawx.setClipboardData

  • js中:
     // 点击复制openid
      textPaste(e){
        wx.setClipboardData({
          data: e.currentTarget.dataset.openid,
          success (res) {
            wx.getClipboardData({
              success (res) {
                console.log(res.data) // data
              }
            })
          }
        }) 
        
      },
      
      
      wxml中:
          <text class='shopName' bindtap='textPaste' data-openid="{{userObj.openid}}">{{userObj.openid}}</text>
    
  • wx.previewImage 图片预览

  •  
       // 点击自定义预览层
       handleSelfPreview(e){ 
          const url = e.currentTarget.dataset.preview
          wx.previewImage({
            current:url, // 当前显示图片的http链接
            urls:[url] // 需要预览的图片http链接列表
          })
       }, 
    
  • wx.startPullDownRefreshwx.stopPullDownRefresh 上拉刷新

  • 
    console.log("下拉刷新")
    wx.startPullDownRefresh({
       success:function(){
         console.log("刷新成功")
       }
    })
    wx.stopPullDownRefresh({
       success:function(){
         console.log("刷新结束")
       }
    })
    

9.登录接口(openid)

openid和unionid

  • openid:微信用户相对于不同的公众号,不同的小程序,都有唯一的用户标识,,这个标识就是openid,在同一个公众号或者同一个小程序中,微信用户的openid是唯一的,即每个微信用户的openid是不同的

  • unionid;微信开放平台帐号下的唯一标识,只有公众号或者小程序绑定到微信开放平台帐号才能获取到unionid,同一个微信用户,在同一个开放平台unionid是惟一的,用做在不同的公众号或者不同的小程序中,识别同一个用户

  • wx.getUserProfile和wx.login

    • wx.getUserProfile:获取用户信息。页面产生点击事件(例如 button上 bindtap的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回userlnfo.

      • 一般只通过通知用户授权,就可以简单获取用户信息, 包括获取微信头像,存在后台自动注册的情况。如果存在多个平台注册,则不适合这种方式。
    • wx.login:调用接口获取**登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)**、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号〉及本次登录的会话密钥(session_key)等。

      • 后台处理,让用户感知没有任何的弹窗。操作更复杂一点。一般在小程序开始运行时自动获取。
    • **相同点:**最终的目的都是拿到openid,用于查询数据中的用户信息

    • **区别:**getUserProfile需要用户操作,不可控制。

      ​ wx.login可以实现自动获取openid

image-20220130205505573 image-20220201134546760

总结:

  • 微信小程序使用wx.login获取的code发送给后台服务器,后台服务器再去访问微信服务器地址,获取openid。(小程序appid, 应该避免暴露); 查询数据库表当前openid是否存在(因为一个用户只能获取到唯一的一个openid)来判断用户是否存在; 如果用户不存在,则只返回openid, 用于微信注册绑定帐号; 如果用户存在,则会返回openid和用户信息(直接登录,并返回用户信息)
  • 自动登录流程:根据获取的openid, 查找openid对应的帐号,如果存在,则返回token, 用户信息,openid, 如果不存在,则只返回openid。
  • 手动登录流程:用户手动输入帐号和密码,提交到后台, 如果返回的数据没有openid, 则跳转微信绑定。
  • 注册流程:请求获取微信授权,申请获取用户的帐号信息,然后将用户数据提交到后台注册帐号(此时,应该是将前面获取的openid 绑定当前微信帐号)。
  • 微信绑定流程:通过传入openid,确认当前帐号是否绑定的是当前微信。微信绑定也是下一次自动登录的关键。
  • openid的作用:openid是当前小程序对当前微信用户的唯一身份标识!以根据微信帐号和系统帐号连接在一起。相对来说,openid是小程序连接自动登录 的关键,而access_token 作为身份认证使用。而网页端是以保存access_token作为自动登录和身份认证的功能。(应该也可以根据openid反向获取用户信息)

1.小程序登录流程

1.前台发起请求:(warning)

App({
  onLaunch() { 

    // 登录
     wx.login({
  success (res) {
    if (res.code) {
      //发起网络请求
      wx.request({
        url: 'https://api.weixin.qq.com/sns/jscode2session',
        // 注意,不要以明文的形式, 请求用户数据。 
        // app.js获取不到封装页面的request文件
        data: {
          appid:'你自己的appid',  
          secret:'你自己的secret',
          js_code:res.code,
          grant_type:'authorization_code'
        } 
      })
    } else {
      console.log('登录失败!' + res.errMsg)
    }
  }
})
  },
  globalData: {
    userInfo: null,
    baseUrl:'https://api.shop.eduwork.cn'
  }
})

2.后台连接微信服务器(建议)

》》 当前小程序

》》appid , 你自己的appid

》》 secret, 你自己的secret

// app.js 

App({
  onLaunch() { 

    // 登录
    wx.login({
      success :(res)=>{
        if (res.code) { 
          //发起网络请求, wx.login获取的code,  然后通过code获取小程序的Openid和用户信息. 
          // data里面的appid是当前的小程序的身份标识   
          wx.request({
            url: this.globalData.baseUrl+'/api/auth/wx/code',
            method:'POST',
            data:{
              appid:'你自己的appid',
              secret:'你自己的secret',
              js_code:res.code
            },
            success(res2){ 
              // 如果当前微信没有绑定过,只能返回openid,缓存openid,用于后续操作。
              wx.setStorageSync('openid', res2.data.openid)

              // 如果绑定过,会返回access_token和用户信息,缓存access_token和用户信息
              // 而小程序是否登录和是否有access_token是直接关系。
              if(res2.data.access_token != ''){
                 wx.setStorageSync("access_token",res2.data.access_token)
                 wx.setStorageSync("userinfo",res2.data.user)
              }
            }
          })
        } else {
          console.log('登录失败!' + res.errMsg)
        }
      }
})
  },
  globalData: {
    userInfo: null,
    baseUrl:'https://api.shop.eduwork.cn'
  }
})

3.混乱secret密钥

 

// 检测当前的页面
export const getAlter_sec = ()=>{
    return getAlter_C(getAlter_B(getAlter_A()))
}
 
//  1.混乱的短字段
export const getAlter_A = ()=>{ 
   // 目标数据  a4f eaca b e4e4 67 f26d 8c8d a1eb22 e7  01
   const _a = 'a4f a1eb22'  // 1 8
   const _b = 'b 67'   // 3 5
   const _c = 'eaca 8c8d 01'  // 2 7 10
   const _d = ''
   const _e = 'e4e4 e7'   // 4  9
   const _f = 'f26d'    // 6
   const arr = [1,8,3,5,2,7,10,0,4,9,6]
   const alpha = ['a','b','c','d','e','f']
   let getA = Array.from('1234567890'); 
   let _turn = -1
   arr.forEach((item)=>{  
      if(item != 0) {
         _turn += 1
         let t_alpha = [];
         alpha.forEach(subItem=>{ 
               var t = 0;
               switch(subItem){
                  case 'a':
                     t = _a;
                     break;
                  case 'b':
                     t = _b;
                     break;
                  case 'c':
                     t = _c;
                     break;
                  case 'd':
                     t = _d;
                     break;
                  case 'e':
                     t = _e;
                     break;
                  case 'f':
                     t = _f;
                     break; 
               } 
            if(t.length){ 
               t_alpha = [...t_alpha,...t.split(' ')]
            }
         })  
         getA.splice(item-1,1, t_alpha[_turn])   
         }
   }) 
   return getA
}
 
//  2.混乱的短字段2
export const getAlter_B = (newArr)=>{
   // 目标数据   67 01 a4f eaca b e4e4 f26d 8c8d a1eb22 e7
   // 传递的数据 a4f eaca b e4e4 67 f26d 8c8d a1eb22 e7  01 
   let arr = Array.from('2345067891'); 
   let getB =  Array.from('1234567890');
    
   arr.forEach((item,index)=>{  
         getB.splice(item,1,newArr[index])  
   })
   return getB 
}

// 3.调整顺序,拼接,
export const getAlter_C = (newArr)=>{  
   // 传入四个字符
   const _a = newArr[0] 
   const _b = newArr[1]
   let prefix = _a[0]+_b+_a[1] 
   return prefix + newArr.slice(2).join('');
}

export const getAlter_appid = () =>{
   const _a = 'wx4cfa'
   const _c = 'd132eb'
   const _b = '9ca05f'
   return _a + _b + _c
}

module.exports = {
   getAlter_sec,getAlter_appid
}

2.oss文件直传

  • 因为我们走的是STS模式,所以首先去后台获取oss配置(accessKeyId,accessKeySecret,stsToken)
  • 创建oss实例,前后端商量好文件上传路径,直接上传,返回的是在线图片链接

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BittewZQ-1661414245342)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220210141956427.png)]

前端js上传图片、文件到阿里云OSS

阿里云简单oss上传

微信小程序与oss直传

vant组件的upload上传(主要参考文章)


  // 提交修改头像
  handleConfirm(){   
    var tempFilePath = this.data.updateAvatarList[0].url   // 监听url数据,并非data数据流
    // 只有更换才会显示发起请求的数据。
    if(!tempFilePath.startsWith("http://tmp/")){
       wx.showToast({
         title: '头像没有变化',
         icon:'error',
         duration:1500
       })
       return;
    } 
    this.getOssKey();
  },
  
  // 1.首先通过后端api返回一个oss接口信息
  getOssKey(){
    ossPicKey().then(res=>{
       console.log("返回的结果是",res)
       this.setData({
        ossKey:res
       })
       this.handleOss();
    })
  },
  
  // 2.通过组件将oss转换成在线的图片链接
  handleOss(){
        console.log("处理在线的链接",this.data.ossKey)    
        //上传的文件信息, 临时的url才有效,已经存在的在线链接,则无效。
        var tempFileDataUrl = this.data.updateAvatarList[0].url   // 监听url数据,并非data数据流
        var prefixUrl = this.data.ossKey.host;    // 图片链接前缀
        var filename = Date.now() + 'aaa.png'   // 文件名称  
        var filepath = `BoardShopping/${filename}`    // 文件路径 (含文件名称)
  
        wx.uploadFile({
          // 目标url "https://laravel-book-shop.oss-cn-beijing.aliyuncs.com/",
          url:  prefixUrl,   // 图片链接前缀
          filePath: tempFileDataUrl,    //  临时url文件
          name: 'file',                 // 文件类型,(图片也可以是file类型)
           // 获取oss数据, 必须是后端已经注册的用户
          formData: {
            name: tempFileDataUrl,     // 临时url文件
            key: filepath,          // 文件路径(含文件名称)
            policy: this.data.ossKey.policy,     // plicy政策
            OSSAccessKeyId:  this.data.ossKey.accessid,   // osss访问id
            success_action_status: "200",      // 成功的状态码
            signature:  this.data.ossKey.signature,    // 签名验证
          },
          success: (res)=>{
            const status =   `${res.statusCode}`
            if(!status.startsWith("2")){   
                console.log('请求错误1: ', res)
                wx.showToast({
                  title: "上传失败",
                  icon: 'error',
                  duration: 1500
                })
            }else{  
              // 完成的图片连接
               const newLink = prefixUrl + filepath ;
               console.log("获取的url链接",newLink)
               // 因为是回调函数, 所以并不能在回调函数中获取页面定义的方法,但箭头函数可以在上级查找data数据   
               this.handleAvatar(newLink);
            }
          },
          fail:(err)=>{
            console.log('请求失败2: ', err.errMsg)
            wx.showToast({
              title: "上传失败",
              icon:'error',
              duration: 1500
            })
          },
        })  
  }, 
  
  // 3.然后将在线图片链接上传到当前帐号
  handleAvatar(newLink){ 
    // const newAvatar = 'https://cdn.jsdelivr.net/gh/JackKetty/PicGoCDN/pic/202201051114294.jpg'
    const newAvatar = newLink;
    const data = {
      avatar:newAvatar
    }
    updateAvatar(data).then(res=>{
      wx.showToast({
        title: '更换头像成功',
        icon:'success',
        duration:1500
      })
      this.setData({
        userObj:{
          ...this.data.userObj,
          avatar_url:newAvatar
        },
        preAvatar:newAvatar,
        updateAvatarList:[
          {...this.data.updateAvatarList[0],url:newAvatar}
        ]
      })
      this.handleChangeAvatar()
    }) 
  },

3.支付宝沙箱支付

1.使用沙箱支付宝

  1. 首先需要使用个人真实支付宝帐号申请一个沙箱帐号,里面包含 商家用户 测试帐号

  2. 然后下载沙箱支付宝,使用 沙箱支付宝帐号登录,支付余额可以在 注册的支付宝帐号里面配置(真实)。

  3. 支付宝沙箱支付帐号

2.可以查看一下沙箱支付宝处理的流程(配置沙箱环境)

  1. 选择支付宝的 研发服务选项, 配置密钥/证书(公钥)

  2. 然后配置应用网关,用于接收支付宝沙箱环境的通知

  3. (自己的服务器)服务端配置 支付宝网关地址APPID签名方式

  4. 然后配置授权回调地址

  5. 沙箱支付环境

10.微信小程序上线

1.项目根路径

1.基础路径

  1. 在项目下所有的json文件中,根路径都是项目所在的路径。
app.wxss文件

@import '/miniprogram_npm/@vant/weapp/common/index.wxss';


app.json文件
 url= "pages/homePage/cart/cart"           // navigator跳转路径

"iconPath": "/assets/icons/home.png",      // assets路径

"pagePath": "pages/homePage/cart/cart",   // tabBar路径

"pages":[                                 // 页面路径
	"pages/homePage/index/index",
]
  1. 在js文件中只能使用相对路径引入
js文件

import {deleteAddress,defaultAddress,addresslist} from '../../../service/address'

import Notify from '../../../miniprogram_npm/@vant/weapp/notify/notify';

json文件(可以在npm构建包中直接找到)

"van-empty": "@vant/weapp/empty/index"

注意:npm构建是将npm包中的组件打包成一个miniprogram_npm 的构建组件。 可以在json文件中直接被找到

2.getapp()方法

  1. Commonjs 语法下的模块引入

    将引入的路径,切换到当前路径,使用了变量的形式

    App({
    	require: ($uri) => require($uri),
    })
    
    const app = getApp()
    const {data} = app.require('model/test.js')
    
  2. Es6 语法下的模块引入 (不建议使用)

    在app.js文件中声明具体模块,并结合getApp方法获取对应的属性,然后在引入的位置执行函数,获取模块对象。

    App({
      alias:{
        'service':()=>require("service/address")
      },
    })
    
    const app = getApp();  
    const  {deleteAddress,defaultAddress,addresslist}  =  app.alias.service( ); 
    

2.开发平台上线

  1. 构建npm包,真机扫码预览,打开开发者调试模式。(因为会校验合法域名)
  2. 校验合法域名(使用https), 在开发者管理配置服务器信息,";"号分隔, 添加可能请求的域名(包括图片)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ay4NmrzP-1661414245342)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220203001649152.png)]

3.发布小程序,在微信开发者工具中点击上传,将当前开发版本上传到 微信开发者平台上

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qdjOzGHQ-1661414245344)(C:\Users\Icy-yun\AppData\Roaming\Typora\typora-user-images\image-20220203002638010.png)]

注意:如果出现 小程序真机调试遇到VM13:2 Unhandled promise rejection 90001

  • 小程序开发中真机调试突然接口加载失败,排查了好多次,最后发现接口域名证书导致的
    VM13:2 Unhandled promise rejection 90001, 重新安装一下域名证书就好了

11.框架知识总结

1.与vue的相同点

  • 生命周期:

    1. vue有8个生命周期: beforeCreate,created, beforeMount, mounted, beforeUpdate, updated, beforeUnmount, unmounted
    2. 微信小程序有3种类型的生命周期:
      1. 应用生命周期:(常用)onLaunch, onShow, onHide, onError, onPageNotFound
      2. 页面生命周期:(常用)onLoad, onShow, onHide, onReady, onUnload, onPUllDownRefresh, onReachBottom
      3. 组件生命周期:(常用):略
  • 组件机制:

    1. vue组件机制,父子之间传递数据,以及使用插槽添加额外的子数据。

    2. 微信小程序只有组件和vue类似, property 属性是继承属性, data 是数据源, methods是方法集合。 使用组件的页面可以通过标签属性传递数据, 而组件可以通过 this.triggerEvent派发一个自定义事件,页面通过 onxxxx = “xxx” 接收组件传递数据。使用方法和vue的$emit类似。

      同时,可以在组件内定义slot标签,作为插槽的数据。

    3. 微信小程序的pages页面也有data数据, 通常使用 this.data.xxx获取指定数据。


2.与vue的区别

  • pages页面

    1. vue是通过组件的拼接形成的页面。

    2. 微信小程序也可以使用组件,但每个页面都有特定的标识。并且,page页面中的js数据源,内部其实是一个类,访问属性与方法是通过this.xxx 或者 this.data.xxx获取。

      并且,vue可以直接对data中的属性进行访问,而微信小程序有react中的状态机制,只有通过

      this.setData({ a: xxx}) 改变数据。即使结果相同,但是实现的方式不一样。

  • 模块语法

    1. vue采用简洁明了的方式,将数据与标签属性值 ,文本内容绑定。 列表循环,数据绑定,事件绑定, 条件渲染。

    2. 微信小程序采用的方法很类似vue,但却不一样。

      1. 事件绑定: 按钮采用 bindtab 表示绑定点击事件, 其余的事件采用 bindxxx, 事件名称小写的习惯进行事件绑定。

      2. 列表循环, vue采用 v-for=“item in goods” :key=“item.id” 的方式; 微信小程序采用 wx:for = “{{goods}}” wx:key=“id” wx:for-item = “item” wx:for-index = “id” 的方式。

      3. 数据绑定, 微信小程序采用 数据绑定wx:xxxx = “{{ xxx}}” , 插值{{xxxx}}

        有点类似vue与react的数据绑定的结合。

      4. 条件渲染: vue采用的是v-if 和v-show ,控制节点的显示;微信小程序采用wx:if , wx:elif , wx:else 和 hidden 控制节点的显示。使用方法相同。

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到