前言:
此时各位老铁们对“vue 翻页效果”大体比较关心,兄弟们都想要学习一些“vue 翻页效果”的相关内容。那么小编同时在网络上汇集了一些对于“vue 翻页效果””的相关文章,希望我们能喜欢,你们快快来了解一下吧!封装步骤插入body,制作全局遮罩层、禁止背景滚动
创建一个组件插入body中,使用固定定位生成一个全局遮罩层,再把图片放进去
创建组件/components/PreviewImage/index.vue
搭建组件结构,传入url数组,以及打开的当前图片索引下标,以便进行翻页查看
如果遮罩层后面页面有滚动条时在组件打开时,需要禁止背景内容随鼠标滚轮滚动,每次打开关闭时给body动态增加样式 overflow: hidden属性即可
<template> <div v-if="show" class="previewImage_wrapper"> <div class="previewImage_image"> <img :src="previewImgList[currentIndex] || ''"> </div> <div class="previewImage_close previewImage_btn" @click="closePreviewImage">×</div> <div class="previewImage_navigation"> <span class="previewImage_navigation_left previewImage_btn" @click="prevImage"><</span> <span class="previewImage_navigation_right previewImage_btn" @click="nextImage">></span> </div> </div></template><script>export default { props: { visible: { // 显示控制 type: Boolean, default: false }, previewImgList: { // url数组 type: Array, default: () => [] }, currentIndex: { // 当前图片索引 type: Number, default: 0 } }, computed: { // 双向绑定 show: { get() { return this.visible }, set(newVal) { this.$emit('update:visible', newVal) } } }, watch: { visible: { // 给body动态增加style属性,禁止背景内容的鼠标滚轮滚动 handler(newVal) { if(newVal) { document.body.style.overflow = "hidden"; } else { document.body.style.overflow = ""; } } }, }, methods: { // 上一张图片 prevImage() { if (this.currentIndex === 0) { this.currentIndex = this.previewImgList.length - 1 } else { this.currentIndex-- } }, // 下一张图片 nextImage() { if (this.currentIndex === this.previewImgList.length - 1) { this.currentIndex = 0 } else { this.currentIndex++ } }, // 关闭预览图片组件 closePreviewImage() { this.show = false } }, mounted() { // 插入body document.body.appendChild(this.$el); }, destroyed() { // 组件销毁后同步清除元素 this.$el.parentNode.removeChild(this.$el); }}定义组件过渡动画
在打开遮罩层时加上过渡效果,让组件体验更好
定义过渡动画,使用vue推荐使用自带的 组件,这样切换显示隐藏都会触发过渡效果,如果以class类名的形式定义的过渡动画,在使用指令时v-if或者v-show 隐藏关闭时不会触发结束的过渡效果
<transition name="zoom"> <!-- 组件 --></transition>
.zoom-enter, .zoom-leave-to { // 元素进入和离开时的动作 transform: scale(0);}.zoom-enter-active, .zoom-leave-active { // 元素进入和离开时的过渡动画定义 transition: transform 0.3s;}
效果如下
效果实现了,接下来还可以加入更多的功能
结合 transform 实现图片控制
在图片底部加一个控制工具栏,例如对预览图片的控制,放大、缩小、翻转等。在封装组件实现功能的时候我们应当先实现基础功能,再深入开发细节功能
想要实现元素的放大缩小,翻转,可以直接利用css3中transform属性中的 scale rotate,然后使用 js 进行动态控制
<script>export default { data() { return { imgHandle: { // 图片控制 scale: 1, rotate: 0 } } }, methods: { // 初始化还原图片缩放旋转控制 async initImgHandle() { this.imgHandle = { scale: 1, rotate: 0 } await this.$nextTick() const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, // 放大图片 async largeHandle() { console.log(this.imgHandle.scale, 'scale') this.imgHandle.scale = Number((this.imgHandle.scale + 0.2).toFixed(2)) // 使用toFixed防止小数点精度不准 const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, // 缩小图片 async shrinkHandle() { console.log(this.imgHandle.scale, 'scale') if (this.imgHandle.scale === 0.2) { // 最低缩放到0.2倍 return } this.imgHandle.scale = Number((this.imgHandle.scale - 0.2).toFixed(2)) // 使用toFixed防止小数点精度不准 const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, }}</script>
在进行小数点计算的时候,要注意小数点的精度问题,不然可能会导致计算出错产生bug,这里使用 toFixed 来解决下
在 JavaScript 中处理小数计算时,会遇到舍入误差导致计算结果不准确的情况。这是由于 JavaScript 中采用的是双精度浮点数格式(IEEE 754 标准)来表示数字,而这种格式无法准确地表示某些十进制小数
接下来写旋转的方法,然后给元素绑定点击事件就ok了
<script>export default { methods: { // 向左翻转 async turnLeftHandle() { this.imgHandle.rotate = this.imgHandle.rotate - 90 await this.$nextTick() const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, // 向右翻转 async turnRightHandle() { this.imgHandle.rotate = this.imgHandle.rotate + 90 await this.$nextTick() const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, }}</script>
最后记得给img图片加上过渡效果 transition: transform 0.3s ease; ,当控制图片操作的时候更平滑
最后的效果如下
组件代码
组件完整代码/components/PreviewImage/index.vue
<template> <transition name="zoom"> <div v-if="show" class="previewImage_wrapper" @wheel="handleScroll"> <div class="previewImage_image"> <img ref="previewImage_img" :src="previewImgList[currentIndex] || ''"> </div> <div class="previewImage_close previewImage_btn" @click="closePreviewImage">×</div> <div class="previewImage_navigation"> <span class="previewImage_navigation_left previewImage_btn" @click="prevImage"><</span> <span class="previewImage_navigation_right previewImage_btn" @click="nextImage">></span> </div> <div class="previewImage_toolbar"> <span class="previewImage_btn" @click="shrinkHandle">-</span> <span class="previewImage_btn" @click="largeHandle">+</span> <span class="previewImage_btn" @click="turnLeftHandle">↺</span> <span class="previewImage_btn" @click="initImgHandle">▣</span> <span class="previewImage_btn" @click="turnRightHandle">↻</span> </div> </div> </transition></template><script>export default { props: { visible: { // 显示控制 type: Boolean, default: false }, previewImgList: { // url数组 type: Array, default: () => [] }, currentIndex: { // 当前图片索引 type: Number, default: 0 } }, data() { return { imgHandle: { // 图片控制 scale: 1, rotate: 0 } } }, computed: { // 双向绑定 show: { get() { return this.visible }, set(newVal) { this.$emit('update:visible', newVal) } } }, watch: { visible: { // 给body动态增加style属性,禁止背景内容的鼠标滚轮滚动 handler(newVal) { if(newVal) { document.body.style.overflow = "hidden"; this.initImgHandle() // 每次打开图片初始化 } else { document.body.style.overflow = ""; } } }, }, methods: { // 鼠标滚轮 handleScroll(event) { if (event.deltaY > 0) { // 向下滚动事件 // console.log('向下滚动'); this.shrinkHandle() } else { // 向上滚动事件 // console.log('向上滚动'); this.largeHandle() } }, // 向左翻转 async turnLeftHandle() { this.imgHandle.rotate = this.imgHandle.rotate - 90 await this.$nextTick() const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, // 向右翻转 async turnRightHandle() { this.imgHandle.rotate = this.imgHandle.rotate + 90 await this.$nextTick() const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, // 初始化还原图片缩放旋转控制 async initImgHandle() { this.imgHandle = { scale: 1, rotate: 0 } await this.$nextTick() const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, // 放大图片 async largeHandle() { console.log(this.imgHandle.scale, 'scale') this.imgHandle.scale = Number((this.imgHandle.scale + 0.2).toFixed(2)) // 使用toFixed防止小数点精度不准 const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, // 缩小图片 async shrinkHandle() { console.log(this.imgHandle.scale, 'scale') if (this.imgHandle.scale === 0.2) { // 最低缩放到0.2倍 return } this.imgHandle.scale = Number((this.imgHandle.scale - 0.2).toFixed(2)) // 使用toFixed防止小数点精度不准 const element = this.$refs.previewImage_img element.style.transform = `scale(${this.imgHandle.scale}) rotate(${this.imgHandle.rotate}deg)` }, // 上一张图片 prevImage() { if (this.currentIndex === 0) { this.currentIndex = this.previewImgList.length - 1 } else { this.currentIndex-- } this.initImgHandle() }, // 下一张图片 nextImage() { if (this.currentIndex === this.previewImgList.length - 1) { this.currentIndex = 0 } else { this.currentIndex++ } this.initImgHandle() }, // 关闭预览图片组件 closePreviewImage() { this.show = false } }, mounted() { // 插入body document.body.appendChild(this.$el); }, destroyed() { // 组件销毁后同步清除元素 this.$el.parentNode.removeChild(this.$el); }}</script><style lang="less" scoped>.previewImage_wrapper{ position: fixed; top: 0; right: 0; bottom: 0; left: 0; background: rgba(0, 0, 0, .5); z-index: 9999; .previewImage_image{ display: flex; align-items: center; justify-content: center; img { width: 100vw; height: 100vh; object-fit: scale-down; transition: transform 0.3s ease; } } .previewImage_close{ position: absolute; right: 20px; top: 20px; transition: transform 0.2s ease-out; &:hover{ transform: scale(1.2); } } .previewImage_navigation{ &_left{ position: absolute; left: 15px; top: 50%; transform: translate(0, -50%); transition: transform 0.2s ease-out; } &_right{ position: absolute; right: 15px; top: 50%; transform: translate(0, -50%); transition: transform 0.2s ease-out; } &_left:hover,&_right:hover{ transform: translate(0, -50%) scale(1.2); } } .previewImage_toolbar{ position: absolute; bottom: 10px; left: 50%; transform: translate(-50%, 0); display: flex; align-items: center; span{ margin-right: 10px; transition: transform 0.2s ease-out; &:hover{ transform: scale(1.1) ; } } span:last-child{ margin-right: 0; } } .previewImage_btn{ width: 50px; height: 50px; display: flex; align-items: center; justify-content: center; font-size: 24px; color: #fff; background-color: #606266; border-radius: 50%; cursor: pointer; }}.zoom-enter, .zoom-leave-to { // 元素进入和离开时的动作 transform: scale(0);}.zoom-enter-active, .zoom-leave-active { // 元素进入和离开时的过渡动画定义 transition: transform 0.3s;}.slide-enter, .slide-leave-to { // 元素进入和离开时的动作 transform: translateX(100%);}.slide-enter-active, .slide-leave-active { // 元素进入和离开时的过渡动画定义 transition: transform 0.3s ease-in-out;}</style>
使用组件代码
<template> <div class="home"> <div class="home-box"> <img v-for="(item, index) in previewImg.imgUrlList" :key="item" :src="item" @click="openPreviewImg(index)"> </div> <PreviewImage :visible.sync="previewImg.visible" :currentIndex="previewImg.currentIndex" :previewImgList="previewImg.imgUrlList" /> </div></template><script>import PreviewImage from '../components/PreviewImage/index.vue'export default { name: 'Home', components: { PreviewImage }, data() { return { previewImg: { visible: false, currentIndex: -1, imgUrlList: [';, ';, ';, ';], } }; }, methods: { // 打开预览图片遮罩层 openPreviewImg(index) { this.previewImg.currentIndex = index this.previewImg.visible = true } }}</script><style lang="less">.home{ height: 3000px; &-box{ display: flex; justify-items: center; img{ width: 150px; height: 150px; cursor: pointer; } }}</style>
标签: #vue 翻页效果