微信小程序学习笔记(6) -- 本地生活项目

简介: 微信小程序学习笔记(6) -- 本地生活项目

本地生活项目



项目效果图


1dc618a0ed9580ce8bfa6facb208c08f.png

5d4c6812c8535adbb050f4ddf2e1bce8.png

46a9d80a6e05e4e3b19d57a0ee70bcdf.png

66ba272a0bfc97be54a5fa679e3d5482.png

88b9988b40447cb37c7e3c492d49867f.png

80308c27701d3aead18db6c7b167f308.png


外观和标签栏的配置



window


用于设置小程序的状态栏、导航条、标题、窗口背景色。

image.png


tabBar


如果小程序是一个多 tab 应用(客户端窗口的底部或顶部有 tab 栏可以切换页面),可以通过 tabBar 配置项指定 tab 栏的表现,以及 tab 切换时显示的对应页面。

image.png

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

image.png


目标


建3个tab的tabBar


1dc618a0ed9580ce8bfa6facb208c08f.png

5d4c6812c8535adbb050f4ddf2e1bce8.png46a9d80a6e05e4e3b19d57a0ee70bcdf.png


具体代码:


核心代码:


app.json

{
  "pages":[
    "pages/index/index",
    "pages/message/message",
    "pages/profile/profile"
  ],
  "window":{
    "navigationBarBackgroundColor": "#3a4891",
    "navigationBarTextStyle":"white",
    "navigationBarTitleText": "本地生活",
    "backgroundColor": "#bcc0c9",
    "backgroundTextStyle":"light",
    "enablePullDownRefresh": false
  },
  "tabBar":{
    "list":[
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "assets/home.png",
        "selectedIconPath":"assets/home-active.png"
      },
      {
        "pagePath": "pages/message/message",
        "text": "消息",
        "iconPath": "assets/message.png",
        "selectedIconPath":"assets/message-active.png"
      },
      {
        "pagePath": "pages/profile/profile",
        "text": "我的",
        "iconPath": "assets/profile.png",
        "selectedIconPath":"assets/profile-active.png"
      }
    ]
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json"
}


<!--index.wxml-->
<view class="container">
  首页
</view>


<!--pages/message/message.wxml-->
<text>pages/message/message.wxml</text>


<!--pages/profile/profile.wxml-->
<text>pages/profile/profile.wxml</text>


公共样式


设置tabBar的样式:


1dc618a0ed9580ce8bfa6facb208c08f.png

5d4c6812c8535adbb050f4ddf2e1bce8.png

app.json全部代码


{
  "pages":[
    "pages/index/index",
    "pages/message/message",
    "pages/profile/profile"
  ],
  "window":{
    "navigationBarBackgroundColor": "#3a4891",
    "navigationBarTextStyle":"white",
    "navigationBarTitleText": "本地生活",
    "backgroundColor": "#bcc0c9",
    "backgroundTextStyle":"light",
    "enablePullDownRefresh": false
  },
  "tabBar":{
     "color": "#999",
     "selectedColor": "#444",
     "backgroundColor": "#fff",
     "borderStyle": "black",
    "list":[
      {
        "pagePath": "pages/index/index",
        "text": "首页",
        "iconPath": "assets/home.png",
        "selectedIconPath":"assets/home-active.png"
      },
      {
        "pagePath": "pages/message/message",
        "text": "消息",
        "iconPath": "assets/message.png",
        "selectedIconPath":"assets/message-active.png"
      },
      {
        "pagePath": "pages/profile/profile",
        "text": "我的",
        "iconPath": "assets/profile.png",
        "selectedIconPath":"assets/profile-active.png"
      }
    ]
  },
  "style": "v2",
  "sitemapLocation": "sitemap.json"
}


首页布局


知识点


image


基础库 1.0.0 开始支持,低版本需做兼容处理。

image.png

mode 的合法值

image.png


目标


1dc618a0ed9580ce8bfa6facb208c08f.png

代码

<!--index.wxml-->
<swiper class="slides">
  <swiper-item>
      <image src="/assets/banner/banner-01.png" mode="aspectFill"></image>
  </swiper-item>
    <swiper-item>
      <image src="/assets/banner/banner-02.png" mode="aspectFill"></image>
  </swiper-item>
</swiper>
<view class="grids">
   <view class="item">
      <image src="/assets/grid/grid-01.png" />
      <text>美食</text>
   </view>
   <view class="item">
      <image src="/assets/grid/grid-02.png" />
      <text>美食</text>
   </view>
   <view class="item">
      <image src="/assets/grid/grid-03.png" />
      <text>美食</text>
   </view>
   <view class="item">
       <image src="/assets/grid/grid-04.png" />
      <text>美食</text>
   </view>
   <view class="item">
       <image src="/assets/grid/grid-05.png" />
      <text>美食</text>
   </view>
   <view class="item">
       <image src="/assets/grid/grid-06.png" />
      <text>美食</text>
   </view>
   <view class="item">
      <image src="/assets/grid/grid-07.png" />
      <text>美食</text>
   </view>
   <view class="item">
       <image src="/assets/grid/grid-08.png" />
      <text>美食</text>
   </view>
   <view class="item">
       <image src="/assets/grid/grid-09.png" />
      <text>美食</text>
   </view>
</view>
<view class="links">
   <image src="/assets/link-01.png"></image>
   <image src="/assets/link-02.png"></image>
</view>
/**index.wxss**/
.slides {
  height: 380rpx;
}
.slides image{
  width: 100%;
  height: 100%;
}
.grids{
   display: flex;
   flex-wrap: wrap;   
   background-color: #fff;
   border-left: 1rpx solid #eee;
   border-bottom: 1rpx solid #eee;
   color: #888;
}
.grids .item{
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 33.333333%;
  height: 250rpx;
  border-right: 1rpx solid #eee;
  border-top: 1rpx solid #eee;
  box-sizing: border-box;
}
.grids .item image{
  width: 70rpx;
  height: 70rpx;
}
.grids .item text{
  margin-top: 20rpx;
  color: #888;
  font-size: 28rpx;
}
.links{
  display: flex;
}
.links image{
    height: 200rpx;
}


效果:

1dc618a0ed9580ce8bfa6facb208c08f.png



小程序中发送HTTP请求


如果是测试环境:


在详情中设置

1dc618a0ed9580ce8bfa6facb208c08f.png

如果是正式环境


1.请求的地址必须在管理后台添加白名单


2.域名必须备案,服务端必须采用HTTPS

//index.js
//获取应用实例
const app = getApp()
Page({
  /**
   * 页面的初始数据
   */
  data: {
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
      wx.request({
        //这里的地址没有跨域的概念
        url: 'https://api.douban.com/v2/movie/coming_soon',
        header: {
          'Content-Type': 'json'
        },
        success: function(res){
            console.log(res)
        }
        //发送异步请求 不再是 WEB 那套 ajax
        //2.没有跨域
        //3.请求的地址必须在管理后台添加白名单
        //4.域名必须备案,服务端必须采用HTTPS
      })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
  },
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
  },
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
  },
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
  }
})


首页数据加载及数据绑定


封装http请求:


在utils的文件夹下:新建fetch.js


module.exports = (url, data) => {
   return new Promise((resolve, reject) => {
    wx.request({
      url: `https://locally.uieee.com/${url}`,
      success: resolve,
      fail: reject
    })
   })
}


index.js导入fetch,并使用


//index.js
//获取应用实例
const app = getApp()
const fetch = require('../../utils/fetch')
Page({
  /**
   * 页面的初始数据
   */
  data: {
     slides: [],
     categories: []
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
      wx.request({
        //这里的地址没有跨域的概念
        url: 'https://api.douban.com/v2/movie/coming_soon',
        header: {
          'Content-Type': 'json'
        },
        success: function(res){
            console.log(res)
        }
        //发送异步请求 不再是 WEB 那套 ajax
        //2.没有跨域
        //3.请求的地址必须在管理后台添加白名单
        //4.域名必须备案,服务端必须采用HTTPS
      })
      // wx.request({
      //   url: 'https://locally.uieee.com/slides',
      //   success: res => {
      //     this.setData({slides: res.data});
      //   }
      // })
      fetch('slides').then(res => {
        this.setData({ slides: res.data})
      })
      // wx.request({
      //   url: 'https://locally.uieee.com/categories',
      //   success: res => {
      //      this.setData({ categories : res.data })
      //   }
      // })
      fetch('slides').then(res => {
        this.setData({ categories: res.data})
      })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
  },
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
  },
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
  },
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
  }
})



页面间跳转


注意点:


tab页跳转到另一个tab页,需要使用navigator的open-type=“switchTab”


例如:


<view class="grids">  
   <navigator class="item" url="/pages/message/message" open-type="switchTab">
      <image src="/assets/grid/grid-02.png" />
      <text>美食</text>
   </navigator>
</view>


普通跳转 ,注意修改navigator的高宽百分比,不然会空白



添加了navigator


列表页分类信息加载


注意点, 设置分类导航栏的名字的顺序,一定在onReady函数执行完之后。


list.js


/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log(2)
    console.log(options)
    //这里不能确定一定是在 onReady过后执行
    fetch(`categories/${options.cat}`).then(res => {
       console.log(res.data)
       //设置导航条
      //  wx.setNavigationBarTitle({
      //    title: res.data.name
      //  })
       this.setData({ category: res.data})
    })
  },
onReady: function () {
      console.log(1)
      if(this.data.category.name){
        wx.setNavigationBarTitle({
          title: res.data.name
        })
      }     
  },


第一页的商铺信息的加载


关键代码:


优化封装的fetch.js,让其可以携带参数


module.exports = (url, data) => {
   return new Promise((resolve, reject) => {
    wx.request({
      url: `https://locally.uieee.com/${url}`,
      data: data,
      success: resolve,
      fail: reject
    })
   })
}


正确使用promise.2个请求,有前后顺序的正确写法:


/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log(2)
    console.log(options)
    //这里不能确定一定是在 onReady过后执行
    fetch(`categories/${options.cat}`).then(res => {
       console.log(res.data)
       //设置导航条
      //  wx.setNavigationBarTitle({
      //    title: res.data.name
      //  })
       this.setData({ category: res.data})
         //加载完分类信息过后再去加载商铺信息
        return  fetch(`categories/${this.data.category.id}shops`,{_page;1,_limit: 10}) 
    })
    .then(res => {
       this.setData({ shops: res.data })
    })
  },


上拉加载更多onReachBottom


https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html


list.json


值越小,越迟钝,看具体需求


{
  "onReachBottomDistance": 20
}


list.js


// pages/list/list.js
const fetch = require('../../utils/fetch')
Page({
  /**
   * 页面的初始数据
   */
  data: {
    //当前加载的分类
    category:{},
    //子分类下的全部店铺
    shops: [],
    pageIndex:0,
    pageSize:20,
    hasMore: true
  },
  loadMore(){
    if(!this.data.hasMore) return;
    //从data中取出 pageIndex 和 pageSize
    let { pageIndex, pageSize } = this.data
    const params = {_page: ++pageIndex, _limit: pageSize}
    fetch(`categories/${this.data.category.id}/shops`, params) 
    .then(res => {
      const totalCount = parseInt(res.header['X-Total-Count'])
      const hasMore = pageIndex * pageSize < totalCount
        const shops = this.data.shops.concat(res.data)
        this.setData({ shops, pageIndex, hasMore})
     })
  }
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log(2)
    console.log(options)
    //这里不能确定一定是在 onReady过后执行
    fetch(`categories/${options.cat}`).then(res => {
       console.log(res.data)
       //设置导航条
      //  wx.setNavigationBarTitle({
      //    title: res.data.name
      //  })
       this.setData({ category: res.data})
         //加载完分类信息过后再去加载商铺信息
        this.loadMore();
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
      console.log(1)
      if(this.data.category.name){
        wx.setNavigationBarTitle({
          title: res.data.name
        })
      }     
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
  },
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
  },
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
       //需要判断是否正在加载,否则会有多次触发问题
      console.log('到底了,别啦了');
      this.loadMore();
  },
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
  }
})


下拉刷新


启动下拉刷新


list.json
{
  "enablePullDownRefresh": true,
  "onReachBottomDistance": 20
}


停止下拉刷新


https://developers.weixin.qq.com/miniprogram/dev/api/ui/pull-down-refresh/wx.stopPullDownRefresh.html

wx.stopPullDownRefresh(Object object)
// pages/list/list.js
const fetch = require('../../utils/fetch')
Page({
  /**
   * 页面的初始数据
   */
  data: {
    //当前加载的分类
    category:{},
    //子分类下的全部店铺
    shops: [],
    pageIndex:0,
    pageSize:20,
    hasMore: true
  },
  loadMore(){
    if(!this.data.hasMore) return;
    //从data中取出 pageIndex 和 pageSize
    let { pageIndex, pageSize } = this.data
    const params = {_page: ++pageIndex, _limit: pageSize}
    return fetch(`categories/${this.data.category.id}/shops`, params) 
    .then(res => {
      const totalCount = parseInt(res.header['X-Total-Count'])
      const hasMore = pageIndex * pageSize < totalCount
        const shops = this.data.shops.concat(res.data)
        this.setData({ shops, pageIndex, hasMore})
     })
  }
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log(2)
    console.log(options)
    //这里不能确定一定是在 onReady过后执行
    fetch(`categories/${options.cat}`).then(res => {
       console.log(res.data)
       //设置导航条
      //  wx.setNavigationBarTitle({
      //    title: res.data.name
      //  })
       this.setData({ category: res.data})
         //加载完分类信息过后再去加载商铺信息
        this.loadMore();
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
      console.log(1)
      if(this.data.category.name){
        wx.setNavigationBarTitle({
          title: res.data.name
        })
      }     
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
  },
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
      //重新加载
      this.setData({shops:[],pageIndex:0, hasMore:false});
      this.loadMore()
  },
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
       //需要判断是否正在加载,否则会有多次触发问题
      console.log('到底了,别啦了');
      this.loadMore().then(() => wx.stopPullDownRefresh());
  },
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
  }
})


详细页


注意点:

1dc618a0ed9580ce8bfa6facb208c08f.png

使用wxs行内脚本设置过滤器。但是不支持es6


预览图片

5d4c6812c8535adbb050f4ddf2e1bce8.png

46a9d80a6e05e4e3b19d57a0ee70bcdf.png


效果:

66ba272a0bfc97be54a5fa679e3d5482.png

相关文章
|
1月前
|
存储 小程序 API
【微信小程序】-- uni-app 项目-- 购物车 -- 首页 - 轮播图效果(五十二)
【微信小程序】-- uni-app 项目-- 购物车 -- 首页 - 轮播图效果(五十二)
【微信小程序】-- uni-app 项目-- 购物车 -- 首页 - 轮播图效果(五十二)
|
1月前
|
小程序 Shell 网络安全
【微信小程序】-- 使用 Git 管理项目(五十)
【微信小程序】-- 使用 Git 管理项目(五十)
|
1月前
|
小程序 安全 JavaScript
从零开始uniapp微信小程序项目到发布(超级详细)
最近微信小程序又掀起一波风潮,本文站在新手的角度出发,比较适合第一次使用uniapp 开发微信小程序的伙伴,或者没有过实战经验的小伙伴参考,从零搭建uniapp小程序项目
129 1
|
1月前
|
小程序 开发工具 git
【微信小程序】-- uni-app 项目--- 购物车 -- 配置 tabBar 效果(五十一)
【微信小程序】-- uni-app 项目--- 购物车 -- 配置 tabBar 效果(五十一)
|
1月前
|
移动开发 自然语言处理 小程序
miniprogram-to-uniapp使用指南(各种小程序项目转换为uni-app项目)
miniprogram-to-uniapp使用指南(各种小程序项目转换为uni-app项目)
33 1
|
1月前
|
小程序 安全 JavaScript
【微信小程序】-- uni-app 项目创建 & 目录结构讲解(四十九)
【微信小程序】-- uni-app 项目创建 & 目录结构讲解(四十九)
|
12天前
|
小程序 前端开发 API
微信小程序全栈开发中的异常处理与日志记录
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的异常处理和日志记录,强调其对确保应用稳定性和用户体验的重要性。异常处理涵盖前端(网络、页面跳转、用户输入、逻辑异常)和后端(数据库、API、业务逻辑)方面;日志记录则关注关键操作和异常情况的追踪。实践中,前端可利用try-catch处理异常,后端借助日志框架记录异常,同时采用集中式日志管理工具提升分析效率。开发者应注意安全性、性能和团队协作,以优化异常处理与日志记录流程。
|
12天前
|
小程序 安全 数据安全/隐私保护
微信小程序全栈开发中的身份认证与授权机制
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中的身份认证与授权机制。身份认证包括手机号验证、微信登录和第三方登录,而授权机制涉及角色权限控制、ACL和OAuth 2.0。实践中,开发者可利用微信登录获取用户信息,集成第三方登录,以及实施角色和ACL进行权限控制。注意点包括安全性、用户体验和合规性,以保障小程序的安全运行和良好体验。通过这些方法,开发者能有效掌握小程序全栈开发技术。
|
12天前
|
JavaScript 前端开发 小程序
微信小程序全栈开发之性能优化策略
【4月更文挑战第12天】本文探讨了微信小程序全栈开发的性能优化策略,包括前端的资源和渲染优化,如图片压缩、虚拟DOM、代码分割;后端的数据库和API优化,如索引创建、缓存使用、RESTful API设计;以及服务器的负载均衡和CDN加速。通过这些方法,开发者可提升小程序性能,优化用户体验,增强商业价值。
|
12天前
|
小程序 前端开发 JavaScript
微信小程序全栈开发中的PWA技术应用
【4月更文挑战第12天】本文探讨了微信小程序全栈开发中PWA技术的应用,PWA结合Web的开放性和原生应用的性能,提供离线访问、后台运行、桌面图标和原生体验。开发者可利用Service Worker实现离线访问,Worker处理后台运行,Web App Manifest添加桌面图标,CSS和JavaScript提升原生体验。实践中需注意兼容性、性能优化和用户体验。PWA技术能提升小程序的性能和用户体验,助力开发者打造优质小程序。

热门文章

最新文章