1.搜索界面开发
1.1 模糊查询
文件地址:pycharm-
class SightListView(ListView):
paginate_by = 5
def get_queryset(self):
#is_valid=True:表中is_valid列,有值则被查询出来
query = Q(is_valid=True)
#1.获得热门景点
is_hot = self.request.GET.get('is_hot',None)
if is_hot:
query = query & Q(is_hot=True)
#2.获得精选景点
is_top = self.request.GET.get('is_top',None)
if is_top:
query = query & Q(is_top=True)
#3.景点名称搜索
👇
#获取前端传来的 用于搜索的景点关键字
name = self.request.GET.get('name',None)
if name:
query = query & Q(name__icontains=name) #名字列模糊查询
👆
queryset = Sight.objects.filter(query)
return queryset
#用于分页函数
def get_paginate_by(self, queryset):
#用于控制 从前端传递过来的每一页显示条数的函数
page_size = self.request.GET.get('limit',None)
return page_size or self.paginate_by #对分页做一个重写
1.2 访问服务端接口【获取数据】
<script setup>
import { ajax } from '@/utils/ajax';
import { SightApis } from '@/utils/apis';
//访问服务端接口,获取数据
const getDataList=()=>{
ajax.get(SightApis.sightListUrl,{
params:{
name:sightName.value,
page:currentPage.value,
limit:perPage.value
}
}).then(({data:{meta,objects}})=>{
dataList.value=objects
totalItem.value = meta.total_count
})
}
onMounted(()=>{
getDataList()
})
</script>
1.3 搜索函数
if语句,判断搜索框中是否输入数据,如果没有数据则提示"说话!"
<script setup>
import { showToast } from 'vant';//提示框组件
//搜索函数
const onSearch = ()=>{
// console.log('onSearch')
if(!sightName.value){
showToast('请输入搜索词')
return
}
//重置数据
dataList.value=[]
currentPage.value=1
//执行查询
getDataList()
}
</script>
1.4 清空并换新列表函数
<script setup>
//清空列表函数
const clear =()=>{
//重置数据
dataList.value=[]
currentPage.value=1
//执行查询
getDataList()
}
const pageChange=()=>{
getDataList()
}
</script>
<template>
<div class="page-search">
<!-- 分页 -->
<van-pagination v-model="currentPage"
:total-items="totalItem"
:items-per-page="perPage"
@change="pageChange">
</van-pagination>
</div>
</template>
1.5 调整搜索界面布局
<style lang="less">
.page-search{
padding-bottom: 60px;
.sight-list{
padding: 10px;
background-color: aliceblue;
margin-bottom: 10px;
}
}
</style>
1.6 分类显示
点击不同的按钮进入不同的搜索界面【热门/推荐景点】
<script setup>
import { useRoute,useRouter } from 'vue-router';
const route = useRoute()
const router = useRouter()
//热门景点和精选景点
const isHot = ref('')
const isTop = ref('')
onMounted(()=>{
isHot.value = route.query.isHot
isTop.value = route.query.isTop
})
</script>
<template>
<div class="page-search">
<!-- 判断显示热门景点还是精选景点 -->
<h2 v-if="isHot">热门推荐</h2>
<h2 v-if="isTop">精选推荐</h2>
<!-- 底部导航 -->
<TripFooter v-if="!(isHot||isTop)"/>
</div>
</template>
1.7 返回主界面
<script setup>
const goBack = ()=>{
router.go(-1)
}
</script>
<template>
<div class="page-search">
<!-- 标题 -->
<van-nav-bar title="搜索景点" left-text="返回"
@click="goBack" v-if="isHot||isTop"/>
<van-nav-bar title="搜索景点" v-else/>
</div>
</template>
1.8 “更多”按键功能跳转
1.8.1 Fine.vue推荐景点
1.8.2 Hot.vue热门景点
2.景点接口数据联调
1.阅读接口文档 2.配置接口地址 3.使用axios获取数据 4.将数据至到模型层
2.1 服务端获取评论信息
数据模型文件
该文件用于统一服务端与数据库端的数据格式
“抗拒不匹配”,数据库端以表的方式表示数据,服务端以对象等方式表示数据
为了使两者数据统一,因此需要数据模型做规范
class Sight(CommonModel):
#....
@property
#获得评论总数
def comment_count(self):
return self.comments.filter(is_valid=True).count()
@property
#获得景点图片总数
def image_count(self):
return self.images.filter(is_valid=True).count()
重构响应对象
重构原因:服务端提供了众多接口用于响应数据,
为了便于前端能够统一处理这些数据,需要将响应的数据统一格式。
以上,成为重构响应对象(序列化)
文件地址:sight/serializers.py
class SightDetailSerializers(BaseSerializer):
#景点详情
def to_dict(self):
obj = self.obj
return {
#...
'comment_count': obj.comment_count,#获得景点评论数量
'image_count': obj.image_count#获得景点图片数量
}
2.2 配置接口
文件地址:src\utils\apis.js
//景点相关的接口
const SightApis = {
//访问服务端的接口地址
//访问景点列表
sightListUrl:apiHost+"/sight/sight/list/",
//访问景点详情
sightDetailUrl:apiHost+"/sight/sight/detail/#{id}/",
//门票列表
sightTicketUrl:apiHost+"/sight/ticket/list/#{id}/",
}
再调整一下路由:
{
path:'/sight/comment/:id',
name:'SightComment',
component:SightComment
},
2.3 控制跳转
import useroute/userouter:用于控制页面跳转工具,传值工具;
goBack:返回前一页。
<script setup>
import {useRoute, useRouter} from 'vue-router'
import { ajax } from '@/utils/ajax';
import { SightApis } from '@/utils/apis';
const router = useRouter()
const route = useRoute()
const goBack = ()=>{
router.go(-1)
}
</script>
2.4 获取景点详情信息
{}:用于表示对象,类似于python字段,由于服务端响应的数据是对象的格式,因此使用{}承载
replace:替换api/sight/sight/detail/#{id}中的id值
route.params.id: 获取地址栏携带id值
const sightDetail = ref({})
const getSightDetail = ()=>{
const url = SightApis.sightDetailUrl.replace('#{id}',route.params.id)
ajax.get(url).then(({data})=>{
sightDetail.value = data
})
}
onMounted(()=>{
getSightDetail()
})
2.5 获取景点门票信息
const ticketList = ref([])
const getTicketList = ()=>{
const url = SightApis.sightTicketUrl.replace('#{id}',route.params.id)
ajax.get(url).then(({data:{objects}})=>{
ticketList.value = objects
})
}
onMounted(()=>{
getTicketList()
})
2.6 获取景点地址
computed计算属性,用于数据处理的函数,如何返回数据进行格式化
const fullArea = computed(()=>{
let area = sightDetail.value.province+sightDetail.value.city
if(sightDetail.value.area){
area += sightDetail.value.area
}
if(sightDetail.value.town){
area += sightDetail.value.town
}
return area
})
2.7 更改静态地址为动态
景点大图:
景点介绍:
地址信息:
门票列表: