共计 2536 个字符,预计需要花费 7 分钟才能阅读完成。
在图片网站中,通常是应用瀑布流的形式来显示图片,等宽度不等高,这样显得错落有致
明天 应用 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…
正文完
发表至: javascript
2023-09-24