微信小程序开发 自学

微信小程序开发

自学方向

自学视频:https://www.bilibili.com/video/BV1WJ41197sD
官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/config.html#全局配置

小程序基础知识

一、小程序的结构目录

1、小程序文件结构与传统web对比

在这里插入图片描述

2、基本项目目录

在这里插入图片描述
在这里插入图片描述

3、全局配置 app,json

3.1、pages 添加页面文件
3.2、window

在这里插入图片描述
在这里插入图片描述

3.3、tabBar

在这里插入图片描述
在这里插入图片描述

4、页面配置 pages.json

在这里插入图片描述
在这里插入图片描述

二、模板语法

1、text

相当于 web 中的 span 标签。行内元素,不会换行

2、view

相当于 web 中的 div 标签,块级标签,会换行

3、checkbox 复选框

4、数据绑定

WXML

<!-- 
  1 text 相当于以前web中的 span标签 行内元素  不会换行
  2 view 相当于以前web中的 div标签 块级元素  会换行
  3 checkbox 以前的复选框标签 
 -->
<!-- <text>1</text>
<text>2</text>
<view>1</view>
<view>2</view> -->

<!-- 1 字符串 -->
<view> {{msg}} </view>
<!-- 2 数字类型 -->
<view>{{num}}</view>
<!-- 3 bool类型  -->
<view> 是否是伪娘: {{isGirl}} </view>
<!-- 4 object类型 -->
<view>{{person.age}}</view>
<view>{{person.height}}</view>
<view>{{person.weight}}</view>
<view>{{person.name}}</view>

<!-- 5 在标签的属性中使用 -->
<view data-num="{{num}}"> 自定义属性</view>

<!-- 
  6 使用bool类型充当属性 checked  
    1 字符串和 花括号之间一定不要存在空格 否则会导致识别失败 
      以下写法就是错误的示范
         <checkbox checked="       {{isChecked}}"> </checkbox>

 -->
<view>
  <checkbox checked="{{isChecked}}"> </checkbox>
</view>

JS

Page({
  data: {
    msg: "hello mina",
    num: 10000,
    isGirl: false,
    person: {
      age: 74,
      height: 145,
      weight: 200,
      name: "富婆"
    }
  }
 });

注意:字符串与花括号之间不能存在空格
例如:

<checkbox checked="   {{ischecked}}"></checkbox>

5、模板表达式

WXML

<!-- 
  7 运算 => 表达式
    1 可以在花括号中 加入 表达式 --  “语句”
    2 表达式
      指的是一些简单 运算 数字运算 字符串 拼接  逻辑运算。。
      1 数字的加减。。
      2 字符串拼接
      3 三元表达式 
    3 语句
      1 复杂的代码段
        1 if else
        2 switch
        3 do while 。。。。
        4 for 。。。
 -->
<view>{{1+1}}</view>

<view>{{'1'+'1'}}</view>

<view>{{ 11%2===0 ? '偶数' : '奇数' }}</view>

三、列表渲染

1、列表循环

1.1、遍历数组

JS

Page({
  data: {
    msg: "hello mina",
    num: 10000,
    isGirl: false,
    person: {
      age: 74,
      height: 145,
      weight: 200,
      name: "富婆"
    },
    isChecked:false,
    list:[
      {
        id:0,
        name:"猪八戒"
      },
      {
        id:1,
        name:"天蓬元帅"
      },
      {
        id:2,
        name:"悟能"
      }
    ]
  }
});

WXML

<!-- 
  8 列表循环
    1 wx:for="{{数组或者对象}}"  wx:for-item="循环项的名称"  wx:for-index="循环项的索引"
    2 wx:key="唯一的值" 用来提高列表渲染的性能
      1 wx:key 绑定一个普通的字符串的时候 那么这个字符串名称 肯定是 循环数组 中的 对象的 唯一属性
      2 wx:key ="*this"  就表示 你的数组 是一个普通的数组  *this 表示是 循环项 
        [1,2,3,44,5]
        ["1","222","adfdf"]
    3 当出现 数组的嵌套循环的时候 尤其要注意  以下绑定的名称 不要重名
        wx:for-item="item" wx:for-index="index"
    4 默认情况下 我们 不写
       wx:for-item="item" wx:for-index="index"
       小程序也会把 循环项的名称 和 索引的名称 item 和 index 
       只有一层循环的话 (wx:for-item="item" wx:for-index="index") 可以省略

 -->
 <view>
   <view 
  wx:for="{{list}}"
  wx:for-item="item"
  wx:for-index="index"
  wx:key="id"
   >
     索引:{{index}}
     --
     值:{{item.name}}
   </view>
 </view>
1.2、遍历对象

WXML

<!-- 
  9 对象循环
    1 wx:for="{{对象}}" wx:for-item="对象的值"  wx:for-index="对象的属性"
    2 循环对象的时候 最好把 item和index的名称都修改一下
      wx:for-item="value"  wx:for-index="key"
 -->
  <view>
   <view>对象循环</view>
   <view 
  wx:for="{{person}}"
  wx:for-item="value"  
  wx:for-index="key"
  wx:key="age"
  >
     属性:{{key}}
     --
     值:{{value}}
   </view>
 </view>

2、block标签

WXML

 <!-- 
   10 block
    1 占位符的标签 
    2 写代码的时候 可以看到这标签存在
    3 页面渲染 小程序会把它移除掉
  -->

  <view>
    <block 
   wx:for="{{list}}"
   wx:for-item="item"
   wx:for-index="index"
   wx:key="id"
   class="my_list"
    >
      索引:{{index}}
      --
      值:{{item.name}}
    </block>
  </view>

四、条件渲染

1、wx:if

WXML

  <!-- 
    11 条件渲染
      1 wx:if="{{true/false}}"
        1 if , else , if else
        wx:if
        wx:elif
        wx:else 
      2 hidden 
        1 在标签上直接加入属性 hidden 
        2 hidden="{{true}}"

      3 什么场景下用哪个
        1 当标签不是频繁的切换显示 优先使用 wx:if
          直接把标签从 页面结构给移除掉 
        2 当标签频繁的切换显示的时候 优先使用 hidden
          通过添加样式的方式来切换显示 
          hidden 属性 不要和 样式 display一起使用
   -->

   <view>
     <view>条件渲染</view>
     <view wx:if="{{true}}">显示</view>
     <view wx:if="{{false}}">隐藏</view>

     <view wx:if="{{flase}}">1</view>
     <view wx:elif="{{flase}}">2 </view>
     <view wx:else> 3 </view>

     <view>---------------</view>
     <view hidden >hidden1</view>
     <view hidden="{{false}}" >hidden2</view>

     <view>-----000-------</view>
     <view wx:if="{{false}}">wx:if</view>
     <view hidden  style="display: flex;" >hidden</view>
   </view>

2、hidden

在这里插入图片描述

五、事件绑定

1、bindinput 监听文本框发生变化

1.1、实现双向绑定功能

WXML

<!-- 
  1 需要给input标签绑定 input事件 
    绑定关键字 bindinput
  2 如何获取 输入框的值 
    通过事件源对象来获取  
    e.detail.value 
  3 把输入框的值 赋值到 data当中
    不能直接 
      1 this.data.num=e.detail.value 
      2 this.num=e.detail.value 
    正确的写法
      this.setData({
        num:e.detail.value 
      })
 -->
<input type="text" bindinput="handleInput" />
<view>  
  {{num}}
</view>

JS

Page({
  data: {
    num: 0
  },
  // 输入框的input事件的执行逻辑
  handleInput(e) {
    // console.log(e.detail.value );
    this.setData({
      num: e.detail.value
    })
  }
})

2、bindtap 点击事件

注意:无法在小程序事件中传参,需要使用自定义属性
WXML

<!--
  4 需要加入一个点击事件 
      1 bindtap
      2 无法在小程序当中的 事件中 直接传参 
      3 通过自定义属性的方式来传递参数
      4 事件源中获取 自定义属性
 -->
<button bindtap="handletap" data-operation="{{1}}" >+</button>
<button bindtap="handletap" data-operation="{{-1}}">-</button>
<view>  
  {{num}}
</view>

在这里插入图片描述
JS

// 加 减 按钮的事件
  handletap(e) {
    // console.log(e);
    // 1 获取自定义属性 operation
    const operation = e.currentTarget.dataset.operation;
    this.setData({
      num: this.data.num + operation
    })
  }

六、样式 WXSS

小程序不需要主动引入样式文件(link)

1、尺寸单位

1.1、rpx

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2、样式导入

在这里插入图片描述

3、选择器

微信小程序 WXSS 不支持通配符 " * "
在这里插入图片描述

4、less

在这里插入图片描述

七、常见组件(标签)

1、view

在这里插入图片描述

2、text

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3、image

在这里插入图片描述
在这里插入图片描述
WXML

<!-- 
  image 图片标签
  1 src 指定要加载的图片的路径
    图片存在默认的宽度和高度 320 * 240      原图大小是 200 * 100
  2 mode 决定 图片内容 如何 和 图片标签 宽高 做适配
    1 scaleToFill 默认值 不保持纵横比缩放图片,使图片的宽高完全拉伸至填满 image 元素 
    2 aspectFit 保持宽高比 确保图片的长边 显示出来   页面轮播图 常用
    3 aspectFill 保持纵横比缩放图片,只保证图片的 短 边能完全显示出来。  少用
    4 widthFix 以前web的图片的 宽度指定了之后 高度 会自己按比例来调整   常用  
    5 bottom。。 类似以前的backgroud-position 
  3 小程序当中的图片 直接就支持 懒加载  lazy-load
    1 lazy-load 会自己判断 当 图片 出现在 视口  上下 三屏的高度 之内的时候  自己开始加载图片 
 -->
 <image mode="bottom" lazy-load src="https://tva2.sinaimg.cn/large/007DFXDhgy1g51jlzfb4lj305k02s0sp.jpg" />

八、swiper 轮播图

1、swiper标签与swiper-item

在这里插入图片描述

2、swiper属性

在这里插入图片描述
在这里插入图片描述
WXML

<!-- 
  1 轮播图外层容器 swiper
  2 每一个轮播项 swiper-item
  3 swiper标签 存在默认样式
    1 width 100%
    2 height 150px    image 存在默认宽度和高度 320 * 240 
    3 swiper 高度 无法实现由内容撑开 
  4 先找出来 原图的宽度和高度 等比例 给swiper 定 宽度和高度
    原图的宽度和高度  1125 * 352 px
    swiper 宽度 / swiper  高度 =  原图的宽度  /  原图的高度
    swiper  高度  =  swiper 宽度 *  原图的高度 / 原图的宽度
    height: 100vw * 352 /  1125
  5 autoplay 自动轮播
  6 interval 修改轮播时间
  7 circular 衔接轮播
  8 indicator-dots 显示 指示器 分页器 索引器 
  9 indicator-color 指示器的未选择的颜色 
  10 indicator-active-color 选中的时候的指示器的颜色 
 -->
<swiper autoplay interval="1000" circular indicator-dots indicator-color="#0094ff" indicator-active-color="#ff0094">
    <swiper-item> <image mode="widthFix" src="//gw.alicdn.com/imgextra/i1/44/O1CN013zKZP11CCByG5bAeF_!!44-0-lubanu.jpg" /> </swiper-item>
    <swiper-item> <image mode="widthFix" src="//aecpm.alicdn.com/simba/img/TB1CWf9KpXXXXbuXpXXSutbFXXX.jpg_q50.jpg" /> </swiper-item>
    <swiper-item> <image mode="widthFix" src="//gw.alicdn.com/imgextra/i2/37/O1CN01syHZxs1C8zCFJj97b_!!37-0-lubanu.jpg" /> </swiper-item>
</swiper>

WXSS

swiper {
  width: 100%;
  /* height: calc(100vw * 352 /  1125); */
  height: 31.28vw;
}
image {
  width: 100%;
}

九、navigator导航标签

类似a标签 超链接标签
在这里插入图片描述
WXML

<!-- 
  导航组件 navigator
  0 块级元素 默认会换行  可以直接加宽度和高度 
  1 url 要跳转的页面路径  绝对路径 相对路径
  2 target 要跳转到当前的小程序 还是其他的小程序的页面
    self 默认值 自己 小程序的页面 
    miniProgram 其他的小程序的页面
  3 open-type 跳转的方式
    1 navigate 默认值 	保留当前页面,跳转到应用内的某个页面,但是不能跳到 tabbar 页面
    2 redirect	关闭当前页面,跳转到应用内的某个页面,但是不允许跳转到 tabbar 页面。
    3 switchTab	跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
    4 reLaunch	关闭所有页面,打开到应用内的某个页面
 -->

 <navigator url="/pages/demo10/demo10"> 轮播图页面 </navigator>
 <navigator url="/pages/index/index"> 直接跳转到 tabbar页面 </navigator>
 <navigator open-type="redirect" url="/pages/demo10/demo10">  轮播图页面 redirect </navigator>
 <navigator open-type="switchTab" url="/pages/index/index">  switchTab直接跳转到 tabbar页面 </navigator>
 <navigator open-type="reLaunch" url="/pages/index/index">  reLaunch 可以随便跳 </navigator> 

十、rich-text 富文本标签

在这里插入图片描述
在这里插入图片描述

十二、buttom

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1、属性

<!-- 
  button 标签
  1 外观的属性
    1 size 控制按钮的大小
      1 default 默认大小
      2 mini 小尺寸
    2 type 用来控制按钮的颜色
      1 default 灰色
      2 primary 绿色
      3 warn 红色
    3 plain  按钮是否镂空,背景色透明
    4 loading 文字前显示正在等待图标
 -->
 <button>默认按钮</button>
 <button size="mini">  mini 默认按钮</button>
 <button type="primary"> primary 按钮</button> 
 <button type="warn"> warn 按钮</button> 
 <button type="warn" plain> plain 按钮</button> 
 <button type="primary" loading> loading 按钮</button> 

2、buttom 开放能力

<!-- 

  button 开发能力
  open-type:
  1 contact 直接打开  客服对话功能  需要在微信小程序的后台配置   只能够通过真机调试来打开 
  2 share 转发当前的小程序 到微信朋友中   不能把小程序 分享到 朋友圈 
  3 getPhoneNumber 获取当前用户的手机号码信息 结合一个事件来使用  不是企业的小程序账号 没有权限来获取用户的手机号码 
    1 绑定一个事件 bindgetphonenumber 
    2 在事件的回调函数中  通过参数来获取信息 
    3 获取到的信息  已经加密过了 
      需要用户自己待见小程序的后台服务器,在后台服务器中进行解析 手机号码,返回到小程序中 就可以看到信息了
  4 getUserInfo 获取当前用户的个人信息
    1 使用方法 类似 获取用户的手机号码
    2 可以直接获取 不存在加密的字段 
  5 launchApp 在小程序当中 直接打开 app
    1 需要现在 app中 通过app的某个链接 打开 小程序
    2 在小程序 中 再通过 这个功能 重新打开 app
    3 找到 京东的app 和 京东的小程序  
  6 openSetting 打开小程序内置的 授权页面
    1 授权页面中 只会出现 用户曾经点击过的 权限 
  7 feedback 打开 小程序内置的 意见反馈页面 
    1 只能够通过真机调试来打开 

  -->
<button open-type="contact">contact</button>
<button open-type="share">share</button>
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">getPhoneNumber</button>
<button open-type="getUserInfo" bindgetuserinfo="getUserInfo">getUserInfo</button>
<button open-type="launchApp">launchApp</button>
<button open-type="openSetting">openSetting</button>
<button open-type="feedback">feedback</button>

在这里插入图片描述

十三、icon

在这里插入图片描述


<!-- 
  小程序中的字体图标
  1 type 图标的类型
    success|success_no_circle|info|warn|waiting|cancel|download|search|clear
  2 size 大小 
  3 color 图标的颜色
 -->
<icon  type="cancel" size="60" color="#0094ff"> </icon>

十四、radio

在这里插入图片描述
WXML


<!-- 
  radio 单选框
  1 radio标签 必须要和 父元素 radio-group来使用
  2 value 选中的单选框的值 
  3 需要给 radio-group 绑定 change事件 
  4 需要在页面中显示 选中的值
 -->
 <radio-group bindchange="handleChange">
   <radio color="red" value="male"></radio>
   <radio color="red" value="female" ></radio>
 </radio-group>

 <view>您选中的是:{{gender}}</view>

JS

Page({
  data: {
    gender: ""
  },
  handleChange(e){
    // 1 获取单选框中的值
    let gender=e.detail.value;
    // 2 把值 赋值给 data中的数据
    this.setData({
      // gender:gender
      gender
    })
  }
})

十五、checkbox

在这里插入图片描述
WXML

<view>
  <checkbox-group bindchange="handleItemChange">
    <checkbox value="{{item.value}}" wx:for="{{list}}" wx:key="id">
      {{item.name}}
    </checkbox>

  </checkbox-group>
  <view>
    选中的水果:{{checkedList}}
  </view>
</view>

JS

Page({
  data: {
    list:[
      {
        id:0,
        name:"🍎",
        value:"apple"
      },
      {
        id:1,
        name:"🍇",
        value:"grape"
      },
      {
        id:2,
        name:"🍌",
        value:"bananer"
      }
    ],
    checkedList:[]
  },
  // 复选框的选中事件
  handleItemChange(e){
    // 1 获取被选中的复选框的值
    const checkedList=e.detail.value;
    // 2 进行赋值
    this.setData({
      checkedList
    })
  }
})

十六、自定义组件

1、创建目录

在这里插入图片描述
在这里插入图片描述

2、声明组件

在这里插入图片描述
到需要引用该组件的页面的json文件中声明

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

在页面wxml中直接使用

<Tabs></Tabs>

3、导航栏组件案例

在这里插入图片描述
在这里插入图片描述

4、父向子传递数据

在这里插入图片描述

5、子向父传递数据

子组件
wxml

<view class="tabs_title">
  <view
  wx:for="{{tabs}}"
  wx:key="id"
  class="title_item  {{item.isActive?'active':''}} "
  bindtap="handleItemTap"
  data-index="{{index}}"
  >

  {{item.value}}
</view>

js

methods: {
    hanldeItemTap(e){
      //  2 获取索引
      const {index}=e.currentTarget.dataset;
      // 5 触发父组件中的自定义事件 同时传递数据给  
      this.triggerEvent("itemChange",{index});
    }
  }

父组件
WXML

<!-- 
  1 父组件(页面) 向子组件 传递数据 通过 标签属性的方式来传递
    1 在子组件上进行接收
    2 把这个数据当成是data中的数据直接用即可
  2 子向父传递数据 通过事件的方式传递
    1 在子组件的标签上加入一个 自定义事件
  
 -->
<Tabs tabs="{{tabs}}" binditemChange="handleItemChange" >
</Tabs>

JS

// 自定义事件 用来接收子组件传递的数据的
  handleItemChange(e) {
    // 接收传递过来的参数
    const { index } = e.detail;
    let { tabs } = this.data;
    tabs.forEach((v, i) => i === index ? v.isActive = true : v.isActive = false);
    this.setData({
      tabs
    })
  }

6、slot 插槽

TAbs 组件 WXML

<view class="tabs_content">
    <!-- 
      slot 标签 其实就是一个占位符 插槽
      等到 父组件调用 子组件的时候 再传递 标签过来 最终 这些被传递的标签
      就会替换 slot 插槽的位置 
     -->
    <slot></slot>
  </view>

页面 WXML

<Tabs tabs="{{tabs}}" binditemChange="handleItemChange" >

<block wx:if="{{tabs[0].isActive}}">0 </block>
<block wx:elif="{{tabs[1].isActive}}">1 </block>
<block wx:elif="{{tabs[2].isActive}}">2 </block>
<block wx:else>3</block>
 
</Tabs>

7、其他属性

在这里插入图片描述

十七、小程序的生命周期

1、应用生命周期

在这里插入图片描述

App({
  //  1 应用第一次启动的就会触发的事件  
  onLaunch() {
    //  在应用第一次启动的时候 获取用户的个人信息 
    // console.log("onLaunch");
    // aabbcc

    // js的方式来跳转 不能触发 onPageNotFound
    // wx.navigateTo({
    //   url: '/11/22/33'
    // });
      
  },

  // 2 应用 被用户看到 
  onShow(){
    // 对应用的数据或者页面效果 重置 
    // console.log("onShow");
  },
  // 3 应用 被隐藏了 
  onHide(){
    // 暂停或者清除定时器 
    // console.log("Hide");
  },
  // 4 应用的代码发生了报错的时候 就会触发
  onError(err){
    // 在应用发生代码报错的时候,收集用户的错误信息,通过异步请求 将错误的信息发送后台去
    // console.log("onError");
    // console.log(err);
  },
  // 5 页面找不到就会触发 
  //  应用第一次启动的时候,如果找不到第一个入口页面 才会触发
  onPageNotFound(){
    // 如果页面不存在了 通过js的方式来重新跳转页面 重新跳到第二个首页
    // 不能跳到tabbar页面  导航组件类似  
    wx.navigateTo({
      url: '/pages/demo09/demo09' 
    });  
      
    // console.log("onPageNotFound");
  }
})

2、页面生命周期

在这里插入图片描述

/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log("onLoad");
    // onLoad发送异步请求来初始化页面数据 
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    console.log("onShow");
  },
  /**
    * 生命周期函数--监听页面初次渲染完成
    */
  onReady: function () {
    console.log("onReady");
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
    console.log("onHide");
  },

  /**
   * 生命周期函数--监听页面卸载 也是可以通过点击超链接来演示 
   * 
   */
  onUnload: function () {
    console.log("onUnload");
  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
    console.log("onPullDownRefresh");
    // 页面的数据 或者效果 重新 刷新
  },

  /**
   * 页面上拉触底事件的处理函数
   * 需要让页面 出现上下滚动才行 
   */
  onReachBottom: function () {
    console.log("onReachBottom");
    // 上拉加载下一页数据 
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
    console.log("onShareAppMessage");
  },
  /**
   * 页面滚动 就可以触发 
   */
  onPageScroll(){
    console.log("onPageScroll");
  },
  /**
   * 页面的尺寸发生改变的时候 触发
   * 小程序 发生了 横屏竖屏 切换的时候触发 
   */
  onResize(){
    console.log("onResize");
  },
  /**
   * 1 必须要求当前页面 也是tabbar页面
   * 2 点击的自己的tab item的时候才触发
   */
  onTabItemTap(){
    console.log("onTabItemTap");
  }

小程序项目

一、完整项目

github

https://github.com/ScissorSeven/wechart-Shopping-Mall/tree/master

二、网络请求

1、文档

网络请求

2、示例代码

onLoad: function(options) {
	wx.request({
	  url: 'test.php', //仅为示例,并非真实的接口地址
	  data: {
	    x: '',
	    y: ''
	  },
	  header: {
	    'content-type': 'application/json' // 默认值
	  },
	  success (res) {
	    console.log(res.data)
	  }
	})
}

三、轮播图图片

wxml

<!-- 轮播图 开始 -->
  <view class="index_swiper">
    <swiper autoplay indicator-dots circular>
      <swiper-item 
      wx:for="{{swiperList}}"
      wx:key="goods_id">
      <image mode="widthFix" src="{{item.image_src}}"></image>
      </swiper-item>
    </swiper>
  </view>
  <!-- 轮播图 结束 -->

在这里插入图片描述

wx.request({
      url: 'http://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata',
      data: {},
      header: {'content-type':'application/json'},
      method: 'GET',
      dataType: 'json',
      responseType: 'text',
      success: (result) => {
        this.setData({
          swiperList: result.data.message
          })
      },
      fail: () => {},
      complete: () => {}
    });

四、Promise进行网络请求封装

request/index.js

export const request=(params)=>{
   // 定义公共的url
  const baseUrl="http://api-hmugo-web.itheima.net/api/public/v1";
  return new Promise((resolve,reject)=>{
    wx.request({
     ...params,
     url:baseUrl+params.url,
     success:(result)=>{
       resolve(result.data.message);
     },
     fail:(err)=>{
       reject(err);
     }
     
    });
  })
}

页面.js 导入request

import { request } from "../../request/index.js";
Page({
  data: {
    // 轮播图数组
    swiperList: [],
  },
  // 页面开始加载 就会触发
  onLoad: function (options) {
    // 1 发送异步请求获取轮播图数据  优化的手段可以通过es6的 promise来解决这个问题 
    this.getSwiperList(); 
  },
  // 获取轮播图数据
  getSwiperList(){
    request({ url: "/home/swiperdata" })
    .then(result => {
      this.setData({
        swiperList: result
      })
    })
  },

五、滚动视图 scroll-view

1、文档

https://developers.weixin.qq.com/miniprogram/dev/component/scroll-view.html
wxml

	<!-- 左侧菜单 -->
      <scroll-view scroll-y class="left_menu">
        <view
        class="menu_item {{index===currentIndex?'active':''}}"
        wx:for="{{leftMenuList}}"
        wx:key="*this"
        bindtap="handleItemTap"
        data-index="{{index}}"
        >
        {{item}}
        </view>
      </scroll-view>
      <!-- 右侧商品内容 -->
      <scroll-view scroll-top="{{scrollTop}}" scroll-y class="right_content">
        <view class="goods_group"
        wx:for="{{rightContent}}"
        wx:for-index="index1"
        wx:for-item="item1"
        >
          <view class="goods_title">
            <text class="delimiter">/</text>
            <text class="title">{{item1.cat_name}}</text>
            <text class="delimiter">/</text>
          </view>
          <view class="goods_list">
            <navigator
            wx:for="{{item1.children}}"
            wx:for-index="index2"
            wx:for-item="item2"
            wx:key="cat_id"
            url="/pages/goods_list/index?cid={{item2.cat_id}}"
            >
            <image mode="widthFix" src="{{item2.cat_icon}}"></image>
            <view class="goods_name">{{item2.cat_name}}</view>
            </navigator>
          </view>
        </view>
      </scroll-view>

less

page{
  height: 100%;
}
.cates{
  height: 100%;
  .cates_container{
    /* less中使用calc的时候要注意 */
    height: ~'calc( 100vh - 90rpx )';
    display: flex;
    .left_menu{
      /* 子项 高度 100% flex */
      flex: 2;
     
      .menu_item{
        height: 80rpx;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 30rpx;
      }
      .active{
        color: var(--themeColor);
        border-left: 5rpx solid currentColor;
      }
    }
    .right_content{
       /* 子项 高度 100% flex */
      flex: 5;
      .goods_group{
        .goods_title{
          height: 80rpx;
          display: flex;
          justify-content: center;
          align-items: center;
          .delimiter{
            color: #ccc;
            padding: 0 10rpx;
          }
          .title{}
        }
        .goods_list{
          display: flex;
          flex-wrap: wrap;
          navigator{
            width: 33.33%;
            text-align: center;
            image{
              width: 50%;
            }
            .goods_name{}
          }
        }
      }
    }
  }
}

六、缓存

网络请求资源过大时,可以使用本地缓存
0 web中的本地存储和 小程序中的本地存储的区别
1 写代码的方式不一样了
web: localStorage.setItem(“key”,“value”) localStorage.getItem(“key”)
小程序中: wx.setStorageSync(“key”, “value”); wx.getStorageSync(“key”);
2:存的时候 有没有做类型转换
web: 不管存入的是什么类型的数据,最终都会先调用以下 toString(),把数据变成了字符串 再存入进去
小程序: 不存在 类型转换的这个操作 存什么类似的数据进去,获取的时候就是什么类型
1 先判断一下本地存储中有没有旧的数据
{time:Date.now(),data:[…]}
2 没有旧数据 直接发送新请求
3 有旧的数据 同时 旧的数据也没有过期 就使用 本地存储中的旧数据即可

//  1 获取本地存储中的数据  (小程序中也是存在本地存储 技术)
const Cates = wx.getStorageSync("cates");
// 2 判断
if (!Cates) {
  // 不存在  发送请求获取数据
  this.getCates();
} else {
  // 有旧的数据 定义过期时间  10s 改成 5分钟
  if (Date.now() - Cates.time > 1000 * 10) {
    // 重新发送请求
    this.getCates();
  } else {
    // 可以使用旧的数据
    this.Cates = Cates.data;
    let leftMenuList = this.Cates.map(v => v.cat_name);
    let rightContent = this.Cates[0].children;
    this.setData({
      leftMenuList,
      rightContent
    })
  }
}

七、ES7的async方法

1、使用步骤

es7的async号称是解决回调的最终方案
1、在小程序的开发工具,勾选es6转es5语法
2、下载facebook的regenerator库中的regenerator/packages/regenerator-runtime/runtime.js
3、在小程序目录下新建文件夹 lib/runtime/runtime.js ,将代码拷贝进去
4、在每一个需要使用async语法的页面js文件,都引入(不能全局引入)

`import regeneratorRuntime from '../../lib/runtime/runtime';

2、数据请求、async的js代码

JS

import { request } from "../../request/index.js";
import regeneratorRuntime from '../../lib/runtime/runtime';
Page({
  data: {
    // 左侧的菜单数据
    leftMenuList: [],
    // 右侧的商品数据
    rightContent: [],
    // 被点击的左侧的菜单
    currentIndex: 0,
    // 右侧内容的滚动条距离顶部的距离
    scrollTop: 0
  },
  // 接口的返回数据
  Cates: [],

  onLoad: function (options) {
    /* 
    0 web中的本地存储和 小程序中的本地存储的区别
      1 写代码的方式不一样了 
        web: localStorage.setItem("key","value") localStorage.getItem("key")
    小程序中: wx.setStorageSync("key", "value"); wx.getStorageSync("key");
      2:存的时候 有没有做类型转换
        web: 不管存入的是什么类型的数据,最终都会先调用以下 toString(),把数据变成了字符串 再存入进去
      小程序: 不存在 类型转换的这个操作 存什么类似的数据进去,获取的时候就是什么类型
    1 先判断一下本地存储中有没有旧的数据
      {time:Date.now(),data:[...]}
    2 没有旧数据 直接发送新请求 
    3 有旧的数据 同时 旧的数据也没有过期 就使用 本地存储中的旧数据即可
     */

    //  1 获取本地存储中的数据  (小程序中也是存在本地存储 技术)
    const Cates = wx.getStorageSync("cates");
    // 2 判断
    if (!Cates) {
      // 不存在  发送请求获取数据
      this.getCates();
    } else {
      // 有旧的数据 定义过期时间  10s 改成 5分钟
      if (Date.now() - Cates.time > 1000 * 10) {
        // 重新发送请求
        this.getCates();
      } else {
        // 可以使用旧的数据
        this.Cates = Cates.data;
        let leftMenuList = this.Cates.map(v => v.cat_name);
        let rightContent = this.Cates[0].children;
        this.setData({
          leftMenuList,
          rightContent
        })
      }
    }

  },
  // 获取分类数据
  async getCates() {
    // request({
    //   url: "/categories"
    // })
    //   .then(res => {
    //     this.Cates = res.data.message;

    //     // 把接口的数据存入到本地存储中
    //     wx.setStorageSync("cates", { time: Date.now(), data: this.Cates });


    //     // 构造左侧的大菜单数据
    //     let leftMenuList = this.Cates.map(v => v.cat_name);
    //     // 构造右侧的商品数据
    //     let rightContent = this.Cates[0].children;
    //     this.setData({
    //       leftMenuList,
    //       rightContent
    //     })
    //   })

    // 1 使用es7的async await来发送请求
    const res = await request({ url: "/categories" });
    // this.Cates = res.data.message;
    this.Cates = res;
    // 把接口的数据存入到本地存储中
    wx.setStorageSync("cates", { time: Date.now(), data: this.Cates });
    // 构造左侧的大菜单数据
    let leftMenuList = this.Cates.map(v => v.cat_name);
    // 构造右侧的商品数据
    let rightContent = this.Cates[0].children;
    this.setData({
      leftMenuList,
      rightContent
    })
  },
  // 左侧菜单的点击事件
  handleItemTap(e) {
    /* 
    1 获取被点击的标题身上的索引
    2 给data中的currentIndex赋值就可以了
    3 根据不同的索引来渲染右侧的商品内容
     */
    const { index } = e.currentTarget.dataset;

    let rightContent = this.Cates[index].children;
    this.setData({
      currentIndex: index,
      rightContent,
      // 重新设置 右侧内容的scroll-view标签的距离顶部的距离
      scrollTop: 0
    })

  }
})

八、组件数据的父传子与子传父

1、TAbs

1.1、properties 接收父组件传递过来的数据
1.2、this.triggerEvent("",value);自定义方法传递数据给父组件

Tabs.wxml

<view class="tabs">
  <view class="tabs_title">
    <view
    wx:for="{{tabs}}"
    wx:key="id"
    class="title_item  {{item.isActive?'active':''}} "
    bindtap="handleItemTap"
    data-index="{{index}}"
    >

    {{item.value}}
  </view>
  </view>
  <view class="tabs_content">
    <slot></slot>
  </view>
</view>

Tabs.js

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    tabs:{
      type:Array,
      value:[]
    }
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {
    // 点击事件
    handleItemTap(e){
      // 1 获取点击的索引
      const {index}=e.currentTarget.dataset;
      // 2 触发 父组件中的事件 自定义
      this.triggerEvent("tabsItemChange",{index});
    }
  }
})

2、index页面

2.1、标签自定义属性给子组件传递数据
2.2、标签绑定子组件的方法 来接收子组件的数据
<Searchinput>
</Searchinput>
<!-- 监听自定义事件 -->
<Tabs tabs="{{tabs}}" bindtabsItemChange="handleTabsItemChange" >
  
  <block wx:if="{{tabs[0].isActive}}">0</block>
  <block wx:elif="{{tabs[1].isActive}}">1</block>
  <block wx:elif="{{tabs[2].isActive}}">2</block>

</Tabs>
  // 标题点击事件 从子组件传递过来
  handleTabsItemChange(e){
    // 1 获取被点击的标题索引
    const {index}=e.detail;
    // 2 修改源数组
    let {tabs}=this.data;
    tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
    // 3 赋值到data中
    this.setData({
      tabs
    })
  },

九、下拉触底事件

onReachBottom()

1、官方文档

https://developers.weixin.qq.com/miniprogram/dev/reference/api/Page.html#onReachBottom

2、代码

index.wxml

<SearchInput></SearchInput>
<!-- 监听自定义事件 -->
<Tabs tabs="{{tabs}}" bindtabsItemChange="handleTabsItemChange" >
  
  <block wx:if="{{tabs[0].isActive}}">
    <view class="first_tab">
        <navigator class="goods_item"
        wx:for="{{goodsList}}"
        wx:key="goods_id"
        url="/pages/goods_detail/index?goods_id={{item.goods_id}}"
        >
            <!-- 左侧 图片容器 -->
            <view class="goods_img_wrap">
              <image mode="widthFix" src="{{item.goods_small_logo?item.goods_small_logo:'https://ww1.sinaimg.cn/large/007rAy9hgy1g24by9t530j30i20i2glm.jpg'}}"></image>
            </view>
            <!-- 右侧 商品容器 -->
            <view class="goods_info_wrap">
              <view class="goods_name">{{item.goods_name}}</view>
              <view class="goods_price">¥{{item.goods_price}}</view>
            </view>
          </navigator>
    </view>
  </block>
  <block wx:elif="{{tabs[1].isActive}}">1</block>
  <block wx:elif="{{tabs[2].isActive}}">2</block>

</Tabs>

index.js

/* 
1 用户上滑页面 滚动条触底 开始加载下一页数据
  1 找到滚动条触底事件  微信小程序官方开发文档寻找
  2 判断还有没有下一页数据
    1 获取到总页数  只有总条数
      总页数 = Math.ceil(总条数 /  页容量  pagesize)
      总页数     = Math.ceil( 23 / 10 ) = 3
    2 获取到当前的页码  pagenum
    3 判断一下 当前的页码是否大于等于 总页数 
      表示 没有下一页数据

  3 假如没有下一页数据 弹出一个提示
  4 假如还有下一页数据 来加载下一页数据
    1 当前的页码 ++
    2 重新发送请求
    3 数据请求回来  要对data中的数组 进行 拼接 而不是全部替换!!!

 */
import { request } from "../../request/index.js";
import regeneratorRuntime from '../../lib/runtime/runtime';
Page({
  data: {
    tabs: [
      {
        id: 0,
        value: "综合",
        isActive: true
      },
      {
        id: 1,
        value: "销量",
        isActive: false
      },
      {
        id: 2,
        value: "价格",
        isActive: false
      }
    ],
    goodsList:[]
  },
  // 接口要的参数
  QueryParams:{
    query:"",
    cid:"",
    pagenum:1,
    pagesize:10
  },
  // 总页数
  totalPages:1,
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.QueryParams.cid=options.cid||"";
    this.QueryParams.query=options.query||"";
    this.getGoodsList();


  },

  // 获取商品列表数据
  async getGoodsList(){
    const res=await request({url:"/goods/search",data:this.QueryParams});
    // 获取 总条数
    const total=res.total;
    // 计算总页数
    this.totalPages=Math.ceil(total/this.QueryParams.pagesize);
    // console.log(this.totalPages);
    this.setData({
      // 拼接了数组
      goodsList:[...this.data.goodsList,...res.goods]
    })
      
  },


  // 标题点击事件 从子组件传递过来
  handleTabsItemChange(e){
    // 1 获取被点击的标题索引
    const {index}=e.detail;
    // 2 修改源数组
    let {tabs}=this.data;
    tabs.forEach((v,i)=>i===index?v.isActive=true:v.isActive=false);
    // 3 赋值到data中
    this.setData({
      tabs
    })
  },
  // 页面上滑 滚动条触底事件
  onReachBottom(){
  //  1 判断还有没有下一页数据
    if(this.QueryParams.pagenum>=this.totalPages){
      // 没有下一页数据
      //  console.log('%c'+"没有下一页数据","color:red;font-size:100px;background-image:linear-gradient(to right,#0094ff,pink)");
      wx.showToast({ title: '没有下一页数据' });
        
    }else{
      // 还有下一页数据
      //  console.log('%c'+"有下一页数据","color:red;font-size:100px;background-image:linear-gradient(to right,#0094ff,pink)");
      this.QueryParams.pagenum++;
      this.getGoodsList();
    }
  }
})

十、上拉刷新事件

1、page.json

 "enablePullDownRefresh":true,
 "backgroundTextStyle":"dark"

2、js代码,接第九章代码

/*
2 下拉刷新页面
  1 触发下拉刷新事件 需要在页面的json文件中开启一个配置项
    找到 触发下拉刷新的事件
  2 重置 数据 数组 
  3 重置页码 设置为1
  4 重新发送请求
  5 数据请求回来 需要手动的关闭 等待效果

 */
   // 下拉刷新事件 
  onPullDownRefresh(){
    // 1 重置数组
    this.setData({
      goodsList:[]
    })
    // 2 重置页码
    this.QueryParams.pagenum=1;
    // 3 发送请求
    this.getGoodsList();
  }

加入关闭窗口方法

  // 获取商品列表数据
  async getGoodsList(){
    const res=await request({url:"/goods/search",data:this.QueryParams});
    // 获取 总条数
    const total=res.total;
    // 计算总页数
    this.totalPages=Math.ceil(total/this.QueryParams.pagesize);
    // console.log(this.totalPages);
    this.setData({
      // 拼接了数组
      goodsList:[...this.data.goodsList,...res.goods]
    })

    // 关闭下拉刷新的窗口 如果没有调用下拉刷新的窗口 直接关闭也不会报错  
    wx.stopPullDownRefresh();
      
  },

十一、消息对话框

1、官方文档

https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showToast.html

2、代码

写在网络请求封装中
requert/index.js


// 同时发送异步代码的次数
let ajaxTimes=0;
export const request=(params)=>{
  // 判断 url中是否带有 /my/ 请求的是私有的路径 带上header token
  let header={...params.header};
  if(params.url.includes("/my/")){
    // 拼接header 带上token
    header["Authorization"]=wx.getStorageSync("token");
  }


  ajaxTimes++;
  // 显示加载中 效果
  wx.showLoading({
    title: "加载中",
    mask: true
  });
    

  // 定义公共的url
  const baseUrl="http://api-hmugo-web.itheima.net/api/public/v1";
  return new Promise((resolve,reject)=>{
    wx.request({
     ...params,
     header:header,
     url:baseUrl+params.url,
     success:(result)=>{
       resolve(result.data.message);
     },
     fail:(err)=>{
       reject(err);
     },
     complete:()=>{
      ajaxTimes--;
      if(ajaxTimes===0){
        //  关闭正在等待的图标
        wx.hideLoading();
      }
     }
    });
  })
}

十二、在新界面中全局预览图片

1、官方文档

https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.previewImage.html

wx.previewImage({
  current: '', // 当前显示图片的http链接
  urls: [] // 需要预览的图片http链接列表
})

十三、获取收货地址

1、openSetting 设置权限

调起客户端小程序设置界面,返回用户设置的操作结果。设置界面只会出现小程序已经向用户请求过的权限。

2、wx.chooseAddress

获取用户收货地址。调起用户编辑收货地址原生界面,并在编辑完成后返回用户选择的地址。

1 获取用户的收货地址
	1 .1、绑定点击事件
	2.1、 调用小程序内置 api  获取用户的收货地址  wx.chooseAddress
2 获取 用户 对小程序 所授予 获取地址的  权限 状态 scope
	1 假设 用户 点击获取收货地址的提示框 确定  authSetting scope.address 
 	 scope 值 true 直接调用 获取收货地址
	2 假设 用户 从来没有调用过 收货地址的api 
  	scope undefined 直接调用 获取收货地址
3 假设 用户 点击获取收货地址的提示框 取消   
  scope 值 false 
  1 诱导用户 自己 打开 授权设置页面(wx.openSetting) 当用户重新给与 获取地址权限的时候 
  2 获取收货地址

在这里插入图片描述

十四、every数组方法

every数组方法会遍历数组,接收一个回调函数,如果每个回调函数的返回值都是true ,那么every方法返回的结果就为true ,
如果,有一个回调函数返回的是false ,那么不在继续遍历,直接返回 false
空数组返回 ture

十五、模态对话框

1、官方文档

https://developers.weixin.qq.com/miniprogram/dev/api/ui/interaction/wx.showModal.html

2、示例代码

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

十六、微信支付

1 哪些人 哪些帐号 可以实现微信支付
  1 企业帐号 
2 企业帐号的小程序后台中 必须 给开发者 添加上白名单 
  1 一个 appid 可以同时绑定多个开发者
  2 这些开发者就可以公用这个appid 和 它的开发权限 

1、官方文档

https://developers.weixin.qq.com/miniprogram/dev/api/open-api/payment/wx.requestPayment.html

十七、获取“我的信息”

1、buttom 的 open-type属性

getUserinfo

在这里插入图片描述

十八、路由

跳转页面

1、官方文档

https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.switchTab.html

2、wx.navigateBack(Object object)

关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。

在这里插入图片描述

2.1、示例代码
wx.navigateBack({
      delta: 1
    });

十九、回车事件

bindconfirm

在这里插入图片描述

向被打开的页面传递数据

search(e) {
      wx.navigateTo({
        url: "../../pages/search/index",
        success: function (res) {
          // 通过eventChannel向被打开页面传送数据
          res.eventChannel.emit("search_value", { data: e.detail["value"] });
          // console.log(e)
        },
      });
    },

页面接收

onLoad: function(option){
    //获取事件对象
    const eventChannel = this.getOpenerEventChannel()
    // 监听aishang事件,获取上一页面通过eventChannel传送到当前页面的数据
    let inpValue="";
    eventChannel.on("search_value", function (data) {
      // console.log("传递的参数", data);
      inpValue=data.data;
    });
  },

改变上一页监听的数据时调用

let eventChannel = this.getOpenerEventChannel();
    let obj = {
      name:'aishang',
      value:'爱尚丽明'
    }
    eventChannel.emit('aishang', { data: obj });
  //第一步就会监听到数据的变化
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值