Foods, Only Foods

General 概要
内容

.事件

.导航

.声明周期函数

目的

.进一步熟悉资源服务器的搭建和网络请求的过程

.掌握事件的基本使用以及

.掌握导航的基本使用

.掌握页面的生命周期函数的使用

原理

.从资源服务器读取数据并渲染

要求

.按照以下步骤完成美食列表的设计和开发

.本案例可拓展至列表形式的其它内容,如新闻、购物车、订单、留言、代办事项等;不局限于美食。如果使用其它题材,请自行准备素材或服务器

.独立完成

.有自己的设计和拓展

.实验报告:采用学院统一下发的 实验模板 文件,以文字说明,配以必要的效果图片或核心代码,展示并说明数据来源、实施过程、各部分功能、具体内容和实现细节;最后导出为PDF,按照要求命名,提交个人学习通作业

Project 项目介绍
首次加载并渲染10条数据
拖动到底部后,触发加载更多数据
顶部下拉时,触发数据刷新
当所有数据加载完毕后,提示"所有数据加载完毕"
单击某个美食,进入到详情页
Keypoints 知识点
搭建服务器 Node.js
列表渲染 wx:for
生命周期函数 lifetime
网络请求 wx.request
下拉刷新 pulldownRefresh
触底加载 reachBottom
导航及传参 navigator
Footage 素材准备
数据文件 JSON

数据节点信息要素;准备若干条

为调试方便,没有给出完整的图片路径,仅给出图片部分路径,后期再拼接上资源服务器的地址

{
    "id": 1,
    "image": "/img/2846ed948e95eef4c4d50edaf52a483432023.jpg",
    "name": "宫廷月亮虾饼",
    "phone": "15530710686",
    "address": "任丘市裕华中路与会战道交叉口东南角蕾莎汇生活4层",
    "businessHours": "周一至周日10:00-21:00"
}
产品图片 images
阿里字体图标 iconfont

店铺、地址、联系电话、营业时间

资源服务器

node.js、express

Pages 项目页面
列表页 index
详情页 detail - 自行完成
Step 1: 项目创建
创建空白文件夹 foods
打开微信开发者工具
新建项目;项目名称为 foods,项目目录为刚才创建的空白文件夹 foods
其他根据实际情况填写
最后确定,完成项目的创建
Step 2: app.json项目设置

颜色、标题可以自定

标题栏设置
"window": {
    "navigationBarTextStyle": "white",
    "navigationBarTitleText": "foods",
    "navigationBarBackgroundColor": "#f39c12"
}
页面配置:index、detail
"pages": [
    "pages/index/index",
    "pages/index/detail/detail"
]
Step 3: app.wxss
初始化样式

盒模型

公共样式设置

字体

图片

布局

第三方样式

导入@import

Step 4: index 页面
index.json - 导航栏标题

使用下拉刷新

"navigationBarTitleText": "Foods",
"navigationBarBackgroundColor": "#ffa502",
"enablePullDownRefresh": true
index.wxml

列表渲染

index.js

网络请求 - 使用一个flag区分下拉刷新和触底加载;page、pageSize、isLoading使用静态数据;baseUrl使用动态数据,因为结构中需要使用

封装网络请求函数
loadLists(flag) {
    this.isLoading = true
    wx.request({
        //url: this.data.baseUrl + '/good/page?page=' + this.page + '&pageSize=' + this.pageSize,
        url: this.data.baseUrl + '/good/page',
        //默认是GET;可以不写
        method: 'GET',
        //也可以不使用data配置项,直接拼接请求参数
        data: {
            page: this.page,
            pageSize: this.pageSize
        },
        success: (res) => {
            //拉取成功后,新数据叠加到旧数据上
            this.setData({
                lists: [...this.data.lists, ...res.data],
                total: res.header['X-Total-Count']
            })
        },
        fail:err=>{
            console.log(err);
        },
        complete: () => {
            this.isLoading = false
            if (flag) {
                wx.stopPullDownRefresh()
            }
        }
    })
}

每个数据项绑定事件,单击后跳转到详情页;思考:为什么使用currentTarget?

toDetail(e) {
    wx.navigateTo({
        url: './detail/detail?id=' + e.currentTarget.dataset.id,
    })
}

下拉刷新 - 页数初始化;初始化完成后,停止刷新动画;true表示要执行停止刷新行为

onPullDownRefresh() {
    this.page = 1,
    this.setData({
        lists: []
    })
    this.loadLists(true)
}

触底加载 - 页数和页大小达到总数时,停止加载;数据加载中停止再次触发加载

onReachBottom() {
    //也可以直接判断当前列表的长度和总长度是否相等
    if (this.page * this.pageSize >= this.data.total) {
        return;
    }
    //这两个条件可以合并判断
    if (this.isLoading) {
        return;
    }
    this.page ++
    this.loadLists(false)
}                
index.wxss

数据项渲染 - flex布局;溢出打点;注意直接父级也要溢出隐藏

Step 5: detail 页面
根据导航参数显示指定美食的详情
请自行设计开发
详情页在onLoad中获取id并渲染对应的商品
onLoad(options) {
    this.setData({
        id: options.id
    })
    //自行完成
}
拓展
给出已加载数据和总数据展示 - 固定定位在页面右下角
使用界面API给出相应的提示,如数据加载中、加载完毕等
资源服务器参考代码
完整流程请参考 动态资源服务器
读取json数据 → 解析 → 根据参数截取 → 返回结果
all:全部返回
page:截取返回
let fs = require('fs');
let express = require('express')
let port = 3000

// 创建Web服务器对象
let app = express();

// 静态资源处理
app.use(express.static('./public'));

// 读取JSON数据
const jsonStr = fs.readFileSync('./public/data/good.json', {
    encoding: 'utf8'
});

const food = JSON.parse(jsonStr);

//全部拉取
app.get('good/all', (req, res) => {
    res.send(food.cont)
})

//分页拉取 - 请求格式 ?page=1&pageSize=10
app.get('good/page', (req, res) => {
    let arr = [...food.cont]
    let start = (req.query.page - 1) * req.query.pageSize;
    let result = arr.splice(start, req.query.pageSize)
    res.setHeader('X-Total-Count', food.cont.length);
    res.send(result);
});

app.listen(port, () => {
    console.log('服务器启动成功,地址为:http://127.0.0.1:3000');
});