w-ui
Version:
A Vue.js 2.0 UI Toolkit for mobile
169 lines (166 loc) • 4.7 kB
JavaScript
import './waterfall.less'
import { addClass, removeClass } from '../../../src/utils'
export default {
name: 'w-waterfall',
props: {
items: {
type: Array
},
columns: {
default: 2,
type: Number
},
enterClass: {
type: String
}
},
data () {
let colData = []
for (let i = 0; i < this.columns; i++) {
colData.push([])
}
return {
columnData: colData,
currentIndex: 0,
currentColumn: 0,
pageIndex: 0,
columnHeight: colData.slice(0),
columnMap: {},
screenHeight: window.innerHeight,
loadedAll: false
}
},
created () {
},
mounted () {
let me = this
let move = this.getRandomName()
let end = this.getRandomName()
let scroll = this.getRandomName()
var moveFlag = false
var timer
window[move] = function (e) {
timer && clearTimeout(timer)
moveFlag = true
timer = setTimeout(window[end], 100)
}
window[scroll] = function (e) {
timer && clearTimeout(timer)
moveFlag = true
timer = setTimeout(window[end], 100)
}
window[end] = function (e) {
if (moveFlag) {
moveFlag = false
me.checkPage()
}
}
document.removeEventListener('touchmove', window[move])
document.removeEventListener('touchend', window[end])
document.addEventListener('touchmove', window[move], false)
document.addEventListener('touchend', window[end], false)
// document.body.addEventListener('scroll', window[move], false)
window.addEventListener('scroll', window[move], false)
this.nextPage()
},
watch: {
currentIndex (val, oldVal) {
(() => {
this.$nextTick(() => {
let vnode = this.$slots.default[val - 1]
addClass(vnode.elm, this.enterClass + '-before')
let imgs = vnode.elm.querySelectorAll('img')
if (imgs && imgs.length > 0) {
imgs = Array.prototype.slice.call(imgs, 0)
Promise.all(imgs.map(img => {
return new Promise((resolve, reject) => {
let timer = setTimeout(() => {
resolve(20)
}, 1000)
img.onload = () => {
clearTimeout(timer)
resolve(img.height)
removeClass(vnode.elm, this.enterClass + '-before')
addClass(vnode.elm, this.enterClass + '-after')
}
img.onerror = () => {
clearTimeout(timer)
resolve(20)
}
})
})).then((data) => {
this.computeHeight(val - 1)
})
} else {
this.computeHeight(val - 1)
}
})
})(val)
}
},
render (h) {
return (
<div class='wui-waterfall'>
<div class='waterfall-content'>
{
this.columnData.map((item, i) => (
<div class='wui-waterfall-column' key={'column-' + i}>
{
item.map(itm => this.$slots.default[itm])
}
</div>
))
}
</div>
{this.loadedAll ? (<div class='no-more'>- 没有更多了 -</div>) : ''}
</div>
)
},
methods: {
computeHeight (index) {
let col = this.columnMap[index]
let vnode = this.$slots.default[index]
let h = vnode.elm.offsetHeight
this.columnHeight[col] = parseInt(this.columnHeight[col]) + parseInt(h)
let [min, minCol] = this.getColumn()
this.currentColumn = minCol
if (min > this.pageIndex * this.screenHeight) {
} else {
this.next()
}
},
getRandomName () {
return 'func_' + (Math.random() * 1000000).toString(32) + '_' + Date.now().toString(32)
},
getColumn () {
let min = this.columnHeight[0]
let minColumn = 0
for (let i = 0; i < this.columnHeight.length; i++) {
if (this.columnHeight[i] < min) {
min = this.columnHeight[i]
minColumn = i
}
}
return [min, minColumn]
},
next () {
if (!this.loadedAll && this.currentIndex < this.$slots.default.length) {
this.columnData[this.currentColumn].push(this.currentIndex)
this.columnMap[this.currentIndex] = this.currentColumn
this.currentIndex++
} else {
this.loadedAll = true
}
},
nextPage () {
this.pageIndex++
this.next()
},
checkPage () {
let st = document.documentElement.scrollTop || document.body.scrollTop
if (st - 50 > (this.pageIndex - 1) * this.screenHeight) {
this.nextPage()
}
}
}
}