目录

微信小程序开发-首页及详情页开发

微信小程序开发–首页及详情页开发

一、常用组件

在之前的 封装请求数据的模块 中请求轮播图的数据

1.首页轮播图数据的请求以及渲染

1.轮播图数据的请求 pages/index/index.js
data: {
    bannerlist:[]  //存放轮播图数据的列表
},
onLoad: function () {
    //请求首页轮播图的数据
    request({
        url : '/banner' //注意接口不要写错
    }).then(res => {
        console.log(res)
        // 在Vue中,this.bannerist = res.data.data
        // 在React中,this.setState(bannerlist: res.data.data)
        // 在小程序中修改状态的方式就是this.setData
        this.setData({ //将获取到的数据保存到本地变量中
          bannerlist: res.data.data
        })
    })
}

同理之前通过 /pro 接口获取到的商品列表的数据也可以通过 this.setData 来保存本地:

data: {
    bannerlist:[],  //存放轮播图数据的列表
    prolist:[] //存放商品数据的列表
},
...
this.setData({ 
    prolist: res.data.data
})

为了代码更加直白美观,可以将获取商品列表数据和请求轮播图数据另外 封装在自定义方法 中,然后在 onLoad 中调用就可以了:

onLoad: function () {
    // 请求轮播图数据
    this.getBannerlistData()
    // 请求商品列表数据
    this.getProlistData()
},
...
//请求轮播图数据
getBannerlistData () {
    request({
    url : '/banner' 
    }).then(res => {
    console.log(res)
    // 在Vue中,this.bannerist = res.data.data
    // 在React中,this.setState(bannerlist: res.data.data)
    // 在小程序中修改状态的方式就是this.setData
    this.setData({ //将获取到的数据保存到本地变量中
    bannerlist: res.data.data
    })
    })  //可以省略catch方法,。没有关系
},
  //请求商品列表数据
  getProlistData () {
      request({
      url : '/pro',
      data : {}
      }).then((res) => { //then是请求成功后的处理方法
      console.log(res)
      this.setData({ 
      prolist: res.data.data
      })
      }).catch((err) => { //catch是请求失败后的处理方法
      console.log(err)
      })
  }

3.使用组件 - 视图容器 - swiper

滑块视图容器。其中 只可放置 swiper-item 组件,否则会导致未定义的行为。 一些属性见官方文档:

<swiper
  indicator-dots="{{true}}" autoplay="{{true}}" circular="{{true}}" 
  duration="{{500}}">
  <!-- wx:key=""不知道写啥的话可以写*this,指的就是自己 -->
  <block wx:for="{{bannerlist}}" wx:key="index">
    <swiper-item >
      <image src="{{item.img}}"></image>
    </swiper-item>
  </block>
</swiper>
<prolist></prolist>

注意:上面的 item.img 是根据获取到的数据结构来判断的,不能直接写 item ,因为 item 指的是每一行的数据,我们要的仅仅是图片数据,所以只需要选取其 路径 item.img 就可以了。

https://i-blog.csdnimg.cn/blog_migrate/ba88a19f7a4d346c78dd07b15067d0b5.png#pic_center

如果碰到图片 显示不全 或者 没有铺满屏幕 的情况,在 wxss 中设置一下即可,例如铺满屏幕:

image {
  width: 100%;
}

更多设置图片格式的方法:

轮播图的使用就到此为止。

二、自定义组件 - 产品列表

1.自定义组件的布局

components/prolist/prolist.wxml 列表组件 prolist 的布局:

<view class="prolist">
  <view class="proitem">
    <view class="itemimg">
      <image class="img" src=""></image>
    </view>
    <view class="iteminfo">
      <view class="title">
        产品名称
      </view>
      <view class="price">
        ¥199
      </view>
    </view>
  </view>
</view>

2.自定义组件的样式

components/prolist/prolist.wxss 列表组件 prolist 的样式:

.prolist .proitem{
  width: 100%;
  display: flex;
  height: 100px;
  box-sizing: border-box;
  border-bottom: 1px solid #ccc;
}

.prolist .proitem .itemimg{
  width: 100px;
  height: 100px;
  padding: 5px;
}

.prolist .proitem .itemimg .img{
  width: 90px;
  height: 90px;
  box-sizing: border-box;
  border: 1px solid #ccc;
}

.prolist .proitem .iteminfo {
  padding: 3px;
}

.prolist .proitem .iteminfo .title{
  font-size: 18px;
  font-weight: bold;
}

.prolist .proitem .iteminfo .price{
  font-size: 12px;
}

3.首页请求数据,并且传递给子组件

pages/index/index.js

首页请求数据就是之前自定义的两个方法 getBannerlistData ()getProlistData ()

pages/index/index.wxml

<prolist prolist="{{prolist}}"></prolist>

vue 父组件给子组件传值:

父组件调用子组件的地方,添加一个自定义的属性,属性的值就是父组件要传递给子组件的值

如果属性的值是 变量booleannumder ,就需要绑定属性

子组件定义的地方,添加一个 props 选项, props 的值是一个数组或者对象

  1. 如果是数组,数组的元素就是添加的属性名,可以在组件中通过此属性名访问数据

  2. 如果是对象,有两种形式:

    2.1. key 值为自定义的属性名, value 值为数据类型

    2.2. key 值为自定义的属性名, value 值为一个对象,该对象有两个选项,一个为 type (数据类型),另一个为 default (默认值),如果默认值是对象或者数组,需要把 default 写成一个函数,返回对象或数组

在小程序中:

父组件调用子组件的地方,添加一个自定义的属性,属性的值就是父组件要传递给子组件的值

如果属性的值是 变量booleannumder ,就需要用 { {}} 包裹

<prolist prolist="{{ prolist }}"/>

子组件定义的地方,添加一个 properties 选项, properties 的值是一个数组或者对象

key为自定义的属性名,value值为数据类型:

properties: {
	prolist:Array 
}

可以在组件中通过此属性名访问数据

4.子组件接收数据

components/prolist/prolist.js

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    prolist: Array
  },
})

5.子组件渲染数据

components/prolist/prolist.wxml

<view class="prolist">
  <view class="proitem" wx:for="{{prolist}}" wx:key="item.proid">
    <view class="itemimg">
      <image class="img" src="{{item.proimg}}"></image>
    </view>
    <view class="iteminfo">
      <view class="title">
        {{item.proname}}
      </view>
      <view class="price">
        ¥{{item.price}}
      </view>
    </view>
  </view>
</view>

三、实现下拉刷新上拉加载

1.开启首页的下拉刷新功能

pages/index/index.json

{
  "usingComponents": {
    "prolist": "/components/prolist/prolist"
  },
  "enablePullDownRefresh": true, //实现下拉刷新
  "backgroundColor": "#efefef",
  "backgroundTextStyle": "dark"
}

2.完善相关的下拉刷新函数

pages/index/index.js

//页面相关事件处理函数---监听用户下拉刷新事件(重新请求了第一页的页面数据)
  onPullDownRefresh: function() {
    console.log("刷新了当前页面")
    this.getRefreshData() //下拉刷新之后重新请求第一页的数据
  },
  //上拉触底事件函数
  /**
   * 上拉加载---分页效果,例如开始是第一页10条数据,下拉到底之后再向数据库中请求后10条数据显示出来,这个过程需要页码
   */
  onReachBottom: function() {
    console.log("对不起已经到底了")
    this.requestMoreData()
  },
...
// 下拉刷新后重新请求第一页的数据
  getRefreshData () {
    request({
      url : '/pro',
      data : {
        pageCode: 0, // 页码默认从0开始
        limitNum: 10 //每一页默认10条数据
      }
    }).then((res) => { //then是请求成功后的处理方法
      console.log(res)
      this.setData({ 
        prolist: res.data.data
        pageCode: 1 //下拉刷新之后切记 要将页码重新置为0
      })
      // 真机测试的时候,在下拉刷新结束后需要 停止 下拉刷新的操作
      wx.stopPullDownRefresh();
    }).catch((err) => { //catch是请求失败后的处理方法
      console.log(err)
    })
  },
  // 上拉触底后再次请求更多的数据显示(翻页)
  requestMoreData () {
    request({
      url : '/pro',
      data : {
        pageCode: this.data.pageCode, // 页码默认从0开始
        limitNum: 10 //每一页默认10条数据
      }
    }).then((res) => { //then是请求成功后的处理方法
      console.log(res)
      // 请求之后需要判断
      // 1.判断还有没有数据
      if (res.data.code === '10000') {
        // 没有更多数据了,要给用户提示信息
        toast({title: '没有更多数据了'}) // 这里toast的参数必须是对象类型
      } else {
        // 2.如果有数据---请求到的数据追加到之前的数据上
        // vue 中, thisprolist = [...this.prolist,res.data.data]
        // 小程序中 修改数据的方式类似于 React
        // React 获取数据  处理数据  修改数据(状态)
        // 3.每一次请求完成页码要+1
        let arr = this.data.prolist //获取数据 
        let num = this.data.pageCode //获取页码
        let list = [...arr,...res.data.data] //处理数据
        num += 1
        this.setData({  //修改数据
          prolist: list,
          pageCode: num
        })
      }
    })
  }

四、返回顶部功能实现

<!-- 返回顶部按钮 -->
<!-- 绑定事件 -->
<!-- 小程序中有两种绑定事件的方法---移动端尽量不使用click事件,建议使用tap事件,或者用touch代替click事件 
  bindtap:
  catchtap:组织冒泡
-->
<button class="backtop" bindtap="backtop">返回顶部</button>

CSS 样式文件:

.backtop {
  position: fixed;
  bottom: 20px;
  right: 10px;
  border-radius: 5px;
  background-color: #f66;
}

pages/index/index.js

backtop: function () {
    // 小程序api 的界面 - 滚动
    wx.pageScrollTo({
        scrollTop: 0,
        duration: 300
    })
}

五、实现点击商品列表进入产品的详情页面

1.构建详情页面

"pages": [
  "pages/detail/detail"
],

2.声明式导航跳转

<!-- 首页商品列表点击进入详情页面vue和React
 1.声明式导航
   vue <router-Link></router-Link>
   React <Link></Link>  <NavLink></NavLink>
 2.编程式导航
   new Vue ({router ,store ,el:' ' })
   vue  this.$router.push()  replace()  go()  back()
   React this.props.history.push()
-->
<!-- 小程序中的点击进入详情页面
   1.声明式导航---标签跳转---<a></a>
   https://developers.weixin.qq.com/miniprogram/dev/component/navigator.html
   格式为:<navigator url=" " open-type=" " ></navigator>
   open-type:
     navigate:保留当前页面,新添加一个页面,不能添加tab页面--push
     redirect:替换当前页面,不能替换tab页面--replace
     switchTab:切换当前的tab页面--小程序特有
     navigateBack:返回--back,goBack
   2.编程式导航---JS跳转---window.location.href=""
   https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.switchTab.html
 -->

<!-- 声明式导航 -->
<view class="prolist">
  <!-- 因为每一个商品列表都有跳转功能,循环遍历时要用在navigator上面 -->
  <navigator url="/pages/detail/detail" wx:for="{{prolist}}" wx:key="item.proid">
    <view class="proitem">
      <view class="itemimg">
        <image class="img" src="{{item.proimg}}"></image>
      </view>
      <view class="iteminfo">
        <view class="title">{{item.proname}}</view>
        <view class="number">目前已售出{{item.sales}}件 / 剩余{{item.stock}}件</view>
        <view class="price">¥{{item.price}}</view>
      </view>
    </view>
  </navigator>
</view>

3.详情页面接收数据并且渲染数据

在小程序中 向目标页面传递参数 使用的是: /../..?+参数 ,例如:

url="{{'/pages/detail/detail?proid='+item.proid}}"

在目标页面的 onLoad 函数中的参数 options 就是传递过来的参数。 pages/detail/detail.js

import { request } from './../../utils/index.js'
Page({
...
  data: {
    proid: '', // 在商品加入购物车时必须要用到的proid
    proname: '',
    proimg: '',
    desc: '',
    price: 0
  },
  onLoad: function (options) {
    console.log(options)
    // 获取传递过来的参数值proid
    const { proid } = options
    // 请求产品详情的数据
    request({
      url:'/pro/detail?proid=' + proid
      // url:'/pro/detail?proid=${proid}'

    }).then(res => {
      console.log(res.data)
      // 解构赋值
      const { proid, proname, price, proimg, desc} = res.data.data
      // const { data:{proid, proname, price, proimg, desc}} = res.data
      // 修改状态
      this.setData({
        proid, proname, price, proimg, desc
      })
    })
  },
...
})

pages/detail/detail.wxml

<image src="{{proimg}}" style="width: 100px;height: 100px;"></image>
<view>{{proname}}</view>
<view>¥{{price}}</view>
<view>{{desc}}</view>

4.编程式导航渲染

使用小程序提供的api实现 :

wx.switchTab(Object object)

跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。

wx.reLaunch(Object object)

关闭所有页面,打开到应用内的某个页面。

wx.redirectTo(Object object)

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

wx.navigateTo(Object object)

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

wx.navigateBack(Object object)

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

小程序传递数据使用 data-params 形式,可以在事件中根据 event 获取该参数,用 bindtap 来绑定单击事件

<view class="prolist">
  <view class="proitem" bindtap="toDetail" data-proid="{{item.proid}}" wx:for="{{prolist}}" wx:key="item.proid">
    <view class="itemimg">
      <image class="img" src="{{item.proimg}}"></image>
    </view>
    <view class="iteminfo">
      <view class="title">{{item.proname}}</view>
      <view class="number">目前已售出{{item.sales}}件 / 剩余{{item.stock}}件</view>
      <view class="price">¥{{item.price}}</view>
    </view>
  </view>
</view>

components/prolist/prolist.js

Component({
...
  methods: {
    toDetail (event) {
      console.log('跳转到详情页面',event)
      // 获取到产品id
      const { proid } = event.currentTarget.dataset
      // 编程式导航
      // 如果跳转的是tab页面,可以使用switchTab 或者 reLuanch
      // 如果跳转的是非tab页面,可以使用 redirectTo 或者 navigateTo 或者 reLuanch
      //1.navigateTo
      wx.navigateTo({
        url: '/pages/detail/detail?proid=' + proid
        // url: '/pages/detail/detail?proid=${proid}'   这种写法无法解析
      })
      //2.redirectTo  页面的左上角没有了返回按钮
      // wx.redirectTo({
      //   url: '/pages/detail/detail?proid=' + proid
      // })
      //3.reLuanch
      // wx.reLaunch({
      //   url: '/pages/detail/detail?proid=' + proid
      // })
    }
  }
})

关于 getCurrentPages 的用法:

detail.js

onShow: function () {
console.log(getCurrentPages())
// console.log(getCurrentPages()[getCurrentPages().length-1])  输出当前页面(即当前自己页面)
// console.log(getCurrentPages()[getCurrentPages().length-2])  输出首页(即上一个页面)
// console.log(getCurrentPages()[getCurrentPages().length-3])  undefined,因为数组中只有两个元素
},

length-1 对应的就是当前页面, length-2 就是(页面栈)上一个页面,以此类推。

如果详情页面的 数据量处理特别多 ,可以将获取数据 抽离出来,封装成方法

request({
    url:'/pro/detail?proid=' + proid
    // url:'/pro/detail?proid=${proid}'  这种写法无法解析
}).then(res => {this.getDetailData(res,proid)})
...
// 将then之后获取数据成功后的方法进行封装
getDetailData (res,proid) {
    console.log(res.data)
    // 解构赋值
    // 此处proid不需要从接口中获取自己内部已经有了
    const { proname, price, proimg, desc} = res.data.data
    // const { data:{proid, proname, price, proimg, desc}} = res.data
    // 修改状态
    this.setData({
        proid, proname, price, proimg, desc
    })
},

六.使用第三方组件库

1.WeUI

WeUI 是微信官方出品的组件库,它沿用了微信的视觉设计与交互设计,提供了各类原生组件的基础样式,风格简约大方。选用这一套组件库,可以让你的小程序与微信本身保持一致的界面风格。

2.iViewUI

iViewUI 是由TalkingData发布的组件库。

3.Vant Weapp

Vant 是由有赞发布的,轻量的小程序 UI 组件库。如果你想制作一款电商、餐饮、外卖平台、票务预订等购物类小程序,选用 Vant 是较为合适的。Vant Weapp里边的组件是 基于小程序自定义组件 开发的。

1.安装

,如果后面出现 无法构建 的情况,安装之前可以使用一下:

npm init
npm i @vant/weapp -S --production
2.构建npm包

打开微信开发者工具,点击 工具 -> 构建 npm ,并勾选 使用 npm 模块 选项,构建完成后,即可引入组件。

https://i-blog.csdnimg.cn/blog_migrate/d31f850c7d1aab88b08f8376e4abad05.png

3.使用组件

在使用之前将 app.json 中的 "style": "v2" 去除,小程序的 强行加上了许多样式,难以去除,不关闭将造成部分组件样式混乱。

首先在全局配置文件 app.json 或者页面配置文件 index.json 中引入:

"usingComponents": {
  "van-goods-action": "@vant/weapp/goods-action/index",
  "van-goods-action-icon": "@vant/weapp/goods-action-icon/index",
  "van-goods-action-button": "@vant/weapp/goods-action-button/index"
}

接着在 detail.wxml 中添加:

<van-goods-action>
  <van-goods-action-icon icon="chat-o" text="客服" />
  <van-goods-action-icon icon="cart-o" text="购物车" />
  <van-goods-action-button
    text="加入购物车"
    type="warning"
  />
  <van-goods-action-button text="立即购买" />
</van-goods-action>

如果出现 json: ["usingComponents"]["van-goods-action"] 未找到,再次点击 工具 -> 构建 npm 即可。如果最终的实现效果和文档中的不一致,那么或许是 详情–本地设置–调式基础库 的原因。

"usingComponents": {
  "van-goods-action": "@vant/weapp/goods-action/index",
  "van-goods-action-icon": "@vant/weapp/goods-action-icon/index",
  "van-goods-action-button": "@vant/weapp/goods-action-button/index"
}

接着在 detail.wxml 中添加:

<van-goods-action>
  <van-goods-action-icon icon="chat-o" text="客服" />
  <van-goods-action-icon icon="cart-o" text="购物车" />
  <van-goods-action-button
    text="加入购物车"
    type="warning"
  />
  <van-goods-action-button text="立即购买" />
</van-goods-action>

如果出现 json: ["usingComponents"]["van-goods-action"] 未找到,再次点击 工具 -> 构建 npm 即可。如果最终的实现效果和文档中的不一致,那么或许是 详情–本地设置–调式基础库 的原因。