追加图片+乱序图片+重置

200 阅读1分钟
 

css部分

<style>
* {
margin: 0;
box-sizing: border-box;
padding: 0;
}

body {
max-width: 500px;
margin: auto;
}

.loading {
margin: 12px;
text-align: center;
}

.action {
margin: 12px;
text-align: center;
}

.action button {
margin-right: 8px;
}

.link {
display: block;
padding: 8px;
text-align: center;
color: red;
}

.wrap {
display: flex;
flex-wrap: wrap;
column-count: 4;
}

.img-wrap {
width: 25%;
padding: 8px;
}

.img {
width: 100%;
height: 200px;
border-radius: 8px;
object-fit: cover;
}

.move {
transition: transform 1s;
}

[v-cloak] {
display: none;
}
</style>


body部分

 <div id="app" v-cloak>
<div class="action">
<button @click="add">
<span v-show="adding">下载中……</span>
<span v-show="!adding">追加图片</span>
</button>
<button @click="shuffle">乱序图片</button>
<button @click="reset">重置</button>
</div>
<div v-if="loading" class="loading">正在加载图片……</div>
<div v-else class="wrap">
<div class="img-wrap" v-for="src in imgs" :key="src">
<img ref="imgs" class="img" :src="src" />
</div>
</div>
</div>



<script>

let initialGetSister = getSisterGenerator()
new Vue({
el: "#app",
data() {
return {
adding: false,
loading: false,
getSister: initialGetSister,
imgs: [],
imgHeights: [],
imgsLoaded: false,
leftImgIndexes: [],
rightImgIndexes: [],
}
},
async created() {
this.loading = true
const imgs = this.getSister()
await preload(imgs)
this.imgs = imgs
this.loading = false
},
methods: {
async add() {
if (this.adding) {
return
}

this.adding = true
const newData = this.getSister()
await preload(newData)
this.adding = false

this.scheduleAnimation(() => {
this.imgs = newData.concat(this.imgs)
})
},
shuffle() {
this.scheduleAnimation(() => {
this.imgs = shuffle(this.imgs)
})
},
scheduleAnimation(update) {
// 获取旧图片的位置
const prevImgs = this.$refs.imgs.slice()
const prevSrcRectMap = createSrcRectMap(prevImgs)
// 更新数据
update()
// DOM更新后
this.$nextTick(() => {
const currentSrcRectMap = createSrcRectMap(prevImgs)
Object.keys(prevSrcRectMap).forEach((src) => {
const currentRect = currentSrcRectMap[src]
const prevRect = prevSrcRectMap[src]

const invert = {
left: prevRect.left - currentRect.left,
top: prevRect.top - currentRect.top,
}

const keyframes = [
{
transform: `translate(${invert.left}px, ${invert.top}px)`,
},
{ transform: "translate(0, 0)" },
]
const options = {
duration: 300,
easing: "cubic-bezier(0,0,0.32,1)",
}

const animation = currentRect.img.animate(keyframes, options)
})
})
},
reset() {
this.getSister = getSisterGenerator()
this.imgs = this.getSister()
},
},
})

function createSrcRectMap(imgs) {
return imgs.reduce((prev, img) => {
const rect = img.getBoundingClientRect()
const { left, top } = rect
prev[img.src] = { left, top, img }
return prev
}, {})
}
</script>

需要引入的部分

<script src="./web-animation-polyfill.js"></script>
<script src="./vue.js"></script>
<script src="./util.js"></script>
<script src="./mock.js"></script>

其中的图片在mock.js部分