在图片网站中,通常是应用瀑布流的形式来显示图片,等宽度不等高,这样显得错落有致
明天 应用 Vue3
实现一个瀑布流组件,并公布为一个 npm
包
grid
布局- 反对响应式
参考自react-plock
1、window.matchMedia
window.matchMedia(mediaQueryString)
办法返回一个 MediaQueryList
对象,示意指定 css
媒体查问字符串的后果
其中参数 mediaQueryString
示意 CSS @media
规定的任何媒体查问选项,比方:
min-width
、min-height
、orientation
等
const media = window.matchMedia("(max-width: 850px)")
在 MediaQueryList
对象中有两个属性:
matches
:返回查问后果,是一个布尔值media
:媒体查问的字符串
所以,依据 matches
咱们就能够晓得是否命中以后的媒体查问选项
并且,咱们还能够通过 addEventListener
监听 mediaQuery
查问后果的变动
media.removeEventListener('change', () => {console.log(media.matches)
});
2、瀑布流组件
响应式管制
依据屏幕大小确定图片的列数
export interface PropConfigType {gap: number[]; // 行列的间距
columns: number[]; // 不同媒体查问选项对应的列数
medias?: number[]; // 媒体查问选项}
import {reactive, onUnmounted} from 'vue';
export function useMediaValues(config: PropConfigType) {
const info = reactive({
columns: 1,
gap: 1
});
const {columns, gap, media} = config;
if (!media) {return setInfo(0);
}
// 循环查问 medias
const mediaQueries = media.map(media =>
window.matchMedia(`(min-width: ${media}px)`)
);
const onSizeChange = () => {
// 记录匹配到的哪一个 media
let matches = 0;
mediaQueries.forEach(mediaQuery => {mediaQuery.matches && matches++;});
// 优先匹配前面的
const idx = Math.min(mediaQueries.length - 1, matches);
setInfo(idx);
};
onSizeChange();
// 监听查问后果
for (let mediaQuery of mediaQueries) {mediaQuery.addEventListener('change', onSizeChange);
}
onUnmounted(() => {for (let mediaQuery of mediaQueries) {mediaQuery.removeEventListener('change', onSizeChange);
}
});
function setInfo(idx: number) {info.columns = columns[idx];
info.gap = gap[idx];
return info;
}
return info;
}
数据结构
info.columns
计算出瀑布流的数据结构,每列为一个数组,并存储到dataColumns
通过 for
循环将 fall-row
给渲染进去
当屏幕宽度变动时,会从新计算info.columns
,失去一个新的dataColumms
,渲染等到新的瀑布流界面
// fall-row 组件
<div
:style="{
display: 'grid',
rowGap: prop.gap,
gridTemplateColumns: `minmax(0, 1fr)`
}"
>
// 用户的内容通过插槽的模式增加
<slot></slot>
</div>
// water-fall 组件
<div
:style="{
display: 'grid',
alignItems: 'start',
gridColumnGap: info.gap + 'px',
gridTemplateColumns: `repeat(${info.columns}, minmax(0, 1fr))`
}"
>
<fallRow
v-for="(columns, index) in dataColumns"
:key="index"
:gap="info.gap +'px'"
>
// 此处为作用域插槽
<slot
v-for="(src, index) in columns"
:key="index"
:src="src"
></slot>
</fallRow>
</div>
- 通过作用域插槽将图片的
src
传递给父组件
3、应用
// 导入组件
import {waterFall} from ...
<waterFall
:data="datasource"
:config="{columns: [1, 2, 3],
gap: [24, 12, 6],
medias: [640, 1024, 1280]
}"v-slot="slotProps"
>
<img
:src="slotProps.src"
:style="{width:'100%', height:'auto'}"
/>
</waterFall>
v-slot="slotProps"
拜访父组件的作用域,获取到src
进行显示
须要留神的是:columns
、gap
、medias
的个数要统一
公布 npm
包
做好工程化后,就能够通过公布为 npm
包
地址:vue3-plock
当初能够通过依赖命令来装置了
pnpm add vue3-plock
点击 codesandbox 查看线上的运行
源码曾经上传 github,欢送 start 😀😀
参考:
- https://github.com/askides/react-plock
- https://developer.mozilla.org/zh-CN/docs/Web/API/Window/match…