Closed DarkPage closed 5 years ago
nuxt服务端渲染的时候不能操作demo,这里有一个同原理的nuxt的demo http://collect.luzhongkuan.cn/uploadList
<template>
<div>
<message-form @refresh="fetchData"></message-form>
<div :style="{height: `${height}px`}" ref="container" class="container message-container">
<div
v-for="item in data"
:key="item.id"
ref="wrap"
:style="{opacity: isReady ? 1 : 0.1}"
class="message-item">
<div :style="{background: (item.color || 'white')}" class="paper">
<time class="time">{{ item.create_time }}</time>
<img class="message-image" v-if="item.url" :src="item.url">
<p>{{ item.message }}</p>
<div class="address">{{ item.address }}</div>
<span class="name">{{ item.name }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
import request from '~/assets/request'
import MessageForm from '~/components/messageForm'
export default {
name: 'message',
head() {
return {
title: '卢忠宽的留言'
}
},
data() {
return {
height: 0,
isReady: false,
itemWidth: 0
}
},
async asyncData() {
const { data } = await request({
url: `/api/message`,
params: { size: 1000 }
}, {isCache: false})
return { data: data.content }
},
methods: {
color() {
const colors = ['#ccf', '#cfc', '#fcc', '#ffc', '#cff', '#fcf']
return colors[Math.floor(Math.random() * colors.length)]
},
setColor() {
this.data.forEach(item => item.color = this.color())
this.data = [...this.data]
},
allReady() {
const { wrap } = this.$refs
const len = wrap.length
const promiseMap = []
for (let i = 0; i < len; i++) {
const el = wrap[i]
promiseMap.push(isReady(el))
}
return Promise.all(promiseMap)
},
getColNum() {
// 获取列数,设置容器宽度
const { container, wrap } = this.$refs
const conW = container.clientWidth
const itemW = wrap[0].clientWidth
const colNum = ~~(conW / itemW)
container.style.width = `${(colNum * itemW) || itemW}px`
this.itemWidth = itemW
return colNum
},
setPos(hMap) {
const { wrap } = this.$refs
const len = wrap.length
for (let i = 0; i < len; i++) {
// 获取最小高度对应组下标
const minHeight = Math.min(...hMap)
let minIndex = hMap.findIndex((item) => item === minHeight)
if (minIndex === -1) minIndex = 0
// 设置item位置
const el = wrap[i]
hMap[minIndex] += el.clientHeight
el.style.left = `${this.itemWidth * minIndex}px`
el.style.top = `${minHeight}px`
// 设置最外层容器高度
this.height = Math.max(...hMap)
}
},
initWaterFall() {
this.$nextTick(async () => {
// 没有数据直接返回
if (!this.data.length) return
// 再次获取宽度的时候,可以获取自适应宽度
this.$refs.container.removeAttribute('style')
// 等待图片加载
await this.allReady()
this.isReady = true
// 设置容器宽度
const colNum = this.getColNum() || 1
// 获取默认各组高度
const hMap = getDefaultHeightMap(colNum)
this.setPos(hMap)
})
},
async fetchData() {
const { data } = await request({
url: `/api/message`
}, {isCache: false})
this.data = []
this.$nextTick(() => {
this.data = data.content
this.setColor()
this.initWaterFall()
})
},
resize() {
debounce(() => {
this.initWaterFall()
})()
}
},
mounted() {
// 设置默认随机颜色
this.setColor()
// 初始化瀑布流
this.initWaterFall()
if (typeof window !== 'undefined') {
window.addEventListener('resize', this.resize)
}
},
beforeDestroy() {
if (typeof window !== 'undefined') {
window.removeEventListener('resize', this.resize)
}
},
components: {
MessageForm
}
}
// 等待图片加载完成,获取高度(在resize的时候等待图片加载),只会判断每个waterFallItem组件中,只能放一张图片
function isReady(el) {
return new Promise(resolve => {
let img
if (el.tagName === 'IMG') {
img = el
} else {
img = el.querySelector('img')
}
if (!img) {
resolve()
} else if (img.complete) {
resolve()
return
}
img.onload = resolve
img.onerror = resolve
})
}
// 获取各组默认高度 [0, 0, 0 ...]
function getDefaultHeightMap(colNum = 1, arr = []) {
if (arr.length < colNum) {
arr.push(0)
return getDefaultHeightMap(colNum, arr)
}
return arr
}
// 防抖函数
function debounce(fn, time = 300) {
if (typeof fn !== 'function') {
throw new Error('必须传入一个函数作为参数')
}
let timer
return () => {
timer && clearTimeout(timer)
timer = setTimeout(() => {
fn()
}, time)
}
}
</script>
<style lang="scss" scoped>
.message-container {
line-height: 1.3;
max-width: 1300px;
}
.paper {
width: 320px;
max-width: 100%;
min-height: 160px;
margin: 0 auto;
box-sizing: border-box;
padding: 20px 20px 36px;
box-shadow: 2px 2px 20px #ccc;
}
.paper:hover {
box-shadow: 2px 2px 40px #bbb;
}
.time {
font-size: 14px;
line-height: 24px;
}
p {
font-size: 16px;
line-height: 22px;
margin: 20px 0;
min-height: 20px;
text-indent: 1em;
}
.address {
font-size: 14px;
color: #999;
line-height: 14px;
}
.name {
float: right;
font-size: 14px;
}
.message-item {
left: 0;
top: 0;
position: absolute;
transition: left .3s, right .3s, opacity .3s;
padding: 20px;
box-sizing: border-box;
}
.message-image {
width: 100%;
}
@media (max-width: 350px) {
.message-item {
max-width: 320px;
}
}
</style>
开发时没有大问题,build后运行就报错,项目用的Nuxt 2.x版本脚手架