首先安装这两个库(vue-masonry, vant2):
npm install vue-masonry --save
npm i vant@latest-v2 --save
main.js中全局注册:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import Vant from 'vant'
import 'vant/lib/index.css'
import {VueMasonryPlugin} from 'vue-masonry';
import '@/assets/global.css'
Vue.config.productionTip = false
Vue.use(Vant)
Vue.use(VueMasonryPlugin)
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
在对应组件使用:
<!--结构-->
<template>
<van-list v-model="loading" :finished="finished" finished-text="我是有底线的" @load="onLoad" :immediate-check="false">
<van-cell>
<div v-masonry transition-duration="0s" item-selector=".film-item">
<div v-masonry-tile class="film-item" v-for="(item, index) in filmList" :key="item.id">
<img :src="item.poster">
<div class="film-information-container">
<div class="film-actors-container">
<div class="film-actors">
主演:{{ filteredActors(item.actors, index) }}
</div>
</div>
<button class="buy-tickets">购票</button>
</div>
</div>
</div>
</van-cell>
</van-list>
</template>
// 状态
data() {
return {
filmList: [],
loading: false,
finished: false,
curPage: 1,
filmsTotal: 0
}
},
总体代码(要实现懒加载需要后端对接口进行分页):
<template>
<van-list v-model="loading" :finished="finished" finished-text="我是有底线的" @load="onLoad" :immediate-check="false">
<van-cell>
<div v-masonry transition-duration="0s" item-selector=".film-item">
<div v-masonry-tile class="film-item" v-for="(item, index) in filmList" :key="item.id">
<img :src="item.poster">
<div class="film-information-container">
<div class="film-actors-container">
<div class="film-actors">
主演:{{ filteredActors(item.actors, index) }}
</div>
</div>
<button class="buy-tickets">购票</button>
</div>
</div>
</div>
</van-cell>
</van-list>
</template>
<script>
import http from '@/utils/http.js';
export default {
data() {
return {
filmList: [],
loading: false,
finished: false,
curPage: 1,
filmsTotal: 0
}
},
mounted() {
http({
url: `/gateway?cityId=310100&pageNum=1&pageSize=10&type=1&k=908466`,
headers: {
'X-Host': 'mall.film-ticket.film.list'
}
}).then((res) => {
this.filmsTotal = res.data.data.total;
this.filmList = res.data.data.films;
console.log(this.filmList);
console.log(this.filmsTotal)
})
},
methods: {
// changeDetail (id) {
// this.$router.push(`/detail/${id}`)
// },
onLoad() {
console.log('到底了,需要继续加载')
// 特判,当总数据小于10条时
if (this.filmsTotal <= 10 && this.filmsTotal !== 0) {
this.finished = true
return
}
// 判断当前页数是否等于总页数,并且初始长度不等于0,防止从详情页返回出现bug,造成误判
if (this.curPage === Math.ceil(this.filmsTotal / 10) && this.filmsTotal !== 0) {
this.finished = true
return
}
this.curPage++
http({
url: `/gateway?cityId=310100&pageNum=${this.curPage}&pageSize=10&type=1&k=908466`,
headers: {
'X-Host': 'mall.film-ticket.film.list'
}
}).then((res) => {
this.filmList = this.addNewFilmItems(res.data.data.films);
this.filmsTotal = res.data.data.total
this.loading = false
console.log(this.filmList);
})
},
addNewFilmItems(newFilmList) {
return this.filmList.concat(newFilmList);
},
filteredActors(actors, index) {
const actorsName = actors.map((item) => {
return item = item.name;
});
return actorsName.join(' ');
}
}
}
</script>
<style lang="scss" scoped>
.van-cell {
padding: 0.25rem 0.3rem 0.25rem 0.3rem;
}
.film-item {
background: white;
margin: 0.5rem;
width: calc((100% - 2rem) / 2);
border-radius: 0.35rem;
box-shadow: 0 0 0 0.05rem #e7e7e7;
img {
width: 100%;
object-fit: cover;
border-radius: 0.35rem 0.35rem 0rem 0rem;
}
.film-information-container {
margin: 0.45rem 0.25rem 0.45rem 0.25rem;
.film-actors-container {
font-size: 0.777rem;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
/* 这里是超出几行省略 */
-webkit-line-clamp: 2;
overflow: hidden;
margin: 0 0 0.5rem 0;
}
.buy-tickets {
background: #6b78fb;
font-size: 0.666rem;
color: white;
width: 80%;
height: 1.2rem;
border-radius: 0.6rem;
border-style: none;
transform: translateX(12.5%);
}
}
}
</style>