1. Vue基础知识
Vue是当前十分流行的JavaScript前端框架之一。它的主要特点是组件化和响应式的数据绑定。在了解滚动和放大动画之前,我们需要先了解Vue一些基本知识。
Vue实例是Vue应用中的一个基本单位。每个Vue应用都包含一个Vue实例。Vue实例用来管理一个组件(component),它描述了组件的行为和样貌。Vue实例内的数据与DOM元素进行绑定,通过修改数据来实现界面的动态更新。这就是Vue响应式的数据绑定的实现机制。
Vue组件是Vue实例的拓展。它是Vue应用中的组成部分,可以复用和嵌套。一个Vue组件有自己的模板、数据、方法、生命周期钩子等属性。
理解Vue的基本概念对于后面的动画实现会有很好的帮助。
2. 图片滚动效果实现
2.1 滚动组件定义
为了实现图片滚动效果,我们需要通过Vue组件的方式来定义一个滚动组件。首先,在Vue应用中创建一个Vue组件:
Vue.component('scroll-box', {
template: `
<div class='scroll-box'>
<div class='scroll-content'>
<slot></slot>
</div>
</div>
`,
/*
此处省略组件其他属性
*/
});
上述代码中,我们通过Vue.component来定义了一个全新的组件scroll-box。在组件的模板中我们定义了一个具有slot的<div>
元素,用于容纳组件中嵌套的子元素。
2.2 滚动组件样式编写
接下来,我们来编写滚动组件的样式。
.scroll-box {
width: 100%;
height: 300px;
overflow: hidden;
position: relative;
border: 1px solid #ccc;
}
.scroll-content {
white-space: nowrap; //横向不换行
transition: 0.5s all cubic-bezier(0.65, 0.05, 0.36, 1);
position: absolute;
top: 0;
left: 0;
width: fit-content;
}
上述代码中,我们给组件的容器scroll-box设置了一个固定的高度,然后通过overflow属性来隐藏超出部分。我们还为.scroll-content设置了绝对定位,确保组件内容显示在滚动框内。
2.3 滚动动画实现
下面我们通过JavaScript来实现滚动动画。
export default {
name: 'ScrollBox',
data() {
return {
scrollWidth: 0, //初始化滚动内容宽度
currentX: 0, //当前滚动的位置
contentWidth: 0 //内容总宽度
};
},
methods: {
//计算内容总宽度
calculateWidth() {
this.contentWidth = this.$refs.content.scrollWidth;
},
/*
向右滚动
*/
scrollRight() {
this.currentX += this.scrollWidth;
if(this.currentX > this.contentWidth) {
//重置
this.currentX = 0;
}
this.$refs.content.style.transform = `translateX(-${this.currentX}px)`;
},
/*
向左滚动
*/
scrollLeft() {
this.currentX -= this.scrollWidth;
if(this.currentX < 0) {
//重置
this.currentX = this.contentWidth - this.scrollWidth;
}
this.$refs.content.style.transform = `translateX(-${this.currentX}px)`;
}
},
mounted() {
//获取当前组件宽度
this.scrollWidth = this.$el.clientWidth;
//计算内容总宽度
this.calculateWidth();
}
};
我们在组件的mounted钩子中获取组件的宽度,并计算滚动内容的总宽度。接下来编写scrollRight和scrollLeft两个函数对滚动内容进行向右和向左的操作。我们使用CSS的transform属性来实现滚动,指定向左滚动x像素,实现了滚动的效果。此处的.scroll-content对应了我们在组件template中的slot。
3. 实现图片放大效果
3.1 放大组件定义
为了实现图片的放大效果,我们同样需要创建一个Vue组件。
Vue.component('zoom-box', {
template: `
<div class='zoom-box' ref='zoomBox'>
<img :src="imgSrc" alt='' @mouseover='handleMouseover' @mousemove='handleMousemove' @mouseleave='handleMouseleave'>
</div>
`,
/*
此处省略组件其他属性
*/
});
上述代码中,我们定义了一个zoom-box组件。组件里面包含了一个img元素,用来展示图片。我们在img上设置了三个事件:鼠标移入事件mouseover、鼠标移动事件mousemove和鼠标移出事件mouseleave。
3.2 放大组件样式编写
.zoom-box {
cursor: zoom-in; //控制鼠标样式
overflow: hidden;
}
.zoom-box img {
width: 100%;
height: 100%;
object-fit: cover; //保持图片比例不变
transition: 0.5s all ease-in-out;
}
在上述代码中,我们设置了鼠标样式cursor,用来改变鼠标在图片上的样式。我们还设置了图片的宽和高为100%以确保图片充满画布,通过object-fit属性来保持图片比例不变,并且为图片设置了一个缩放的过渡效果。
3.3 放大效果实现
export default {
name: 'ZoomBox',
props: {
imgSrc: {
type: String,
required: true
}
},
data() {
return {
isZoomed: false,
zoomBoxWidth: 0,
zoomBoxHeight: 0
};
},
methods: {
/*
处理鼠标移动事件
*/
handleMousemove(e) {
if(this.isZoomed) {
const mx = e.pageX - this.$refs.zoomBox.offsetLeft;
const my = e.pageY - this.$refs.zoomBox.offsetTop;
const px = mx / this.zoomBoxWidth * 100;
const py = my / this.zoomBoxHeight * 100;
e.target.style.transform = `translate(-${px}%, -${py}%) scale(2)`;
}
},
/*
处理鼠标移出事件
*/
handleMouseleave() {
if(this.isZoomed) {
e.target.style.transform = `translate(-50%, -50%) scale(1)`;
}
},
/*
处理鼠标移入事件
*/
handleMouseover(e) {
this.isZoomed = true;
this.zoomBoxWidth = this.$refs.zoomBox.clientWidth;
this.zoomBoxHeight = this.$refs.zoomBox.clientHeight;
}
}
};
在方法中,handleMouseover用来处理鼠标移入事件。当鼠标移入图片区域时,将isZoomed设置为true。然后获取zoom-box元素的宽和高,并记录在zoomBoxWidth和zoomBoxHeight中。接下来,我们需要在handleMousemove中处理鼠标移动事件。我们计算出鼠标在图片内的位置,并根据鼠标位置来缩放图片,形成放大的效果。当鼠标移出图片时,我们需要在handleMouseleave中将isZoomed设置为false,并且将图片恢复到正常大小。
4. 整合滚动和放大两个组件
4.1 整合组件代码
最后,我们将滚动和放大效果整合在一起,实现一套完整的图片库效果。
Vue组件代码:
<template>
<div class='image-library'>
<scroll-box>
<div class='scroll-images'>
<zoom-box v-for='img in images' :key="img" :imgSrc="img"></zoom-box>
</div>
</scroll-box>
</div>
</template>
<script>
import ScrollBox from './ScrollBox.vue';
import ZoomBox from './ZoomBox.vue';
export default {
name: 'ImageLibrary',
components: { ScrollBox, ZoomBox },
data() {
return {
images: [] //存储所有图片的URL
};
},
computed: {
/*
模拟图片URL
*/
urls() {
return [
'https://i.picsum.photos/id/1018/500/300.jpg', 'https://i.picsum.photos/id/1038/500/300.jpg',
'https://i.picsum.photos/id/1073/500/300.jpg',
'https://i.picsum.photos/id/1080/500/300.jpg',
'https://i.picsum.photos/id/111/500/300.jpg',
'https://i.picsum.photos/id/180/500/300.jpg',
'https://i.picsum.photos/id/187/500/300.jpg',
'https://i.picsum.photos/id/235/500/300.jpg'
];
}
},
methods: {
/*
预加载所有图片
*/
preloadImages() {
this.urls.forEach((url) => {
const img = new Image();
img.src = url;
this.images.push(url);
});
}
},
mounted() {
this.preloadImages();
}
};
</script>
我们在一个外层的父组件中引用了scroll-box和zoom-box两个子组件。在子组件中,我们通过props来传递imageSrc属性,用来指定图片的路径。为了展示图片,我们在列表中遍历调用了zoom-box组件。在mounted钩子中,我们通过preloadImages方法预加载了所有图片,将所有路径存储在images数组中。
4.2 整合组件样式编写
.image-library {
margin: 20px auto;
width: 80%;
max-width: 1000px;
}
.scroll-images {
display: flex;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: center;
height: 100%;
}
在样式方面,我们主要是设置外层容器的宽度、内部图片区域的布局等样式。具体来说,我们给image-library容器设置了一个固定的宽度和居中的样式。我们还通过flex布局设置了图片区域的宽度、高度、排列方式等。
5. 总结
通过这篇文章,我们了解了如何利用Vue框架实现图片的滚动和放大动画。我们首先学习了Vue基本概念,接着分别实现了滚动组件和放大组件。最后,我们将这两个组件整合在一起,实现了一个完整的图片库效果。如果你对此感兴趣,可以尝试在这个基础上添加更多的交互效果与功能,让这个图片库更加完善。