[Frontend] Vue project: Travel App-(21) detail: house details page and its data, return navigation bar, carousel map

Summary of this project blog: [Front-end] Vue project: Travel App-Blog Summary

Target

Complete the return navigation bar and carousel image on the detail page. (The detail page is the page clicked into the houseList:)

insert image description here
Corresponding data: To pass in houseId, different data will be returned depending on the parameter houseId. like:

123.207.32.32:1888/api/detail/infos?houseId=20061007
123.207.32.32:1888/api/detail/infos?houseId=44173741

process and code

Request data: request+store

Request data:

service/modules/detail.js:

// 此文件保存所有detail页面的网络请求
import HYRequest from '@/service/request'

export function getDetailInfos(houseId) {
    
    
    return HYRequest.get({
    
    
        url: '/detail/infos',
        params: {
    
    
            houseId
        }
    })
}

service/index:

// 此文件导入并导出所有要使用的service

export * from '@/service/modules/city'
export * from '@/service/modules/home'
export * from '@/service/modules/detail'

Management data:

store/modules/detail:

import {
    
     defineStore } from "pinia";
import {
    
     getDetailInfos } from '@/service/modules/detail'

const useDetailStore = defineStore('detail', {
    
    
    state: () => {
    
    
        return {
    
    
            detailData: {
    
    },

        }
    },
    actions: {
    
    
        async fetchDetailData(houseId) {
    
    
            const res = await getDetailInfos(houseId)
            console.log(res)
            this.detailData=res.data
        }
    }
})

export default useDetailStore

detail.vue:

const route = useRoute()
const houseId = route.params.id
const detailStore = useDetailStore()

detailStore.fetchDetailData(houseId)
const {
    
     detailData } = storeToRefs(detailStore)

Data requested by the page:

insert image description here

This data is more complicated. When we make each component, it is best to split the data. For example, the component that makes the carousel only transmits the data related to the carousel.

Don't think about "once in place", it will be very troublesome.

carousel component

Swipe Carousel - Vant 4 (gitee.io)

Related image data: We use url for carousel.

insert image description here
The carousel component made according to the Vant library:detail-swipe

<template>
    <div class="swipe">
        <van-swipe class="swipeList" :autoplay="3000" lazy-render>
            <van-swipe-item v-for="item in props.swipeData" :key="item">
                <img :src="item.url" />
            </van-swipe-item>
        </van-swipe>
    </div>
</template>

<script setup>
const props = defineProps({
      
      
    swipeData: {
      
      
        type: Array,
        default: () => []
    }
})
</script>

<style lang="less" scoped>

</style>

detail

<!-- 轮播图 -->
<detailSwipe :swipe-data="detailData.mainPart.topModule.housePicture.housePics"/>

bug:undefined

There is such a bug:

insert image description here
Relevant analysis and solutions: [Front-end debug] Carousel chart error TypeError: Cannot read properties of undefined (reading 'topModule')

Carousel related properties and styles

detail-swipe

<template>
    <div class="swipe">
        <van-swipe class="swipeList" :autoplay="3000" lazy-render :show-indicators="false">
            <van-swipe-item v-for="item in props.swipeData" :key="item">
                <img :src="item.url" />
            </van-swipe-item>
            <!-- 自定义指示器 -->
            <template #indicator="{ active, total }">
                <div class="custom-indicator">{
   
   { active + 1 }}/{
   
   { total }}</div>
            </template>
        </van-swipe>
    </div>
</template>

<script setup>
const props = defineProps({
      
      
    swipeData: {
      
      
        type: Array,
        default: () => []
    }
})
</script>

<style lang="less" scoped>
.swipe {
      
      

    .swipeList {
      
      
        img {
      
      
            width: 100%;
        }

        .custom-indicator {
      
      
            position: absolute;
            right: 5px;
            bottom: 5px;
            padding: 2px 5px;
            font-size: 12px;
            background: rgba(0, 0, 0, 0.1);
            margin-right: 5px;
            margin-bottom: 5px;
            color: #fff;
        }
    }
}
</style>

detail.vue

<!-- 轮播图 -->
<div class="main" v-if="detailData.mainPart">
    <detailSwipe :swipe-data="detailData.mainPart.topModule.housePicture.housePics"/>
</div>

back to navigation bar

NavBar Navigation Bar - Vant 4 (gitee.io)

Just use this:
insert image description here

According to the document, modify the theme color of the navigation bar NavBar: (common.css: root)

--van-text-color:var(--primary-color) !important;

Note that this page does not display the TabBar at the bottom, we need to add the top-page class:

/* 隐藏TabBar的类 */
.top-page {
    
    
    /* 占满整个屏幕 */
    height: 100vh;
    /* 有position,z-index才生效
     这里如果是absolute则不生效,可能与TabBar组件相关样式有关 */
    position: relative;
    /* TabBar的z-index默认1 */
    z-index: 9;
    /* 背景色挡住TabBar */
    background-color: #fff;
    /* y轴方向溢出:滚动条 */
    overflow-y: auto;
}

Effect

insert image description here

total code

Modified or added files

insert image description here

css/common

Modify the navigation bar style:

:root {
    
    
    /* 主题颜色 */
    --primary-color: #ff9854;
    /* 所有搜索框,有!important才会显示 */
    --van-search-left-icon-color: var(--primary-color) !important;
    /* 所有bottom下划线  */
    --van-tabs-bottom-bar-color: var(--primary-color) !important;

    --van-primary-color:var(--primary-color) !important;
    --van-text-color:var(--primary-color) !important;

    /* 渐变色 */
    --theme-linear-gradient:linear-gradient(90deg,#fa8c1d,#fcaf3f);
}

body {
    
    
    font-size: 14px;
}

/* 隐藏TabBar的类 */
.top-page {
    
    
    /* 占满整个屏幕 */
    height: 100vh;
    /* 有position,z-index才生效
     这里如果是absolute则不生效,可能与TabBar组件相关样式有关 */
    position: relative;
    /* TabBar的z-index默认1 */
    z-index: 9;
    /* 背景色挡住TabBar */
    background-color: #fff;
    /* y轴方向溢出:滚动条 */
    overflow-y: auto;
}

service/modules/detail

All network requests for the detail page are here.

// 此文件保存所有detail页面的网络请求
import HYRequest from '../request'

export function getDetailInfos(houseId) {
    
    
    return HYRequest.get({
    
    
        url: '/detail/infos',
        params: {
    
    
            houseId
        }
    })
}

service/index

All services are here. (All imports are functions)

// 此文件导入并导出所有要使用的service

export * from '@/service/modules/city'
export * from '@/service/modules/home'
export * from '@/service/modules/detail'

store/modules/detail

store: manage the data of detail.

import {
    
     defineStore } from "pinia";
import {
    
     getDetailInfos } from '@/service/modules/detail'

const useDetailStore = defineStore('detail', {
    
    
    state: () => {
    
    
        return {
    
    
            detailData: {
    
    },

        }
    },
    actions: {
    
    
        async fetchDetailData(houseId) {
    
    
            const res = await getDetailInfos(houseId)
            // console.log(res)
            this.detailData=res.data
        }
    }
})

export default useDetailStore

views/detail/detail

House details page:

<template>
    <div class="detail top-page">
        <van-nav-bar title="房屋详情" left-text="旅途" left-arrow @click-left="onClickLeft" />

        <!-- 轮播图 -->
        <div class="main" v-if="detailData.mainPart">
            <detailSwipe :swipe-data="detailData.mainPart.topModule.housePicture.housePics" />
        </div>
    </div>
</template>

<script setup>
import useDetailStore from '@/store/modules/detail';
import detailSwipe from '../detail/cpns/detail-swipe.vue'

import {
      
       storeToRefs } from 'pinia';
import {
      
       useRoute } from 'vue-router';

// const
const route = useRoute()
const houseId = route.params.id
const detailStore = useDetailStore()

// store
detailStore.fetchDetailData(houseId)
const {
      
       detailData } = storeToRefs(detailStore)

// navBar
const onClickLeft = () => history.back();
</script>

<style lang="less" scoped>

</style>

views/detail/cpns/detail-swipe

The carousel component of the details page:

<template>
    <div class="swipe">
        <van-swipe class="swipeList" :autoplay="3000" lazy-render :show-indicators="false">
            <van-swipe-item v-for="item in props.swipeData" :key="item">
                <img :src="item.url" />
            </van-swipe-item>
            <!-- 自定义指示器 -->
            <template #indicator="{ active, total }">
                <div class="custom-indicator">{
   
   { active + 1 }}/{
   
   { total }}</div>
            </template>
        </van-swipe>
    </div>
</template>

<script setup>
const props = defineProps({
      
      
    swipeData: {
      
      
        type: Array,
        default: () => []
    }
})
</script>

<style lang="less" scoped>
.swipe {
      
      

    .swipeList {
      
      
        img {
      
      
            width: 100%;
        }

        .custom-indicator {
      
      
            position: absolute;
            right: 5px;
            bottom: 5px;
            padding: 2px 5px;
            font-size: 12px;
            background: rgba(0, 0, 0, 0.1);
            margin-right: 5px;
            margin-bottom: 5px;
            color: #fff;
        }
    }
}
</style>

main.js

Introduce new vant component.

reference

[Front-end debug] Carousel chart error TypeError: Cannot read properties of undefined (reading 'topModule')

Guess you like

Origin blog.csdn.net/karshey/article/details/128871178