Usedcar.vue
<template>
<div class="usedcar">
<div class="usedcar_regular" ref="regular">
<div class="usedcar_top">
<img src="../assets/usedcar/left.jpg" class="usedcar_top_left" />
<div class="usedcar_top_content">
<div class="usedcar_top_content_left">
<div class="registration">上牌</div>
<div>北京</div>
<img src="../assets/usedcar/downarrow.jpg" alt="" srcset="" />
</div>
<input type="text" class="input" placeholder="搜索品牌车系/价格" />
<img src="../assets/usedcar/search.jpg" class="usedcar_top_content_search" />
</div>
<img src="../assets/usedcar/qiehuan.jpg" class="usedcar_top_right" />
</div>
<div class="usedcar_title">
<div>
综合排序
<img src="../assets/usedcar/down.jpg" class="usedcar_title_down" />
</div>
<div>
品牌
<img src="../assets/usedcar/down.jpg" class="usedcar_title_down" />
</div>
<div>
价格
<img src="../assets/usedcar/down.jpg" class="usedcar_title_down" />
</div>
<div>
筛选
<img src="../assets/usedcar/screen.jpg" class="usedcar_title_downscreen" />
</div>
</div>
</div>
<div class="usedcar_content" ref="page">
<div class="usedcar_content_rate">
<div>5万以下</div>
<div>5-10万</div>
<div>10-15万</div>
<div>15-20万</div>
<div>20万以上</div>
</div>
<div class="usedcar_content_details" >
<div class="usedcar_content_details_content" v-for="item in carList" :key="item.ID" >
<img :src="setImage(item)" class="car" @error="onError(item)" />
<div class="usedcar_content_details_content_right">
<div class="car-title">
<i>{{ item.tit_con }}</i
><br />
宝马17款
</div>
<div class="car_content">
<div class="car_content_registration">2022年上牌</div>
<div class="car_content_kilometer">1.2万公里</div>
</div>
<div class="cat_bottom">
<div class="cat_bottom_num">
<i>17.6w</i
>万 首付 3.4 万
</div>
<!-- <div class="collect">♥</div> -->
<img src="../assets/usedcar/collection.jpg" alt="" />
</div>
</div>
</div>
</div>
<div class="loading">Loading...</div>
</div>
<div class="usedcar-shadow" v-if="shadowShow">
加载中...
</div>
</div>
</template>
<script setup lang="ts">
import {useCarStore} from '@/store'
import { storeToRefs } from 'pinia';
const carStore=useCarStore();
const {setImage,onError}=carStore;
const {carList,shadowShow,page,regular}=storeToRefs(carStore);
</script>
<style scoped lang="less">
.usedcar {
width: 100%;
height: 100%;
background-color: #f5f5f6;
.usedcar-shadow{
width:100vw;
height:100vh;
position:fixed;
left:0;
top:0;
background:#fff;
line-height:100vh;
text-align:center;
}
.usedcar_regular {
width: 100%;
height: 188px;
position: fixed;
background-color: #f5f5f6;
.usedcar_top {
display: flex;
justify-content: space-between;
padding: 0 30px;
box-sizing: border-box;
height: 96px;
width: 100%;
align-items: center;
.usedcar_top_left {
height: 36px;
width: 21px;
}
.usedcar_top_content {
width: 571px;
height: 65px;
background-color: #ffffff;
border-radius: 50px;
display: flex;
position: relative;
.usedcar_top_content_left {
width: 161px;
height: 65px;
font-size: 22px;
line-height: 65px;
padding-left: 24px;
box-sizing: border-box;
align-items: center;
display: flex;
.registration {
color: #787878;
padding-right: 10px;
}
img {
width: 11px;
height: 7px;
padding-left: 12px;
}
}
.usedcar_top_content_left::after {
content: '';
width: 2px;
height: 23px;
background-color: #ececec;
margin-left: 14px;
}
.input {
width: 360px;
height: 65px;
border: 0;
outline: none;
font-size: 21px;
padding-left: 19px;
box-sizing: border-box;
}
::placeholder {
color: #b9b9b9;
}
.usedcar_top_content_search {
width: 25px;
height: 25px;
position: absolute;
top: 19px;
right: 25px;
}
}
.usedcar_top_right {
height: 39px;
width: 39px;
}
}
.usedcar_title {
width: 100%;
background-color: #fff;
height: 92px;
border-top-right-radius: 20px;
border-top-left-radius: 20px;
display: flex;
justify-content: space-between;
padding-right: 59px;
padding-left: 29px;
box-sizing: border-box;
font-size: 24px;
align-items: center;
img {
vertical-align: middle;
margin-left: 13px;
}
.usedcar_title_down {
width: 11px;
height: 8px;
}
.usedcar_title_downscreen {
width: 16px;
height: 17px;
}
}
}
.usedcar_content {
width: 100%;
height: 101%;
padding-top: 188px;
box-sizing: border-box;
background-color: white;
.usedcar_content_rate {
height: 120px;
width: 100%;
display: flex;
justify-content: space-between;
box-sizing: border-box;
padding-left: 22px;
div {
width: 138px;
height: 87px;
border: 2px solid #ededee;
border-radius: 25px;
font-size: 21px;
color: #282828;
text-align: center;
line-height: 87px;
margin-right: 14px;
}
}
.loading{
padding-top: 20px;
}
.usedcar_content_details {
width: 100%;
background-color: white;
// padding-top: 33px;
box-sizing: border-box;
.usedcar_content_details_content {
display: flex;
justify-content: space-between;
padding-left: 18px;
box-sizing: border-box;
padding-right: 40px;
padding-bottom: 60px;
height:257px;
.car {
width: 263px;
height: 197px;
}
.usedcar_content_details_content_right {
width: 407px;
height: 197px;
display: flex;
justify-content: space-between;
flex-direction: column;
.car-title {
font-size: 23px;
color: #1f1f1f;
i {
display: inline-block;
font-style: normal;
font-size: 25px;
font-weight: 900px;
margin: 10px 0;
color: #020202;
}
}
.car_content {
margin-top: 30px;
height: 32px;
display: flex;
.car_content_registration {
width: 135px;
height: 32px;
border: 2px solid #dfdfdf;
color: #575757;
font-size: 18px;
text-align: center;
line-height: 32px;
border-radius: 8px;
}
.car_content_kilometer {
width: 113px;
height: 32px;
border: 2px solid #dfdfdf;
color: #575757;
font-size: 18px;
text-align: center;
line-height: 32px;
border-radius: 8px;
margin-left: 6px;
}
}
.cat_bottom {
display: flex;
justify-content: space-between;
align-items: flex-end;
color: #eb6429;
font-size: 21px;
i {
font-style: normal;
font-size: 25px;
}
img {
width: 32px;
height: 28px;
}
// .collect {
// font-size: 32px;
// color: #e4e4e4;
// }
}
}
}
}
}
}
</style>
UsedCar.ts
import { defineStore } from 'pinia'
import { onMounted, reactive, toRefs } from 'vue'
import { getCarList } from '@/api'
interface iCarList {
ID: number,
tit_con: string,
img_src: string,
show?: boolean,
height?: number
}
interface iCars {
carList: iCarList[],
shadowShow: boolean,
imageCount: number,
page: HTMLDivElement | null,
regular:HTMLDivElement | null,//定位元素
pageHeight: number,
pageTop: number,
itemHeight: number,
clientHeight: number,
scrollTop: number,
pageCount: number,
titleHeight:number
}
export const useCarStore = defineStore('car', () => {
// const page = ref<HTMLDivElement>();
// 所有的对象定义的地方
const cars = reactive<iCars>({
carList: [],
shadowShow: true,
imageCount: 0,
page: null,// page父级元素
regular:null,
pageHeight: 0,
pageTop: 0,
itemHeight: 0,
clientHeight: 0,// 页面可视区高度
scrollTop: 0,// 页面滚动距离
pageCount: 1,//页码累计,
titleHeight:0
});
const onError=(item:iCarList)=>{
item.img_src=`default.gif`
}
const setImage = (item: iCarList) => {
if (item.show) {
return `http://www.ibugthree.com/${item.img_src}`
} else {
return `http://www.ibugthree.com/default.gif`
}
}
// 加载一页数据
(async () => {
cars.carList = (await getCarList({ page: `${cars.pageCount}` }));
cars.carList.forEach((item, index) => {
if (index <= 3) {
const oImage = new Image();
oImage.src = `http://www.ibugthree.com/${item.img_src}`;
oImage.onload = () => {
if (cars.imageCount == 3) {
cars.shadowShow = false;
// console.log(cars.page!.offsetHeight, 999666)
// 添加整个页面的高度
cars.titleHeight = cars.regular!.offsetHeight;
cars.pageTop = (cars.page!.children[0] as HTMLDivElement).offsetHeight+cars.titleHeight
cars.pageHeight = (cars.page!.children[1] as HTMLDivElement).offsetHeight;
// 求出每个块的高度
cars.itemHeight = cars.pageHeight / cars.carList.length;
cars.carList.forEach((item, index) => {
item.height = cars.pageTop + cars.itemHeight * index;
});
}
cars.imageCount++;
item.show = true;
}
}
});
window.onscroll = async () => {
cars.clientHeight = document.body.clientHeight || document.documentElement.clientHeight;
cars.scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// 获取一页数据
if (cars.clientHeight + cars.scrollTop === cars.page!.scrollHeight) {
cars.pageCount++;
const carList= (await getCarList({ page: `${cars.pageCount}` }));
cars.carList=cars.carList.concat(carList)
// 设置每个盒子的高度
cars.carList.forEach((item, index) => {
item.height = cars.pageTop + cars.itemHeight * index;
});
console.log(cars.carList,999666)
}
// 每条数据设置图片是否显示
cars.carList.forEach((item) => {
if (!item.show) {
if ((cars.clientHeight + cars.scrollTop >= item.height!)) {
item.show = true;
}
}
});
}
})();
// onMounted(() => {
// })
// reactive转成一个一个ref对象
return {
...toRefs(cars),
setImage,
onError
}
});
api/index.ts
import { Service } from "./request";
import {AxiosPromise} from 'axios'
interface searchConfig {
page: number | string
mod: string
}
interface getConfig {
page: number | string
}
interface Item {
ID: number
activity: string
after_sale: string
authen: string
bright_point: string
buy_time: string
car_price: string
card_time: string
color: string
decimal: string
detail_par: string
dif_cards: string
diff_coun: string
discharge: string
displacement: string
down_payments: string
drive: string
emission_standard: string
excellent_service: string
fil_engine: string
fil_gearbox: string
fil_structor: string
fueltype: string
img_src: string
insurance: string
integer: string
kilometre: string
logistics: string
manu_type: string
mileage: string
mon_price: string
nal_price: string
number: string
output_volume: string
qanda: string
seatnumber: string
service_shop: string
shopcar: string
state: boolean
tit_con: string
top: number
trait: string
transaction: string
veh_age: string
vehicle_system: string
year_mspect: string
status: number
likeIconColor: string
displayStatus: boolean
}
// 搜索接口
export function searchCar(config: searchConfig):Item[] {
const params = new URLSearchParams()
params.append('page', config.page as string);
params.append('mod', config.mod);
return Service({
url: "./api/oldcar/searchCar",
data: params
}) as AxiosPromise & Item[]
}
// 列表接口
export function getCarList(config: getConfig):Item[] {
const params = new URLSearchParams()
params.append('page', config.page as string)
return Service({
url: "/api/oldcar/getCarList",
data: params
}) as AxiosPromise & Item[]
}
api/request.ts
import axios from "axios";
export const Service = axios.create({
timeout: 80000, //延迟时间
method: 'POST',
headers: {
"content-Type": "application/x-www-form-urlencoded",
"pc-token": "4a82b23dbbf3b23fd8aa291076e660ec", //后端提供
}
})
// 请求拦截
Service.interceptors.request.use(config => {
return config
})
// 响应拦截
Service.interceptors.response.use(response => {
return response.data
}, err => {
console.log(err)
})