前言
需要实现一个图片+视频的瀑布流效果,使用了vue3+Masonry库进行实现,这是一个关于调用AI提供接口(聚合起来)再实现一个二次AI的平台
效果

开始
1.安装
npm install masonry-layout
2.代码实现
<script setup lang="ts">
import { reactive, ref, watch, onMounted, nextTick } from "vue";
import Masonry from "masonry-layout";
/**
* 图片瀑布流
*/
const gridRef = ref(null);
let msnry = null;
// 初始化 Masonry
const initMasonry = async () => {
console.log("====initMasonry======");
await nextTick();
if (!gridRef.value) return;
msnry = new Masonry(gridRef.value, {
itemSelector: ".i-c-card",
columnWidth: 224,
gutter: 5,
fitWidth: false,
// 水平排序
horizontalOrder: true,
// 取消掉左上角动画
transitionDuration: 0,
});
};
// 监听数据变化[更新布局]
watch(
() => dataImgArr.value,
async () => {
await nextTick();
if (msnry) {
msnry.reloadItems();
msnry.layout();
}
},
{ deep: true },
);
// 图片|视频加载好调用msnry.layout
const relayout = () => {
if (msnry) {
msnry.layout();
}
};
// 页面渲染完执行initMasonry
onMounted(() => {
initMasonry();
});
</script>
<template>
<div class="my-container">
<!-- 图片瀑布流 -->
<div class="img-container" @scroll="handleScroll">
<div class="img-content" ref="gridRef">
<template v-for="(item, key) in dataArr" :key="item.id">
<div class="i-c-card" ref="cardRef">
<div style="position: relative">
<img
v-if="item.chat_type == 'image'"
:src="item.chat_message[0]"
alt="Image"
@load="relayout"
/>
<video
v-if="item.chat_type == 'video'"
:src="item.chat_message[0]"
@loadedmetadata="relayout"
></video>
<div class="i-c-nav-content">
<div
style="
display: flex;
justify-content: center;
align-items: center;
"
>
<div class="logo">
<img :src="item.userinfo.avatar" alt="" />
</div>
<div class="title">
<span>{{ item.userinfo.nickname }}</span>
</div>
</div>
<div
v-if="item.glsquare"
style="
display: flex;
justify-content: center;
align-items: center;
"
>
<div class="btn">
<div class="content">
<img src="@assets/icons/white-watch.svg" alt="" />
<span>{{ item.glsquare.views }}</span>
</div>
</div>
<div class="btn" style="margin-left: 10px">
<div class="content">
<img src="@assets/icons/collect.svg" alt="" />
<span>{{ item.glsquare.likes }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="i-c-nan-title-content" v-if="false">
<div class="title">
<span>{{ item.glsquare.title }}</span>
</div>
</div>
</div>
</template>
</div>
</div>
<!-- end 图片瀑布流 -->
</div>
</template>
<style scoped lang="scss">
.img-container {
height: calc(100vh - 60px);
overflow-y: auto;
margin-left: 20px;
.img-content {
width: 100%;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 2px;
padding: 0px 0px;
padding-bottom: 100px; // 滚动条
.ready {
opacity: 1;
}
.i-c-card::after {
content: "";
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0);
transition: all 0.25s ease;
pointer-events: none;
}
.i-c-card:hover::after {
background: rgba(0, 0, 0, 0.4);
}
.i-c-card:hover {
// transform: translateY(-6px);
box-shadow:
0 12px 30px rgba(0, 0, 0, 0.18),
0 4px 10px rgba(0, 0, 0, 0.12);
}
.i-c-card:hover .i-c-nav-content {
z-index: 9;
}
.i-c-card:hover .i-c-nan-title-content {
z-index: 9;
}
.i-c-card {
overflow: hidden;
display: flex;
flex-direction: column;
//width: 100%;
width: 224px;
// width: calc((100vw - 280px) / 8);
border-radius: 8px;
margin-bottom: 10px;
//background-color: red;
//height: auto;
img {
cursor: pointer;
width: 100%;
height: auto;
display: block;
object-fit: cover;
}
video {
cursor: pointer;
width: 100%;
height: auto;
display: block;
object-fit: cover;
}
.i-c-nan-title-content {
padding: 10px 20px;
display: flex;
align-items: center;
border: 1px solid rgba(38, 38, 38, 1);
border-top: 0;
background-color: rgba(23, 23, 23, 1);
color: rgba(196, 199, 200, 1);
font-size: 12px;
.title {
width: 200px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
.i-c-nav-content {
width: 100%;
position: absolute;
bottom: 5px;
padding: 0px 20px;
display: flex;
align-items: center;
justify-content: space-between;
.i-c-n-li {
flex: 1;
}
.logo {
width: 24px;
img {
width: 24px;
height: 24px;
border-radius: 100%;
}
}
.title {
width: 80px;
margin-left: 4px;
margin-right: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 10px;
color: rgba(255, 253, 253, 1);
}
.btn {
//background-color: rgba(217, 217, 217, 0.8);
border-radius: 10px;
padding: 5px 5px;
img {
width: 12px;
height: 12px;
margin-right: 2px;
}
.content {
display: flex;
justify-content: center;
align-items: center;
span {
margin-left: 5px;
font-size: 14px;
}
}
}
}
}
}
@media (max-width: 1600px) {
.img-content {
grid-template-columns: repeat(5, 1fr);
}
}
@media (max-width: 1400px) {
.img-content {
grid-template-columns: repeat(4, 1fr);
}
}
@media (max-width: 1100px) {
.img-content {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 768px) {
.img-content {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 480px) {
.img-content {
grid-template-columns: repeat(1, 1fr);
}
}
}
</style>
只能提供大概得代码模板,仅供参考
总结
1.先安装npm install masonry-layout
2.查看它的配置参数
3.代码实现

367

被折叠的 条评论
为什么被折叠?



