文章目录
目标
上一篇显示了服务器中的数据:【前端】Vue项目:旅游App-(9)city:固定tab栏、内容中显示数据
本篇目标:将数据展示成这个效果。
过程与代码
分析数据并展示
首先我们要分析要展示的数据。以国内数据为例:
数据分为cities
、hotcities
、title
。我们这里要展示的是cities
。
cities
详情:是一个数组,里面的每一个元素都是一个对象。
每个对象有两个属性:
- group:表示以本字母开头
- cities:一个数组,表示以group开头的所有城市
这就是我们要展示的数据。显然需要两层循环。
代码:
<div class="content">
<template v-for="(item,index) in currentGroup?.cities" :key="index">
<h2 class="title">
标题{{ item.group }}
</h2>
<div class="cities">
<template v-for="(itemm,indexx) in item.cities" :key="indexx">
<div class="cityName">
{{ itemm.cityName }}
</div>
</template>
</div>
</template>
</div>
效果:
封装到一个组件
为了代码的可维护性,封装一下。
currentGroupCity.vue:
<template>
<template v-for="(item, index) in currentGroup?.cities" :key="index">
<h2 class="title">
标题{{ item.group }}
</h2>
<div class="cities">
<template v-for="(itemm, indexx) in item.cities" :key="indexx">
<div class="cityName">
{{ itemm.cityName }}
</div>
</template>
</div>
</template>
</template>
<script setup>
// 定义数据currentGroup:一个对象
defineProps({
currentGroup: {
type: Object,
default: () => ({})
}
})
</script>
<style lang="less" scoped>
h2{
font-size: 20px;
font-weight: 700;
}
</style>
city.vue把数据传一下:
<div class="content">
<currentGroupCity :current-group="currentGroup"/>
</div>
添加indexBar
数据已经展示好了,我们还要添加样式。要添加的样式叫做:IndexBar 索引栏 - Vant 4 (gitee.io)
注册好后,根据indexBar的代码进行修改。
代码:
<template>
<van-index-bar>
<template v-for="(item, index) in currentGroup?.cities" :key="index">
<van-index-anchor :index="item.group" />
<template v-for="(itemm, indexx) in item.cities" :key="indexx">
<van-cell :title="itemm.cityName" />
</template>
</template>
</van-index-bar>
</template>
效果:
出了一些bug:
Failed to resolve component: van-cell
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
解决方法:【vue】Failed to resolve component: van-cell If this is a native custom element, make sure to exclude
效果:
样式修改
把颜色改成主题色橙色。具体步骤见之前的博客,不再赘述。
common.css的:root:
--van-primary-color:var(--primary-color) !important;
还有一件事:我们的滚轮往下滑的时候索引栏会被挡住:
给类top增加z-index:
.top {
position: fixed;
top: 0;
left: 0;
right: 0;
// 不被indexBar挡住
z-index: 9;
}
当然,让它被挡住也行,具体看产品的需求。这里只是写一下如果不让他被挡住的方法。
优化tab栏的切换
写到这里我们发现,每点一次tab栏的切换,数据就会重新加载。这样的效率其实是不高的。
我们可以这样做:把两份数据都写出来,用v-show显示对应的数据。就像前面对title所做的一样。
<div class="content">
<template v-for="(value, key, index) in allCity">
<currentGroupCity v-show="key===TabActive" :current-group="value" />
</template>
</div>
切换的直观感受:快了一些。虽然数据上差别不大。
效果
总代码
修改或新增的文件
common.css
修改了样式:主题颜色。
:root {
--van-primary-color:var(--primary-color) !important;
}
city.vue
显示数据。
<template>
<div class="city top-page">
<div class="top">
<!-- show-action:显示 “取消” -->
<van-search shape="round" v-model="value" show-action placeholder="城市/区域/位置" @search="onSearch"
@cancel="onCancel" />
<van-tabs v-model:active="TabActive">
<template v-for="(value, key, index) in allCity">
<van-tab :title="value.title" :name="key"></van-tab>
</template>
</van-tabs>
</div>
<div class="content">
<template v-for="(value, key, index) in allCity">
<currentGroupCity v-show="key===TabActive" :current-group="value" />
</template>
</div>
</div>
</template>
<script setup>
import { computed, ref } from 'vue';
import { showToast } from 'vant';
import useCityStore from '@/store/modules/city'
import { storeToRefs } from 'pinia';
import currentGroupCity from './cpns/currentGroupCity.vue';
const value = ref('');
const TabActive = ref(0);
const onSearch = (val) => showToast(val);
const onCancel = () => {
showToast('取消');
}
// tabs的数据
const cityStore = useCityStore()
cityStore.fetchAllCity()
// cityStore是响应式的
const { allCity } = storeToRefs(cityStore)
// console.log(allCity)
// currentGroup:当前选了哪个tab,是key值
// allCity和TabActive都是响应式,因此要用value取到值
// computed:依赖的东西改变则重新计算,相当于令currentGroup响应式,否则它是写死的(只算一次)
const currentGroup = computed(() => allCity.value[TabActive.value])
console.log(currentGroup)
</script>
<style lang="less" scoped>
.top {
position: fixed;
top: 0;
left: 0;
right: 0;
// 不被indexBar挡住
z-index: 9;
}
.content {
margin-top: 98px;
}
</style>
currentGroupCity.vue
循环显示数据的组件。
<template>
<van-index-bar>
<template v-for="(item, index) in currentGroup?.cities" :key="index">
<van-index-anchor :index="item.group" />
<template v-for="(itemm, indexx) in item.cities" :key="indexx">
<van-cell :title="itemm.cityName" />
</template>
</template>
</van-index-bar>
</template>
<script setup>
// 定义数据currentGroup:一个对象
defineProps({
currentGroup: {
type: Object,
default: () => ({})
}
})
</script>
<style lang="less" scoped>
h2 {
font-size: 20px;
font-weight: 700;
}
</style>
main.js
引入组件。