前端Vue项目:旅游App-(15)home:网络请求house数据动态并组件化展示house列表信息

Posted karshey

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端Vue项目:旅游App-(15)home:网络请求house数据动态并组件化展示house列表信息相关的知识,希望对你有一定的参考价值。

文章目录

本项目博客总结:【前端】Vue项目:旅游App-博客总结

目标

完成热门精选的内容。

过程与代码

content组件

我们将houseList的内容抽取到一个组件中,将其命名为home-content.vue。

<template>
    <div class="content">
        <h2>热门精选</h2>
        <div class="list">

        </div>
    </div>
</template>

<script setup>

</script>

<style lang="less" scoped>
.content 
    padding: 0 20px;
    h2 
        font-size: 20px;
        font-weight: 700;
    

</style>

请求数据:houseList

数据是分页的。

第1页:123.207.32.32:1888/api/home/houselist?page=1
第2页:123.207.32.32:1888/api/home/houselist?page=2
以此类推。

本项目已经多此实现对数据请求的功能,因此这里不再赘述。

数据输出:

request

get请求的参数为params,post请求的参数为data。

这里先写死:请求第一页数据。

export function getHouseList() 
    return HYRequest.get(
        url: '/home/houselist',
        params: 
            page: 1
        
    )

store

// home.vue页面所有的进行网络请求和数据都封装到这里

import  defineStore  from "pinia";
import  getHotSuggest, getCategories, getHouseList  from '@/service'

const useHomeStore = defineStore('home', 
    state: () => 
        return 
            hotSuggest: [],
            categories: [],
            houseList: [],
        
    ,
    actions: 
        // 网络请求,由于返回一个promise,要异步async await
        async fetchHotSuggest() 
            const res = await getHotSuggest()
            this.hotSuggest = res.data
            // console.log(res)
        ,
        async fetchCategories() 
            const res = await getCategories()
            this.categories = res.data
        ,
        async fetchHouseList() 
            const res = await getHouseList()
            this.houseList = res.data
        
    
)

export default useHomeStore

控制台输出

数据请求成功。

动态加载更多列表数据

这里的数据一页只有20条,而我们也在代码中写死参数page=1。
实际上,App中此模块的数据是在下拉过程中加载更多的数据。因此我们要动态地加载数据。
这里要使用Array.push...解构语法。

为什么要解构?
答:网络请求得到的是一个数组,不解构会使store中的数据变成二维数组,这不是我们想要的。

如何动态地加载数据?
我们可以先用一个按钮模拟这个功能,每次点击按钮就加载更多的数据,page的参数可以用currentPage来表示,每点击按钮令currentPage++。currentPage存在store中。

request:

export function getHouseList(currentPage) 
    return HYRequest.get(
        url: '/home/houselist',
        params: 
            page: currentPage
        
    )

store:

// home.vue页面所有的进行网络请求和数据都封装到这里

import  defineStore  from "pinia";
import  getHotSuggest, getCategories, getHouseList  from '@/service'

const useHomeStore = defineStore('home', 
    state: () => 
        return 
            hotSuggest: [],
            categories: [],
            houseList: [],
            currentPage: 1,

        
    ,
    actions: 
        // 网络请求,由于返回一个promise,要异步async await
        async fetchHotSuggest() 
            const res = await getHotSuggest()
            this.hotSuggest = res.data
            // console.log(res)
        ,
        async fetchCategories() 
            const res = await getCategories()
            this.categories = res.data
        ,
        async fetchHouseList() 
            const res = await getHouseList(this.currentPage)
            this.currentPage++
            this.houseList.push(...res.data)
        
    
)

export default useHomeStore

按钮:

<button @click="moreList()">page++</button>
function moreList()
    homeStore.fetchHouseList()

初始状态:说明只请求了第一页数据。


点一次按钮:请求了第二页数据。

注意store中currentPage的代码。它表示的是下一次要请求的页面。

根据F12中的网络也可以得知请求的数据:

house-item组件

显然house-item可能会在项目中多个地方使用,因此我们要把它单独抽为对应组件:


注意,数据中discoveryContentType表示不同的展示列表数据的方式。上图左为9,右为3.

思路:

  • house-content判断discoveryContentType,为3则引入组件house-item-v3,为9则引入组件house-item-v9
  • house-item中定义props:item
  • house-content中传入数据house-item

阶段1:数据传送

数据的传送情况如下:


当前效果:


对应代码:

home-content:

<template>
    <div class="content">
        <h2>热门精选</h2>

        <div class="list">
            <template v-for="(item, index) in houseList" :key="item.data.houseId">
                <houseItemV9 v-if="item.discoveryContentType === 9" :item="item.data"></houseItemV9>
                <houseItemV3 v-else-if="item.discoveryContentType === 3" :item="item.data"></houseItemV3>
            </template>
        </div>
    </div>
</template>

<script setup>
import  storeToRefs  from "pinia";
import useHomeStore from "../../../store/modules/home";
import houseItemV9 from "../../../components/house-item/house-item-v9.vue";
import houseItemV3 from "../../../components/house-item/house-item-v3.vue";


const homeStore = useHomeStore()
homeStore.fetchHouseList()
const  houseList  = storeToRefs(homeStore)
console.log(houseList)

</script>

<style lang="less" scoped>
.content 
    padding: 0 20px;

    h2 
        font-size: 20px;
        font-weight: 700;
    

</style>

house-item-v9:

<template>
    <div class="house-item">
        <h2>v9 item.houseName</h2>
    </div>
</template>

<script setup>
defineProps(
    item: 
        type: Object,
        default: () => ()
    
)
</script>

<style lang="less" scoped>

</style>

house-item-v3:

<template>
    <div class="house-item">
        <h2>v3 item.houseName</h2>
    </div>
</template>

<script setup>
defineProps(
    item: 
        type: Object,
        default: () => ()
    
)
</script>

<style lang="less" scoped>

</style>

阶段2:对着目标写样式

评分使用vant库。Rate 评分 - Vant 4 (gitee.io)

要显示小数。

house-item-v9

效果:


代码:

<template>
    <div class="house-item">
        <div class="house-inner">
            <div class="image">
                <img :src="item.image.url" alt="">
            </div>
            <div class="info">
                <div class="summary"> item.summaryText </div>
                <div class="name"> item.houseName </div>
                <div class="tips">
                    <div class="stars" >
                        <van-rate v-model="starValue" readonly allow-half size="12px"/>
                    </div>
                    <div class="price"> item.finalPrice 
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
import  ref  from 'vue';

const props = defineProps(
    item: 
        type: Object,
        default: () => ()
    
)

const starValue = ref(props.item.commentScore);
</script>

<style lang="less" scoped>
.house-item 
    // 每个item宽度占屏幕一半
    width: 50%;
    margin-top: 20px;

    .house-inner 
        // 信息在img上:子绝父相
        position: relative;

        margin: 5px;

        .image 
            img 
                width: 100%;
                border-radius: 6px;
            
        

        .info 
            position: absolute;
            bottom: 0;

            padding: 8px 10px;

            color: #fff;

            .summary 
                font-size: 12px;
            

            .name 
                // 超过2行就省略号省略...
                overflow: hidden;
                text-overflow: ellipsis;
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;

                margin: 5px 0;
            

            .tips
                display: flex;
                justify-content: space-between;
            
        

    

</style>
house-item-v9:debug

出现了一个问题:4.8分只有4颗星。

控制台报错:


大致意思:modelValue要的是Number而不是String。

查看Vue插件的starValue:是字符串。


因此我们要把它改成Number。

const starValue = ref(Number(props.item.commentScore));
house-item-v3

icon的引入:Icon 图标 - Vant 4 (gitee.io)


效果:


代码:

<template>
    <div class="house-item">
        <div class="house-inner">
            <div class="image">
                <img :src="item.image.url" alt="">
            </div>
            <div class="info">
                <div class="location">
                    <van-icon name="location" color="#808080" />
                     item.location 
                </div>
                <div class="name"> item.houseName </div>
                <div class="summary"> item.summaryText </div>
                <div class="price">
                    <div class="cheap"> item.finalPrice </div>
                    <div class="exp"> item.productPrice </div>
                    <div class="sale">立减¥ item.productPrice - item.finalPrice 
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup>
defineProps(
    item: 
        type: Object,
        default: () => ()
    
)
</script>

<style lang="less" scoped>
.house-item 
    width: 50%;

    .house-inner 
        margin: 5px;

        .image 
            img 
                width: 100%;
                border-radius: 6px;
     

以上是关于前端Vue项目:旅游App-(15)home:网络请求house数据动态并组件化展示house列表信息的主要内容,如果未能解决你的问题,请参考以下文章

前端Vue项目:旅游App-(13)home:热门数据的网络请求store和显示

前端Vue项目:旅游App-(13)home:热门数据的网络请求store和显示

前端Vue项目:旅游App-(14)home+search:搜索按钮及其路由跳转分组数据的网络请求request数据存储store和动态显示

前端Vue项目:旅游App-(14)home+search:搜索按钮及其路由跳转分组数据的网络请求request数据存储store和动态显示

前端Vue项目:旅游App-(17)home:页面滚动显示搜索栏节流时间同步

前端Vue项目:旅游App-(20)home:点击跳转至带参数的动态路由