文章目录
- 目标
- 过程与代码
- 房东介绍landlord
- 热门评论HotComment
- 预定须知Book
- 效果
- 总代码
- 修改或添加的文件
- detail.vue
- detail-book.vue
- detail-hotComment.vue
- detail-landlord.vue
- 参考
本项目博客总结:【前端】Vue项目:旅游App-博客总结
目标
根据detail页面获得的数据完成房东介绍、热门评论和预定须知模块。
房东介绍:
热门评论:
预定须知:
过程与代码
房东介绍landlord
目标:
相关数据:
数据对应:
ps:后来发现这个V4房东是固定的背景,不是businessType:https://pic.tujia.com/upload/festatic/crn/v4landlord.png
传入数据:
<!-- 房东介绍 -->
<detailSection :header-text="'房东介绍'" :more-text="'房东主页'">
<detailLandlord :landlord-module="detailData.mainPart.dynamicModule.landlordModule"/>
</detailSection>
在控制台把数据打印出来:
根据数据写html:
<template>
<div class="landlord">
<div class="bg">
<img src="https://pic.tujia.com/upload/festatic/crn/v4landlord.png" alt="">
</div>
<div class="hotelInfo">
<div class="logo">
<img :src="props.landlordModule.hotelLogo" alt="">
</div>
<div class="name">
<div class="name1">{{ props.landlordModule.hotelName }}</div>
<div class="nameInfo">
<template v-for="(item, index) in props.landlordModule.hotelTags" :key="index">
<div class="separate" v-if="index !== 0" :style="{ color: item.tagText.color }">|</div>
<div class="text" :style="{ color: item.tagText.color }">{{ item.tagText.text }}</div>
</template>
</div>
</div>
<div class="button">
<span>联系房东</span>
</div>
</div>
<div class="summary">
<template v-for="(item, index) in props.landlordModule.hotelSummary" :key="index">
<div class="title">{{ item.title }}</div>
<div class="intro">{{ item.introduction }}</div>
<div class="tip">{{ item.tip }}</div>
</template>
</div>
</div>
</template>
<script setup>
const props = defineProps({
landlordModule: {
type: Object,
default: () => ({})
}
})
console.log(props.landlordModule)
</script>
效果:
加上样式css:
.landlord {
.bg {
img {
width: 100%;
}
}
.hotelInfo {
display: flex;
justify-content: left;
align-items: center;
padding: 16px 0;
.logo {
img {
width: 54px;
height: 54px;
}
}
.name {
margin-left: 12px;
margin-right: 16px;
.name1 {
font-weight: 700;
font-size: 16px;
color: #333;
}
.nameInfo {
display: flex;
align-items: center;
margin-top: 5px;
font-size: 12px;
.separate {
padding: 0 2px;
}
}
}
.button {
width: 72px;
height: 24px;
// 垂直水平居中
line-height: 24px;
text-align: center;
background-image: var(--theme-linear-gradient);
color: #fff;
font-weight: 600;
font-size: 12px;
border-radius: 4px;
}
}
.summary {
display: flex;
justify-content: space-between;
align-items: center;
padding: 22px 0 20px 0;
.item {
display: flex;
flex-direction: column;
}
.title {
color: #999;
font-size: 12px;
}
.intro {
color: #333;
font-weight: 700;
font-size: 18px;
margin: 4px 0 2px 0;
}
.tip {
color: #666;
font-size: 12px;
}
}
}
效果:
热门评论HotComment
相关数据:
在控制台打印数据:
数据的对应:
根据数据写html:
<template>
<div class="Comment">
<div class="info">
<div class="summary">
<div class="overall">{{ props.hotComment.overall }}</div>
<div class="scoreTitle">{{ props.hotComment.scoreTitle }}</div>
<div class="totalCount">{{ props.hotComment.totalCount }}条评论</div>
<div class="star">
<van-rate v-model="starValue" readonly allow-half />
</div>
</div>
<div class="summaryTag">
<template v-for="(item, index) in props.hotComment.subScores" :key="index">
<div>{{ item }}</div>
</template>
</div>
</div>
<div class="tag">
<template v-for="(item, index) in props.hotComment.commentTagVo" :key="index">
<div class="item" :style="{ color: item.color, backgroundColor: item.backgroundColor }">{{ item.text }}</div>
</template>
</div>
<div class="comment">
<div class="user">
<div class="img">
<img :src="props.hotComment.comment.userAvatars" alt="">
</div>
<div class="name">
<div class="userName">{{ props.hotComment.comment.userName }}</div>
<div class="time">{{ props.hotComment.comment.checkInDate }}</div>
</div>
</div>
<div class="content">
{{ props.hotComment.comment.commentDetail }}
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const props = defineProps({
hotComment: {
type: Object,
default: () => ({})
}
})
const starValue = ref(props.hotComment.overall);
console.log(props.hotComment)
</script>
效果:
加上样式:
.Comment {
.info {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 13px;
.summary {
display: flex;
align-items: center;
justify-content: left;
.overall {
font-size: 48px;
font-weight: 700;
color: #333;
text-decoration: underline var(--primary-color);
}
.otherComment {
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 10px;
.scoreTitle {
font-size: 12px;
color: #333;
margin-bottom: 3px;
}
.totalCount {
font-size: 12px;
color: #999;
margin-bottom: 3px;
}
}
}
.summaryTag {
display: grid;
grid-template-columns: auto auto;
color: #999;
font-size: 12px;
.item2 {
margin: 0 2px 2px 0;
}
}
}
.tag {
display: flex;
flex-wrap: wrap;
margin: 3px 0;
.item {
font-size: 12px;
margin: 0 4px 4px 0;
padding: 4px 8px;
border-radius: 7px;
}
}
.comment {
background-color: #f7f9fb;
margin: 8px 0 0;
padding: 12px;
.user {
display: flex;
justify-content: left;
align-items: center;
.img {
width: 40px;
img {
width: 100%;
border-radius: 50%;
}
}
.name {
display: flex;
flex-direction: column;
justify-content: flex-start;
margin-left: 5px;
.userName {
font-weight: 600;
color: #333;
margin-bottom: 3px;
}
.time {
color: #999;
}
}
}
.content {
color: #333;
font-size: 12px;
margin: 10px 0;
}
}
}
效果:
预定须知Book
相关数据:
数据对应:
在控制台打印数据:
根据数据搭建html:
<template>
<div class="book">
<div class="order">
<template v-for="(item, index) in props.book.orderRules" :key="index">
<div class="item">
<div class="title">{{ item.title }}</div>
<div class="if" v-if="item.icon !== null" :style="{ backgroundColor: item.color, color: '#fff' }">{{
item.icon
}}</div>
<div class="content">{{ item.introduction }}</div>
</div>
</template>
</div>
<div class="cancel">
<template v-for="(item, index) in props.book.cancelRules" :key="index">
<div class="content">
<div class="introduction">{{ item.introduction }}</div>
<div class="tip" :style="{ color: item.tipColor, backgroundColor: item.backColor }">{{ item.tip }}
</div>
</div>
</template>
</div>
<div class="checkIn">
<div class="item">
<div class="title">{{ props.book.checkInRules[0].title }}</div>
<div class="content">
<template v-for="(item, index) in props.book.checkInRules[0].items" :key="index">
<div class="content-item">
<div class="icon">
<div v-if="item.isDeleted">
<van-icon name="close" />
</div>
<div v-else="item.isDeleted">
<van-icon name="passed" />
</div>
</div>
<div class="text">{{ item.introduction }}</div>
</div>
</template>
</div>
</div>
</div>
<div class="checkOther">
<div class="item">
<div class="title" v-if="props.book.checkinOtherInfo[0].title!==null">{{ props.book.checkinOtherInfo.title }}</div>
<div class="content">
<template v-for="(item,index) in props.book.checkinOtherInfo[0].items" :key="index">
{{ item.introduction }}
</template>
</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
book: {
type: Object,
default: () => ({})
}
})
console.log(props.book)
</script>
<style lang="less" scoped>
</style>
效果:
加上样式:
.item {
display: flex;
align-items: center;
margin-top: 20px;
font-size: 12px;
line-height: 15px;
.title {
color: #666;
width: 64px;
height: 15px;
}
.content {
color: #333;
}
}
.book {
.order {
.if {
margin-right: 4px;
padding: 1px 4px;
border-radius: 3px;
}
}
.checkIn {
.content2 {
display: grid;
grid-template-columns: 100% 100%;
.content-item {
display: flex;
margin-bottom: 5px;
.icon {
margin-right: 3px;
}
}
}
}
.checkOther{
.content{
color: #666;
}
}
}
效果
总代码
修改或添加的文件
detail.vue
房屋详情页总页。
<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 class="info">
<detailInfo :house-info="detailData.mainPart.topModule" />
</div>
<!-- 内容 -->
<detailSection :header-text="'房屋设施'" :more-text="'全部房屋设施'">
<!-- 插槽内容 -->
<detailFacility :houseFacility="detailData.mainPart.dynamicModule.facilityModule.houseFacility" />
</detailSection>
<!-- 房东介绍 -->
<detailSection :header-text="'房东介绍'" :more-text="'房东主页'">
<detailLandlord :landlord-module="detailData.mainPart.dynamicModule.landlordModule" />
</detailSection>
<!-- 热门评论 -->
<detailSection :header-text="'热门评论'" :more-text="'全部'+detailData.mainPart.dynamicModule.commentModule.totalCountStr+'条评论'">
<detailHotComment :hot-comment="detailData.mainPart.dynamicModule.commentModule" />
</detailSection>
<!-- 预定须知 -->
<detailSection :header-text="'预定须知'">
<detailBook :book="detailData.mainPart.dynamicModule.rulesModule"/>
</detailSection>
</div>
</div>
</template>
<script setup>
import useDetailStore from '@/store/modules/detail';
import detailSwipe from '../detail/cpns/detail-swipe.vue'
import detailInfo from './cpns/detail-info.vue';
import detailSection from '@/components/detail-section/detail-section.vue';
import detailFacility from './cpns/detail-facility.vue';
import detailLandlord from './cpns/detail-landlord.vue';
import detailHotComment from './cpns/detail-hotComment.vue';
import detailBook from './cpns/detail-book.vue';
import { useRoute } from 'vue-router';
import { storeToRefs } from 'pinia';
// const
const detailStore = useDetailStore()
const route = useRoute()
// 返回导航栏
const onClickLeft = () => history.back();
// 相关参数:在store前
const houseId = route.params.id
// store
detailStore.fetchDetailData(houseId)
const { detailData } = storeToRefs(detailStore)
</script>
<style lang="less" scoped>
.detail {
.info {
margin: 9px;
}
}
</style>
detail-book.vue
预定须知组件。
<template>
<div class="book">
<div class="order">
<template v-for="(item, index) in props.book.orderRules" :key="index">
<div class="item">
<div class="title">{{ item.title }}</div>
<div class="if" v-if="item.icon !== null" :style="{ backgroundColor: item.color, color: '#fff' }">{{
item.icon
}}</div>
<div class="content">{{ item.introduction }}</div>
</div>
</template>
</div>
<div class="checkIn">
<div class="item">
<div class="title">{{ props.book.checkInRules[0].title }}</div>
<div class="content">
<div class="content2">
<template v-for="(item, index) in props.book.checkInRules[0].items" :key="index">
<div class="content-item">
<div class="icon">
<div v-if="item.isDeleted">
<van-icon name="close" color="#ff6666" />
</div>
<div v-else="item.isDeleted">
<van-icon name="passed" color="#17d2bc" />
</div>
</div>
<div class="text">{{ item.introduction }}</div>
</div>
</template>
</div>
</div>
</div>
</div>
<div class="checkOther">
<div class="item">
<div class="title" v-if="props.book.checkinOtherInfo[0].title !== null">{{
props.book.checkinOtherInfo.title
}}</div>
<div class="title" v-else > </div>
<div class="content">
<template v-for="(item, index) in props.book.checkinOtherInfo[0].items" :key="index">
{{ item.introduction }}
</template>
</div>
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
book: {
type: Object,
default: () => ({})
}
})
console.log(props.book)
</script>
<style lang="less" scoped>
.item {
display: flex;
align-items: center;
margin-top: 20px;
font-size: 12px;
line-height: 15px;
.title {
color: #666;
width: 64px;
height: 15px;
}
.content {
color: #333;
}
}
.book {
.order {
.if {
margin-right: 4px;
padding: 1px 4px;
border-radius: 3px;
}
}
.checkIn {
.content2 {
display: grid;
grid-template-columns: 100% 100%;
.content-item {
display: flex;
margin-bottom: 5px;
.icon {
margin-right: 3px;
}
}
}
}
.checkOther{
.content{
color: #666;
}
}
}
</style>
detail-hotComment.vue
热门评论组件。
<template>
<div class="Comment">
<div class="info">
<div class="summary">
<div class="overall">{{ props.hotComment.overall }}</div>
<div class="otherComment">
<div class="scoreTitle">{{ props.hotComment.scoreTitle }}</div>
<div class="totalCount">{{ props.hotComment.totalCount }}条评论</div>
<div class="star">
<van-rate v-model="starValue" readonly allow-half size="10px" color="var(--primary-color)" />
</div>
</div>
</div>
<div class="summaryTag">
<template v-for="(item, index) in props.hotComment.subScoresFocus" :key="index">
<div class="item2">{{ item.text }}</div>
</template>
</div>
</div>
<div class="tag">
<template v-for="(item, index) in props.hotComment.commentTagVo" :key="index">
<div class="item" :style="{ color: item.color, backgroundColor: item.backgroundColor }">{{ item.text }}
</div>
</template>
</div>
<div class="comment">
<div class="user">
<div class="img">
<img :src="props.hotComment.comment.userAvatars" alt="">
</div>
<div class="name">
<div class="userName">{{ props.hotComment.comment.userName }}</div>
<div class="time">{{ props.hotComment.comment.checkInDate }}</div>
</div>
</div>
<div class="content">
{{ props.hotComment.comment.commentDetail }}
</div>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
const props = defineProps({
hotComment: {
type: Object,
default: () => ({})
}
})
const starValue = ref(props.hotComment.overall);
// console.log(props.hotComment)
</script>
<style lang="less" scoped>
.Comment {
.info {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 13px;
.summary {
display: flex;
align-items: center;
justify-content: left;
.overall {
font-size: 48px;
font-weight: 700;
color: #333;
text-decoration: underline var(--primary-color);
}
.otherComment {
display: flex;
flex-direction: column;
justify-content: space-between;
margin-left: 10px;
.scoreTitle {
font-size: 12px;
color: #333;
margin-bottom: 3px;
}
.totalCount {
font-size: 12px;
color: #999;
margin-bottom: 3px;
}
}
}
.summaryTag {
display: grid;
grid-template-columns: auto auto;
color: #999;
font-size: 12px;
.item2 {
margin: 0 2px 2px 0;
}
}
}
.tag {
display: flex;
flex-wrap: wrap;
margin: 3px 0;
.item {
font-size: 12px;
margin: 0 4px 4px 0;
padding: 4px 8px;
border-radius: 7px;
}
}
.comment {
background-color: #f7f9fb;
margin: 8px 0 0;
padding: 12px;
.user {
display: flex;
justify-content: left;
align-items: center;
.img {
width: 40px;
img {
width: 100%;
border-radius: 50%;
}
}
.name {
display: flex;
flex-direction: column;
justify-content: flex-start;
margin-left: 5px;
.userName {
font-weight: 600;
color: #333;
margin-bottom: 3px;
}
.time {
color: #999;
}
}
}
.content {
color: #333;
font-size: 12px;
margin: 10px 0;
}
}
}
</style>
detail-landlord.vue
房东介绍组件。
<template>
<div class="landlord">
<div class="bg">
<img src="https://pic.tujia.com/upload/festatic/crn/v4landlord.png" alt="">
</div>
<div class="hotelInfo">
<div class="logo">
<img :src="props.landlordModule.hotelLogo" alt="">
</div>
<div class="name">
<div class="name1">{{ props.landlordModule.hotelName }}</div>
<div class="nameInfo">
<template v-for="(item, index) in props.landlordModule.hotelTags" :key="index">
<div class="separate " v-if="index !== 0" :style="{ color: item.tagText.color }">|</div>
<div class="text " :style="{ color: item.tagText.color }">{{ item.tagText.text }}</div>
</template>
</div>
</div>
<div class="button">
<span>联系房东</span>
</div>
</div>
<div class="summary">
<template v-for="(item, index) in props.landlordModule.hotelSummary" :key="index">
<div class="item">
<div class="title">{{ item.title }}</div>
<div class="intro">{{ item.introduction }}</div>
<div class="tip">{{ item.tip }}</div>
</div>
</template>
</div>
</div>
</template>
<script setup>
const props = defineProps({
landlordModule: {
type: Object,
default: () => ({})
}
})
// console.log(props.landlordModule)
</script>
<style lang="less" scoped>
.landlord {
.bg {
img {
width: 100%;
}
}
.hotelInfo {
display: flex;
justify-content: left;
align-items: center;
padding: 16px 0;
.logo {
img {
width: 54px;
height: 54px;
}
}
.name {
margin-left: 12px;
margin-right: 16px;
.name1 {
font-weight: 700;
font-size: 16px;
color: #333;
}
.nameInfo {
display: flex;
align-items: center;
margin-top: 5px;
font-size: 12px;
.separate {
padding: 0 2px;
}
}
}
.button {
width: 72px;
height: 24px;
// 垂直水平居中
line-height: 24px;
text-align: center;
background-image: var(--theme-linear-gradient);
color: #fff;
font-weight: 600;
font-size: 12px;
border-radius: 4px;
}
}
.summary {
display: flex;
justify-content: space-around;
align-items: center;
padding: 22px 0 20px 0;
.item {
display: flex;
flex-direction: column;
}
.title {
color: #999;
font-size: 12px;
}
.intro {
color: #333;
font-weight: 700;
font-size: 18px;
margin: 4px 0 2px 0;
}
.tip {
color: #666;
font-size: 12px;
}
}
}
</style>
参考
html图像和屏幕一样宽_林小李的博客-CSDN博客_html图片宽度和页面一样宽
css里面div如何居中显示文字-css教程-PHP中文网
CSS text-decoration 属性 | 菜鸟教程 (runoob.com)
最强大的 CSS 布局 —— Grid 布局 - 掘金 (juejin.cn)
CSS Grid 网格布局教程 - 阮一峰的网络日志 (ruanyifeng.com)