原生JavaScript 瀑布流 实现 zx-waterfall
栏目: JavaScript · 发布时间: 6年前
内容简介:源码地址:InstallES6+
源码地址: https://github.com/capricornc...
使用说明
Install zx-waterfall
using npm
npm i --save zx-waterfall
ES6+
import ZxWaterfall from 'zx-waterfall'
const waterfall = new ZxWaterfall({
// HTMLElement, waterfall items's outer container
container: document.getElementById('zxWaterfall'),
// children item selector, eg. '.item-container'
itemSelector: '.item-wrapper',
// item's spacing, unit px
gutter: 20,
// item's width
itemWidth: 300
})
// reset
waterfall.reset()
// loaMedias
waterfall.loadMedia(['http://xx.com/aaa.jpg'])
// change
waterfall.change()
browser
<script src="path/zx-waterfall.min.js"></script>
demo
https://capricorncd.github.io...
注意
-
container's style must bestyle.position=relative|absolute|fixed
参数options
-
container:
HTMLElement瀑布流外容器.
-
containerWidth:
Number瀑布流宽度,如果初始化时外容器未隐藏状态则需使用该参数.
默认获取外容器宽度.
-
itemSelector:
String子元素选择器,比如 样式名'.item-container'.
-
gutter:
Number元素间的间隔.
-
verticalGutter:
Number元素间垂直方向间隔,默认使用gutter值.
-
itemWidth:
Number元素宽度, 默认
300, 会根据容器宽度自动调整. -
forceItemWidth:
Boolean强制元素宽度,即使用itemWidth作为宽度值,默认
false. -
align:
String, Optional valueleft|center|right强制宽度时,元素显示靠边位置,默认
center.
源码
/**
* preload image
* @param url
* @param handler
*/
function loadImage (url, handler) {
let $el = document.createElement('img')
$el.src = url
$el.onload = handler
$el.onerror = handler
$el = null
}
/**
* to int
* @param m
* @returns {number}
*/
function int (m) {
let n = parseInt(m)
return isNaN(n) ? 0 : n
}
/**
* convert pseudoArray to array
* @param pseudoArray
* @param index
* @returns {T[]}
*/
function slice (pseudoArray, index) {
return Array.prototype.slice.call(pseudoArray, int(index))
}
// default options
const DEF_OPTIONS = {
// HTMLElement, waterfall items's outer container
container: null,
// container's width, container are hidden when initialized
// default get container offsetWidth when it's visible
containerWidth: 0,
// children item selector, eg. '.item-container'
itemSelector: '',
// item's spacing, unit px
gutter: 20,
// item's vertical spacing, default use gutter's value
verticalGutter: 0,
// item's width
itemWidth: 300,
// force item width
forceItemWidth: false,
// Horizontal align when forceItemWidth is true
align: 'center'
}
/**
* ZxWaterfall
*/
class ZxWaterfall {
/**
* constructor
* @param opts
*/
constructor (opts) {
opts = Object.assign({}, DEF_OPTIONS, opts)
// check container
if (!opts.container || opts.container.nodeType !== 1) {
throw new TypeError(`Instancing parameter 'container' is not HTMLElement.`)
}
// check itemSelector
if (!opts.itemSelector || typeof opts.itemSelector !== 'string') {
throw new TypeError(`Instancing parameter 'itemSelector' is null or is't a string.`)
}
// check verticalGutter
if (!opts.verticalGutter) {
opts.verticalGutter = opts.gutter
}
// item number
this.count = 0
this.opts = opts
this._init()
// clone this.reset
this._resetClone = this.reset.bind(this)
window.addEventListener('resize', this._resetClone)
}
/**
* initialization
* @private
*/
_init () {
let opts = this.opts
// container width
let containerWidth = int(opts.containerWidth) || opts.container.offsetWidth
// column number
let columnNum = Math.floor(containerWidth / (opts.itemWidth + opts.gutter))
// opts.itemWidth when opts.forceItemWidth = true
// else use compute new width
this.itemWidth = opts.forceItemWidth
? opts.itemWidth
: (containerWidth - (columnNum + 1) * opts.gutter) / columnNum
// column current height array
this.columns = Array(columnNum)
this.columns.fill(0, 0)
// offset left when forceItemWidth=true
this.offsetLeft = 0
if (opts.forceItemWidth) {
let residualSpaceWidth = containerWidth - (this.itemWidth + opts.gutter) * columnNum - opts.gutter
switch (opts.align) {
case 'center':
this.offsetLeft = residualSpaceWidth / 2
break
case 'right':
this.offsetLeft = residualSpaceWidth
break
}
}
}
/**
* set items position
* @private
*/
_setPosition () {
let opts = this.opts
// get new item elements
let $childs = slice(opts.container.querySelectorAll(opts.itemSelector), this.count)
// console.log(this.count, $childs)
let len = $childs.length
// reset this.count value
this.count += len
// handle new $item
let i, $item
for (i = 0; i < len; i++) {
$item = $childs[i]
if (!$item) continue
$item.style.position = 'absolute'
$item.style.width = this.itemWidth + 'px'
$item.style.display = 'inline-block'
// get columns min value
let min = Math.min.apply(null, this.columns)
let index = this.columns.findIndex(val => val === min)
// set $item position
$item.style.top = `${min + opts.verticalGutter}px`
$item.style.left = `${this.offsetLeft + (this.itemWidth + opts.gutter) * index + opts.gutter}px`
// reset waterfall current column height value
let itemHeight = $item.offsetHeight
this.columns[index] = min + itemHeight + opts.verticalGutter
// update container new min height style
// opts.container.style.minHeight = Math.max.apply(null, this.columns) + opts.verticalGutter + 'px'
}
}
/**
* container's items number change
*/
change () {
// reset postion, when new item element append to container, or remove
this._setPosition()
}
/**
* reset
*/
reset () {
this.count = 0
this._init()
this._setPosition()
}
/**
* preload media items
* @param arr media source urls array
* @returns {Promise<any>}
*/
loadMedia (arr) {
return new Promise(resolve => {
if (Array.isArray(arr) && arr.length) {
let len = arr.length
let count = 0
/* eslint-disable */
arr.forEach(url => {
loadImage(url, () => {
count++
if (len === count) resolve()
})
})
} else {
resolve()
}
})
}
/**
* destroy
* removeEventListener window resize
*/
destroy () {
window.removeEventListener('resize', this._resetClone)
}
}
export default ZxWaterfall
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Game Programming Patterns
Robert Nystrom / Genever Benning / 2014-11-2 / USD 39.95
The biggest challenge facing many game programmers is completing their game. Most game projects fizzle out, overwhelmed by the complexity of their own code. Game Programming Patterns tackles that exac......一起来看看 《Game Programming Patterns》 这本书的介绍吧!