(十九)小程序的前端【首页】页面和后端逻辑
前端【首页】页面
思路
1.初始化数据
2.下拉刷新数据
3.上翻页刷新数据
4.瀑布流-----在wxss中 falls
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!-- 上面四幅图 --> <view class="menu"> <view class="item" wx:for="{{menuList}}" wx:key="index"> <image src="{{item.img}}"></image> <text>{{item.text}}</text> </view> </view> <!-- news --> <view class="falls"> <view class="item" wx:for="{{newsList}}" wx:key="id"> <view class="pic"> <navigator url="/pages/newsDetail/newsDetail?newsId={{item.id}}"><image class="img" src="{{item.cover}}" mode="widthFix"></image></navigator> <view class="user"> <view class="author"> <image class="avatar" src="{{item.user.avatar}}"></image> <view>{{item.user.nickname}}</view> </view> <view class="favor"> <image class="icon" src="/static/images/icon/likes_smallicon_nor.png"></image> <view>{{item.favor_count}}</view> </view> </view> </view> <view class="title"> <text>{{item.content}}</text> <text class="tag" wx:if="{{item.topic.title}}"># {{item.topic.title}}</text> </view> </view> </view>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/**index.wxss**/ .menu{ padding: 20rpx } .menu image{ width: 100rpx; height: 100rpx; border-radius: 50rpx; } .menu{ display: flex; flex-direction: row; justify-content: space-around; } .menu .item{ display: flex; flex-direction: column; align-items: center; } .falls { -moz-column-count:2; /* Firefox */ -webkit-column-count:2; /* Safari and Chrome */ column-count:2; -moz-column-gap:20rpx; /* Firefox */ -webkit-column-gap:20rpx; /* Safari and Chrome */ column-gap:20rpx; } .falls .item{ break-inside: avoid-column; -webkit-column-break-inside: avoid; /* Safari and Chrome */ } .falls .item .pic{ position: relative; } .falls .item .pic .img{ width: 100%; display: block; } .falls .item .pic .user{ position: absolute; bottom: 0; left: 0; background-color: #333; opacity: 0.6; height: 60rpx; display: flex; flex-direction: row; justify-content: space-between; align-items: center; width: 100%; color: #fff; font-size: 28rpx; } .falls .item .pic .user .author,.falls .item .pic .user .favor{ display: flex; flex-direction: row; align-items: center; padding: 0 10rpx; } .falls .item .pic .user .author .avatar{ width: 28rpx; height: 28rpx; border-radius: 14rpx; margin-right:10rpx; } .falls .item .pic .user .favor .icon{ width: 28rpx; height: 28rpx; margin-right:10rpx; } .falls .item .title{ border: 1rpx solid #ddd; padding: 15rpx; font-size: 28rpx; } .falls .item .title .tag{ font-size: 32rpx; color: #00c8b6; margin: 0 10rpx; }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// pages/home/home.js var api = require('../../config/api.js') Page({ /** * 页面的初始数据 */ data: { menuList: [{ 'text': '精品文章', 'img': "/static/icon/home_essays_icon_show.png" }, { 'text': '小视频', 'img': "/static/icon/home_video_icon_show.png" }, { 'text': '名人堂', 'img': "/static/icon/home_superstar_icon_show.png" }, { 'text': '观点说', 'img': "/static/icon/home_viewpoint_icon_show.png" }, ], newsList: [], minId:0, maxId:0, }, /** * 分页获取动态列表 */ getNews:function(){ wx.request({ url: api.News, method: 'GET', dataType: 'json', responseType: 'text', success: (res) => { this.setData({ newsList:res.data, maxId:res.data[0].id, minId:res.data[res.data.length-1].id, }) }, }) }, /** * 生命周期函数--监听页面加载 * 页面第一次执行执行这个函数 也可以把上面的函数写在这个函数里 */ onLoad: function (options) { this.getNews(false); }, /** * 页面相关事件处理函数--监听用户下拉动作 * 1. 传数据 最大的id * 2. 返回的数据和之前有的数据合并用 concat * 3. 在记录一下当前的最大的id */ onPullDownRefresh: function () { wx.request({ url: api.News, data: { max_id:this.data.maxId }, method: 'GET', dataType: 'json', responseType: 'text', success: (res)=> { if(!res.data.length){ wx.showToast({ title: '已是最新数据', icon:"none" }) // 刷新之后就停止 wx.stopPullDownRefresh() return } // 查出来的数据翻转一下 var dataList = res.data.reverse(); this.setData({ newsList: dataList.concat(this.data.newsList), maxId: dataList[0].id }) wx.stopPullDownRefresh() }, }) }, /** * 页面上拉触底事件的处理函数 * 1. 传数据 最小的id * 2. 返回的数据和之前有的数据合并用 concat * 3. 在记录一下当前的最小的id */ onReachBottom: function () { wx.request({ url: api.News, data: { min_id:this.data.minId }, method: 'GET', dataType: 'json', responseType: 'text', success: (res)=> { if(res.data.length===0){ wx.showToast({ title: '已经到底啦', icon: 'none', }) return } this.setData({ newsList:this.data.newsList.concat(res.data), minId:res.data[res.data.length-1].id }) }, }) }, })
后端的接口
方式一 继承APIView
from app01 import models from django.forms import model_to_dict from rest_framework.views import APIView from rest_framework import serializers from rest_framework.response import Response # 第二步 序列化 class NewsModelSerializer(serializers.ModelSerializer): # 因为这个样子是拿到的 tpoic和user 是一个数字 我们不希望是这样 所有我们修改
# 下面两行代码 + 下面的两个函数 是解决方法 user = serializers.SerializerMethodField() topic = serializers.SerializerMethodField() class Meta: model = models.News fields = ['id', 'cover', 'content', 'topic', "user", 'favor_count'] def get_user(self, obj): return model_to_dict(obj.user, fields=['id', 'nickname', 'avatar']) def get_topic(self, obj): if not obj.topic: return return model_to_dict(obj.topic, fields=['id', 'title']) # 第一步 先进入这个函数 查到数据走序列化 class NewsView(APIView): def get(self, request, *args, **kwargs): min_id = request.query_params.get("min_id") max_id = request.query_params.get("max_id") if min_id: queryset = models.News.objects.filter(id__lt=min_id).order_by('-id')[0:10] elif max_id: queryset = models.News.objects.filter(id__gt=max_id).order_by('id')[0:10] else: queryset = models.News.objects.all().order_by('-id')[0:10] # GET 用instance 多条用 mang=True ser = NewsModelSerializer(instance=queryset, many=True) return Response(ser.data)
方式二 继承ListAPIView
from app01 import models from rest_framework import serializers from django.forms import model_to_dict from rest_framework.filters import BaseFilterBackend from rest_framework.pagination import LimitOffsetPagination from rest_framework.generics import ListAPIView from rest_framework.response import Response # 序列化 class ListNewsModelSerializer(serializers.ModelSerializer): # 因为这个样子是拿到的 tpoic和user 是一个数字 我们不希望是这样 所有我们修改 user = serializers.SerializerMethodField() topic = serializers.SerializerMethodField() class Meta: model = models.News fields = ['id', 'cover', 'content', 'topic', "user", 'favor_count'] def get_user(self, obj):
# 想要展示的几种形式 # return obj.user.nickname # return {'nickname',obj.user.nickname} # from django.forms import model_to_dict return model_to_dict(obj.user, fields=['id', 'nickname', 'avatar']) def get_topic(self, obj): if not obj.topic: return # from django.forms import model_to_dict return model_to_dict(obj.topic, fields=['id', 'title']) # 分页 class OldBoyLimitPagination(LimitOffsetPagination): """ 本质上帮助我们进行切片的处理:[0:N] """ default_limit = 5 max_limit = 50 limit_query_param = 'limit' offset_query_param = 'offset' def get_offset(self, request): return 0 def get_paginated_response(self, data): return Response(data) class ReachBottomFilter(BaseFilterBackend): '''下来传过来的值''' def filter_queryset(self, request, queryset, view): min_id = request.query_params.get('min_id') if not min_id: return queryset return queryset.filter(id__lt=min_id)[0:10] class PullDownRefreshFilter(BaseFilterBackend):
'''上拉刷新''' def filter_queryset(self, request, queryset, view): max_id = request.query_params.get('max_id') if not max_id: return queryset return queryset.filter(id__gt=max_id)[0:10]
# 第一步: class NewsView(ListAPIView): queryset = models.News.objects.all().order_by('-id') # 上滑和下拉 条件走 filter_backends pagination_class = OldBoyLimitPagination filter_backends = [ReachBottomFilter, PullDownRefreshFilter] # 这里的CreateNewsModel我省略了 序列化 def get_serializer_class(self): if self.request.method == 'POST': return CreateNewsModelSerializer if self.request.method == 'GET': return ListNewsModelSerializer