小程序100-125

一、通用模块封装

1.为什么要进行模块封装

(1)减少代码的冗余,让代码号维护

(2)为后续的网络请求模块封装做铺垫

2.消息提示模块封装

javascript 复制代码
// app.js

// import { toast } from './utils/extendApi'
import './utils/extendApi'

App({

  onShow () {
    // wx.showToast({
    //   title: '消息提示框', // 提示的内容
    //   icon: 'success',   // 提示的图标,success(成功)、error(失败)、loading(加载)、none(不显示图标)
    //   duration: 2000,	 // 提示的延迟时间
    //   mask: true		 // 是否显示透明蒙层,防止触摸穿透
    // })    

    // 可以不传入参数
    // toast()
    // wx.toast()

    // 可以传入参数,传入的参数会覆盖默认的参数
    // toast({ title: '数据加载完毕', icon: 'success' })
    wx.toast({ title: '数据加载完毕', icon: 'success' })
  }

})











// extendApi.js

// 在使用 toast 方法时,可以传入参数,也可以不传入参数
// 如果需要传入参数,要传入对象作为参数
// const toast = (options = {}) => {}

// 如果用户传入了对象作为参数
// 在形参位置通过解构的方式获取用户传入的参数,同时设置为默认值
const toast = ({ title = '数据加载中...', icon = 'none', duration = 2000, mask = true } = {}) => {

  wx.showToast({
    title,
    icon,
    duration,
    mask
  })
}

// 如果有很多 .js 文件,都需要调用 toast 方法
// 每次使用都需要导入 toast,然后进行调用,太麻烦
// 可以将 toast 方法挂载到 wx 全局对象身上
// 如果想挂载到 wx 全局对象上这种写法生效,需要让当前文件执行一次
wx.toast = toast

// 如果其他 .js文件,需要使用 toast 方法
// 需要先导入 toast ,然后进行调用才可以
export { toast }

3.模块对话框封装

4.网络请求封装

javascript 复制代码
// storage.js

/**
 * @description 存储数据
 * @param {*} key 本地缓存中指定的 key
 * @param {*} value 需要缓存的数据
 */
export const setStorage = (key, value) => {
  try {
    wx.setStorageSync(key, value)
  } catch (error) {
    console.error(`存储指定 ${key}数据发生了异常`)
  }
}

/**
 * @description 从本地读取指定 key 的数据
 * @param {*} key 
 */
export const getStorage = (key) => {
  try {
    const value = wx.getStorageSync(key)

    if (value) {
      return value
    }

  } catch (error) {
    console.error(`读取指定 ${key} 数据发生了异常`, error)
  }
}

/**
 * @description 从本地移除指定 key 的数据
 * @param {*} key 
 */
export const removeStorage = (key) => {
  try {
    wx.removeStorageSync(key)
  } catch (error) {
    console.error(`移除指定 ${key} 数据发生了异常`, error)
  }
}

/**
 * @description 从本地移除、清空全部的数据
 */
export const clearStorage = () => {
  try {
    wx.clearStorageSync()
  } catch (error) {
    console.error(`清除、清空数据发生了异常`, error)
  }
}

/**
 * @description 异步将数据存储到本地
 * @param {*} key 本地缓存中指定的 key
 * @param {*} data 需要缓存的数据
 */ 
export const asyncSetStorage = (key, data) => {
  return new Promise((resolve) => {
    wx.setStorage({
      key,
      data,
      complete (res) {
        resolve(res)
      }
    })
  })
}

/**
 * @description 异步从本地获取指定 key 的数据
 * @param {*} key 
 */
export const asyncGetStorage = (key) => {
  return new Promise((resolve) => {
    wx.getStorage({
      key,
      complete (res) {
        resolve(res)
      }
    })
  })
}

/**
 * @description 异步从本地移除指定 key 的数据
 * @param {*} key 
 */
export const asyncRemoveStorage = (key) => {
  return new Promise((resolve) => {
    wx.removeStorage({
      key,
      complete (res) {
        resolve(res)
      }
    })
  })
}

/**
 * @description 异步从本地清除、移除全部缓存的数据
*/
export const asyncClearStorage = () => {
  return new Promise((resolve) => {
    wx.clearStorage({
      complete (res) {
        resolve(res)
      }
    })
  })
}




// app.js

// import { toast } from './utils/extendApi'
import './utils/extendApi'

// import { setStorage, getStorage, removeStorage, clearStorage } from './utils/storage'
import { asyncSetStorage, asyncGetStorage, asyncRemoveStorage, asyncClearStorage } from './utils/storage'

App({
  async onShow () {
    // setStorage('name', 'tom')
    // setStorage('age', 10)

    // // const name = getStorage('name')
    // // console.log(name)

    // // removeStorage('name')

    // clearStorage()


    // asyncSetStorage('name', 'Jerry').then(res => {
    //   console.log(res)
    // })
    // asyncSetStorage(age, 100).then(res => {
    //   console.log(res)
    // })

    // asyncGetStorage('name').then ((res) => {
    //   console.log(res.data)
    // })

    // asyncRemoveStorage('name').then(res => {
    //   console.log(res)
    // })

    // asyncClearStorage().then((res) => {
    //   console.log(res)
    // })
  }
})

二、网络请求封装

1.为什么要封装 wx.request

2.request 实例方法

javascript 复制代码
// request.js

// 创建 WxRequest 类
// 通过类的方式来进行封装,会让代码更加具有复用性
// 也可以方便添加新的属性和方法

class WxRequest {
  // 用于创建和初始化类的属性以及方法
  constructor () {}

  // request 实例方法接收一个对象类型的参数
  // 属性值和 wx.request 方法调用时传递的参数保持一致
  request (options) {
    // 需要使用 Promise 封装 wx.request, 处理异步请求
    return new Promise((resolve, reject) => {
      wx.request({
        ...options,

        // 当接口调用成功时,会触发 success 回调函数
        success: (res) => {
          resolve(res)
        },

        // 当接口调用失败时,会触发 fail 回调函数
        fail: (err) => {
          reject(err)
        }
      })
    })
  }
}

// ..................... 以下为实例化的代码 .....................
// 目前写到同一个文件中,是为了方便测试,以后会提取成多个文件

// 对 WxRequest 进行实例化
const instance = new WxRequest()

// 将 WxRequest 实例进行暴露出去,方便再其他文件中进行使用
export default instance





// pages/test/test.js
import instance from '../../utils/request'

Page({

  async handler () {
    // 第一种调用方式, .then 的方式进行调用
    // instance.request({
    //   url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
    //   method: 'GET'
    // }).then(res => {
    //   console.log(res)
    // })

    // 第二种调用方式,通过 await 和 async 的方式进行调用
     const res = await instance.request({
      url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
      method: 'GET'
    })

    console.log(res)
  }

})
html 复制代码
<!--pages/test/test.wxml-->
<!-- <text>pages/test/test.wxml</text> -->

<view class="box">
  <button type="warn" plain size="mini" bind:tap="handler">测试发送请求</button>
</view>
css 复制代码
/* pages/test/test.wxss */

.box {
  display: flex;
  height: 200rpx;
  justify-content: center;
  align-items: center;
}

3.设置请求参数

javascript 复制代码
// request.js

// 创建 WxRequest 类
// 通过类的方式来进行封装,会让代码更加具有复用性
// 也可以方便添加新的属性和方法

class WxRequest {

  // 定义实例属性,用来设置默认请求参数
  defaults = {
    baseURL: '', // 请求基准地址
    url: '', // 接口的请求路径
    data: null, // 请求参数
    method: 'GET', // 默认的请求方法
    // 请求头
    header: {
      "Content-type": "application/json" // 设置数据的交互格式
    },
    timeout: 60000 // 默认的超时时长,小程序默认的超时时长是 1 分钟
  }

  // 用于创建和初始化类的属性以及方法
  // 在实例化时传入的参数,会被 constructor 形参进行接收
  constructor (params = {}) {
    // 通过 Object.assign 方法合并请求参数
    // 注意:需要传入的参数,覆盖默认的参数,因此传入的参数需要放到最后
    this.defaults = Object.assign({}, this.defaults, params)
  }

  // request 实例方法接收一个对象类型的参数
  // 属性值和 wx.request 方法调用时传递的参数保持一致
  request (options) {

    // 注意:需要先合并完整的请求地址 (baseURL +url)
    // https://gmall-prod.atguigu.cn/mall-api/index/findBanner
    options.url = this.defaults.baseURL + options.url

    // 合并请求参数
    options = { ...this.defaults, ...options }

    // 需要使用 Promise 封装 wx.request, 处理异步请求
    return new Promise((resolve, reject) => {
      wx.request({
        ...options,

        // 当接口调用成功时,会触发 success 回调函数
        success: (res) => {
          resolve(res)
        },

        // 当接口调用失败时,会触发 fail 回调函数
        fail: (err) => {
          reject(err)
        }
      })
    })
  }
}

// ..................... 以下为实例化的代码 .....................
// 目前写到同一个文件中,是为了方便测试,以后会提取成多个文件

// 对 WxRequest 进行实例化
const instance = new WxRequest({
  baseURL: 'https://gmall-prod.atguigu.cn/mall-api',
  timeout: 15000
})

// 将 WxRequest 实例进行暴露出去,方便再其他文件中进行使用
export default instance






// pages/test/test.js
import instance from '../../utils/request'

Page({

  async handler () {
    // 第一种调用方式, .then 的方式进行调用
    // instance.request({
    //   url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
    //   method: 'GET'
    // }).then(res => {
    //   console.log(res)
    // })

    // 第二种调用方式,通过 await 和 async 的方式进行调用
     const res = await instance.request({
      url: '/index/findBanner',
      method: 'GET'
    })

    console.log(res)
  }

4.封装请求快捷方法

javascript 复制代码
  // 封装 GET 实例方法
  get (url, data = {}, config = {}) {
    // 需要调用 request 请求方法发送请求,只需要组织好参数,传递给 request 请求方法即可
    // 当调用 get 方法时,需要将 request 方法的返回值 return 出去
    return this.request(Object.assign({ url, data, method: 'GET' }, config))
  }

  // 封装 DELETE 实例方法
  delete (url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
  }

  // 封装 POST 实例方法
  post (url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'POST' }, config))
  }

  // 封装 PUT 实例方法
  put (url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'PUT' }, config))
  }

5.wx.request 注意事项

javascript 复制代码
wx.request({
      url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
      method: 'GET',
      timeout: 100,
      success: (res) => {
        // 在使用 wx.request 发送请求时
        // 只要成功接收到服务器返回的结果
        // 无论 statusCode、状态码是多少,都会执行 success
        // 开发者就需要根据业务逻辑,自己来进行相关的判断处理
        console.log('虽然接口错了,但是我依然会走 success')
        console.log(res)
      },
      fail: (err) => {
        // 一般在网络出现异常时(网络超时),就会执行 fail
        console.log('网络超时了,这时候网络出现异常,就会执行 fail')
        console.log(err)
      }
    })

6.定义请求-响应拦截器

javascript 复制代码
  // 定义拦截器对象
  // 需要包含请求拦截器以及响应拦截器,方便再请求之前以及响应以后时进行逻辑处理
  interceptors = {
    // 请求拦截器
    // 在请求发送之前,对请求参数进行新增或者是修改
    request: (config) => config,

    // 响应拦截器
    // 在服务器响应数据以后,对服务器响应的数据进行逻辑处理
    response: (response) => response
  }


 request (options) {

    // 注意:需要先合并完整的请求地址 (baseURL +url)
    // https://gmall-prod.atguigu.cn/mall-api/index/findBanner
    options.url = this.defaults.baseURL + options.url

    // 合并请求参数
    options = { ...this.defaults, ...options }

    // 在请求发送之前,调用请求拦截器,新增和修改请求参数
    options = this.interceptors.request(options)

    // console.log(options)

    // 需要使用 Promise 封装 wx.request, 处理异步请求
    return new Promise((resolve, reject) => {
      wx.request({
        ...options,

        // 当接口调用成功时,会触发 success 回调函数
        success: (res) => {
          // 不管是成功响应还是失败响应,都需要调用响应拦截器
          // 响应拦截器需要接收服务器响应的数据,然后对数据进行逻辑处理,处理好以后进行返回
          // 然后再通过 resolve 将返回的数据抛出去

          // 在给响应拦截器传递参数时,需要将请求参数也一起传递
          // 方便进行代码的调试或者进行其他逻辑处理,需要先合并参数
          // 然后将合并的参数传递给响应拦截器

          const mergeRes = Object.assign({}, res, { config: options })
          resolve(this.interceptors.response(mergeRes))
        },

        // 当接口调用失败时,会触发 fail 回调函数
        fail: (err) => {
          // 不管是成功响应还是失败响应,都需要调用响应拦截器
          const mergeErr = Object.assign({}, err, { config: options })
          reject(this.interceptors.response(mergeErr))
        }
      })
    })
  }


// ..................... 以下为实例化的代码 .....................
// 目前写到同一个文件中,是为了方便测试,以后会提取成多个文件

// 配置请求拦截器
instance.interceptors.request = (config) => {
  // 在请求发送之前做点什么......
  return config
}

7.完善请求-响应拦截器

javascript 复制代码
class WxRequest {
    
  // coding....
    
   request(options) {
    // coding....

    // 使用 Promise 封装异步请求
    return new Promise((resolve, reject) => {
      // 使用 wx.request 发起请求
      wx.request({
        ...options,

        // 接口调用成功的回调函数
        success: (res) => {
          // 响应成功以后触发响应拦截器
          if (this.interceptors.response) {
             // 调用响应拦截器方法,获取到响应拦截器内部返回数据
             // success: true 表示服务器成功响应了结果,我们需要对业务状态码进行判断
             res = this.interceptors.response({ response: res, isSuccess: true })
          }

          // 将数据通过 resolve 进行返回即可
          resolve(res)
        },

        // 接口调用失败的回调函数
        fail: (err) => {
          // 响应失败以后也要执行响应拦截器
          if (this.interceptors.response) {
             // isSuccess: false 表示是网络超时或其他问题
             err = this.interceptors.response({ response: err, isSuccess: true })
          }

          // 当请求失败以后,通过 reject 返回错误原因
          reject(err)
        }
          
      })
    })
  }
    
  // coding......
}


// -----------------------------------------------------


// 对 WxRequest 进行实例化
const instance = new WxRequest({
  baseURL: 'https://gmall-prod.atguigu.cn/mall-api'
})

// 设置请求拦截器
instance.setRequestInterceptor((config) => {
  console.log('执行请求拦截器')

  return config
})

// 设置响应拦截器
 instance.setResponseInterceptor((response) => {
  const { response: res, isSuccess } = response

   // isSuccess: false 表示是网络超时或其他问题,提示 网络异常,同时将返回即可
   if (!isSuccess) {
     wx.toast('网络异常,请稍后重试~')
    // 如果请求错误,将错误的结果返回出去
     return res
   }

  // 简化数据
 return response.data
})

// 将 WxRequest 的实例通过模块化的方式暴露出去
export default instance

8.使用请求-响应拦截器

javascript 复制代码
// 判断服务器响应的业务状态码
  switch (data.code) {
    // 如果后端返回的业务状态码 = 200,说明请求成功,服务器成功响应了数据
    case 200:
        // 对服务器响应数据做点什么......
        return data
    // 如果返回的业务状态码 = 208,说明 没有 token,或者 token 失效
    // 就需要让用户登录或者重新登录
    case 208:
      const res = await modal({
        content: '鉴权失败,请重新登录',
        showCancel: false // 不显示取消按钮
      })
  
      if (res) {
        // 清除之前失效的 token,同时要清除本地存储的全部信息
        clearStorage()

        wx.navigateTo({
          url: '/pages/login/login'
        })
      }

      return Promise.reject(response)

    default:
      toast({
        title: '程序出现异常,请联系客服或稍后重试'
      })

      return Promise.reject(response)
  }

9.添加并发请求

javascript 复制代码
// test.js

// 测试并发请求
  async allHandler () {
    // 演示通过 async 和 await 方式同时发起多个请求
    // async 和 await 能够控制异步任务以同步的流程来执行

    // async 和 await 方式发起多个请求
    // 当第一个请求结束以后,才能够发起第二个请求
    // 在前一个请求结束以后,才能发起下一个请求
    // 会造成请求的阻塞,从而影响页面的渲染速度
    // await instance.get('/index/findBanner')
    // await instance.get('/index/findCategory1')
    // await instance.get('/index/findBanner')
    // await instance.get('/index/findCategory1')

    // 演示通过 Promise.all 同时发起多个请求
    // Promise.all 能够将多个请求同时进行发送
    // Promise.all 能够将多个异步请求同时进行发送,也就是并行发送
    // 并不会造成请求的阻塞,从而不会影响页面的渲染速度
    // await Promise.all([instance.get('/index/findBanner'), instance.get('/index/findCategory1'),instance.get('/index/findBanner'), instance.get('/index/findCategory1')])

    const res = await instance.all(instance.get('/index/findBanner'), instance.get('/index/findCategory1'),instance.get('/index/findBanner'), instance.get('/index/findCategory1'))

    console.log(res)
  }




// request.js

class WxRequest {
 // 用来处理并发请求
  all (...promise) {
    console.log(promise)
    // 通过展开运算符来接收传递的参数
    // 那么展开运算符会将传入的参数转成数组
    return Promise.all(promise)
  }
}

10.添加 loading

javascript 复制代码
// request.js

    // 在请求发送之前,添加 loading 效果
    wx.showLoading()



return new Promise((resolve, reject) => {
      wx.request({
        ...options,


        // 接口调用结束的回调函数(调用成功、失败都会执行)
        complete: () => {
          // 不管请求是成功还是失败,都需要隐藏 loading
          wx.hideLoading()
        }
      })
    })

11.完善 loading

javascript 复制代码
  // 定义数组队列
  // 初始值需要是一个空数组,用来存储请求队列、存储请求标识
  queue = []



  request (options) {
    // 如果有新的请求,就清除上一次的定时器
    this.timerId && clearTimeout(this.timerId)


    // 判断 queue 队列是否为空,如果是空,就显示 loading 
    // 如果不是空,就不显示 loading,不调用 wx.showLoading()
    this.queue.length === 0 && wx.showLoading()

    // 然后立即向 queue 数组队列中添加请求标识
    // 每个标识代表是一个请求,标识是自定义的
    this.queue.push('request')
    return new Promise((resolve, reject) => {
      wx.request({
        // 接口调用结束的回调函数(调用成功、失败都会执行)
        complete: () => {

          // 在每一个请求结束以后,都会执行 complete 回调函数
          // 每次都从 queue 队列中删除一个标识
          this.queue.pop()

          this.queue.length === 0 && this.queue.push('request')

          this.timerId = setTimeout(() => {
            this.queue.pop()

            // 在删除标识以后,需要判断目前 queue 数组是否为空
            // 如果是空,说明并发请求完成了
            // 就需要隐藏 loading,要调用 wx.hideLoading()
            this.queue.length === 0 && wx.hideLoading()

            clearTimeout(this.timerId)
          }, 1)

          // 不管请求是成功还是失败,都需要隐藏 loading
          // wx.hideLoading()
        }
      })
}

12.控制 loading 显示

javascript 复制代码
class WxRequest {

  // 定义实例属性,用来设置默认请求参数
  defaults = {
    isLoading: true // 控制是否使用默认的 loading ,默认值是 true 标识使用默认的 loading
  }

13.封装 uploadFile

javascript 复制代码
  /**
   * @description upload 实例方法,用来对 wx.uploadFile 进行封装
   * @param {*} url 文件的上传地址、接口地址
   * @param {*} filePath 要上传的文件资源路径
   * @param {*} name 文件对应的 key
   * @param {*} config 其他配置项
   */
  upload (url, filePath, name = 'file', config = {}) {
    return this.request(
      Object.assign({url, filePath, name, method: 'UPLOAD'}, config)
    )
  }

14.使用npm包发送请求

参考文档:

javascript 复制代码
// npm方法
// 导入模块、包提供的类
import WxRequest from 'mina-request'
// 导入封装的本地存储操作模块
import { getStorage, clearStorage } from './storage'
// 导入封装的增强 API
import { toast, modal } from './extendApi'

// 对类进行实例化
const instance = new WxRequest({
  baseURL: 'https://gmall-prod.atguigu.cn/mall-api',
  timeout: 15000
})

// 添加请求拦截器(在请求发送之前对请求参数进行新增或者修改)
instance.interceptors.request = (config) => {

  // 在实际开发中,有一些接口需要使用访问令牌 token
  // 访问令牌 token 通常是存储到本地
  // 需要先从本地获取到存储的 token
  const token = getStorage('token')

  // 如果本地存在 token,这时候就需要在请求头中添加 token 字段
  if (token) {
    config.header['token'] = token
  }

  // 在发送请求之前做些什么
  return config
}

// 添加响应拦截器(在服务器响应数据以后,对返回的数据进行逻辑处理)
instance.interceptors.response = async (response) => {

  // 从 response 对象中解构两个数据
  const { isSuccess, data } = response

  // response 服务器响应的数据,只不过数据被 wx.request 进行了一层包装
  // console.log(response)

  // response.config 封装的包里面提供的 config 属性,是请求的参数信息
  // 可以使用请求参数进行代码调试

  // response.data 服务器真正响应的数据

  // response.isSuccess 是用来判断代码执行了哪一个回调函数
  // isSuccess = true,说明了代码执行了 wx.request 方法的 success 回调函数
  // isSuccess = false,说明了代码执行了 wx.request 方法的 fail 回调函数

  // 如果 isSuccess = false ,说明网络出现了问题
  if (!isSuccess) {
    toast({
      title: '网络异常请重试',
      icon: 'error'
    })

    return Promise.reject(response)
  }

  // 如果 isSuccess = true,说明代码执行到了 success 回调函数
  // 需要开发者对返回的参数进行逻辑判断
  // 需要对后端返回的业务状态码进行判断
  // 业务状态码 === 200,接口调用成功,服务器成功返回了数据
  // 业务状态码 === 208,没有 token 或者 token 失效,需要让用户重新进行登录
  // 如果业务状态码既不等于 200,也不等于 208,说明出现了其他异常,需要给用户统一进行其他提示
  switch (data.code) {
    case 200:
      // 接口调用成功,服务器成功返回了数据,只需要将数据简化以后返回即可
      return data
  
    case 208:
      const res = await modal({
        content: '鉴权失败,请重新登录',
        showCancel: false
      })

      if (res) {
        // 既然用户需要重新进行登录,就需要吧之前用户存储的信息(过期的 token) 进行清除
        clearStorage()

        wx.navigateTo({
          url: '/pages/login/login'
        })
      }

      return Promise.reject(response)
  
    default:
      toast({
        title: '程序出现异常,请联系客服或者稍后重试!'
      })
      return Promise.reject(response)
  }

  // return response
}

// 导出实例
export default instance

15.环境变量-小程序设置环境变量

javascript 复制代码
// 就是用来配置当前小程序项目的环境变量

// 获取当前小程序的账号信息
const { miniProgram } = wx.getAccountInfoSync()

// 获取小程序的版本
const { envVersion } = miniProgram

let env = {
  baseURL: 'https://gmall-prod.atguigu.cn/mall-api'
}

switch (env) {
  // 开发版
  case 'develop':
    env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
    break

  // 体验版
  case 'trial':
    env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
    break

  // 正式版
  case 'release':
    env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
    break

  default:
    env.baseURL = 'https://gmall-prod.atguigu.cn/mall-api'
    break
}

export { env }

16.接口调用方式说明

javascript 复制代码
/**
 * @description 用来获取首页轮播图数据
 */
export const reqSwiperData = () => http.get('/index/findBanner')


// export const reqSwiperData = () => {
//   return http.get('/index/findBanner')
// }

三、项目首页

1.获取首页数据

javascript 复制代码
//index.js/api

// 导入封装的 网络请求模块实例
import http from '../utils/http'

export const reqIndexData = () => {
  // 通过并发请求获取首页的数据,来提升页面的渲染速度
  // 通过 Promise.all 进行并发请求
  // return Promise.all([
  //   http.get('/index/findBanner'),
  //   http.get('/index/findCategory1'),
  //   http.get('/index/advertisement'),
  //   http.get('/index/findListGoods'),
  //   http.get('/index/findRecommendGoods')
  // ])

  // 是使用封装的 all 方法发送请求
  // 这两种方式都可以
  return http.all(
    http.get('/index/findBanner'),
    http.get('/index/findCategory1'),
    http.get('/index/advertisement'),
    http.get('/index/findListGoods'),
    http.get('/index/findRecommendGoods')
  )
}




// index.js/index

import { reqIndexData } from '../../api/index'

Page({
  
  // 初始化数据
  data: {
    bannerList: [], // 轮播图数据
    categoryList: [], // 商品导航数据
    activeList: [], // 活动宣传区域
    hotList: [], // 人气推荐
    guessList: [] // 猜你喜欢
  },

  // 获取首页数据
  async getIndexData () {
    // 调用接口 API 函数,获取数据
    // reqIndexData 内部使用的是 all 或者 Promise.all
    // 返回的是一个数组,是按照接口调用顺序返回的
    const res = await reqIndexData()

    // 需要对数据进行赋值,在赋值的时候,一定要注意索引
    this.setData({
      bannerList: res[0].data,
      categoryList: res[1].data,
      activeList: res[2].data,
      guessList: res[3].data,
      hotList: res[4].data
    })
  },

  // 监听页面的加载
  onLoad () {
    // 在页面加载以后,调用获取首页数据的方法
    this.getIndexData()
  }
})

2.分析轮播图区域并渲染

html 复制代码
<!-- index.wxml -->

<!-- 轮播图区域 -->
    <banner bannerList="{{ bannerList }}" />


<!-- banner.wxml -->

        <!-- 通过 navigator 组件来实现页面的跳转 -->
        <navigator
          class="navigator"
          url="/pages/goods/detail/detail?goodsId={{ item.id }}"
        >
          <image class="img" src="{{ item.imageUrl }}"></image>
        </navigator>

3.实现轮播图和指示点的联动

javascript 复制代码
// pages/index/banner/banner.js

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    // 轮播图数据
    bannerList: {
      type: Array,
      value: []
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
     activeIndex: 0 // 被激活的轮播图索引,默认是 0
  },

  /**
   * 组件的方法列表
   */
  methods: {
     // 获取被激活的轮播图索引
     getSwiperIndex(event) {
       // console.log(event)
       const { current } = event.detail

       this.setData({
         activeIndex: current
       })
     }
  }
})
html 复制代码
<!-- 轮播图 -->
<view class="swiper-box">
  <!-- swiper 滑块视图容器,用来绘制轮播图 -->
  <swiper
    autoplay
    class="swiper"
    indicator-active-color="#FF734C"
    interval="2000"
    duration="1000"
    indicator-color="rgba(0, 0, 0, .3)"
     bindchange="getSwiperIndex"
  >
    <!-- 通过 block 标签对 轮播图数据 进行渲染 -->
    <block wx:for="{{ bannerList }}" wx:key="index">

      <!-- coding... -->

    </block>
  </swiper>

  <!-- 轮播图的面板指示点,因为面板指示点不支持自定义,所以我们只能通过自定义结构的方式 -->
  <view class="indicator">
    <!-- active 类名:当前被激活的面板指示点颜色 -->
    <!-- rectangle 类名:默认的面板指示点颜色 -->
    <text
      wx:for="{{bannerList.length}}"
      wx:key="id"
       class="{{  index === activeIndex ? 'active rectangle' : 'rectangle' }}"
    ></text>
  </view>
</view>

4.分析商品导航区域并渲染

5.分析猜你喜欢+人气推荐并渲染

6.首页骨架屏组件

1.点击右下角三个点(...)生成骨架屏

2.再pages/index里创建一个新文件夹skeleton把生成骨架屏的两个文件放进去

相关推荐
weixin_446729165 小时前
注解和反射
java·开发语言
এ慕ོ冬℘゜6 小时前
JS 前端基础高频面试题
开发语言·前端·javascript
凯瑟琳.奥古斯特6 小时前
常见加密算法及应用
java·开发语言·网络·网络协议·职场和发展
Dxy12393102166 小时前
JS列表获取指定范围值的 N 种方法
开发语言·javascript·ecmascript
froginwe116 小时前
Memcached CAS 命令详解
开发语言
c++逐梦人6 小时前
epoll ET服务器(Reactor模式)
运维·服务器·php
春栀怡铃声6 小时前
【C++修仙录02】筑基篇:vector 使用
开发语言·c++·算法
彦为君6 小时前
JavaSE-11-ByteBuffer(NIO核心组件)
java·开发语言·前端·数据库·后端·spring·nio
茉莉玫瑰花茶6 小时前
LangGraph 持久化(Persistence)[ 2 ]
开发语言·python·ai·langgraph