功能:图片预览组件,支持双手指放大/缩小,双击放大/缩小,单击消失隐藏。

注:touch事件请手机预览

源码分享

组件参数

data() {

return {

loading: 2, // 1成功 2正在加载 3error失败

dragObject: {},

starLine: 0, // 初始俩个点第1次距离

zoom: 1, // 放缩比

compress: null, // 最大压缩比

elWidth: null, // 外层宽度

elHeight: null, // 外层高度

imgWidth: null, // 当前图片宽度

imgHeight: null, // 当前图片高度

mTop: 0, // margin-top 值

mLeft: 0, // margin-left 值

isTouch: false, // 是否touch

scrolling: false, // 是否放缩

animating: false, // 是否动画中

isTwoClick: false, // 是否双击

startTime: null, // 第一次时间

timeFunc: null, // 定时器

}

},

组件初始化init(),dom绑定事件,区分滑动事件、单击、双击事件

/**

* 初始化事件

* @param {Object} $el 当前DOM

*/

init($el) {

this.elWidth = document.documentElement.clientWidth

this.elHeight = document.documentElement.clientHeight

$el.addEventListener('touchstart', (e) => {

if (this.animating) return

// 记录点击时间和第二次点击的时差

if (this.startTime) this.dragObject.duration = new Date() - this.startTime

if (!this.startTime) this.startTime = new Date()

if (this.dragObject.duration) this.startTime = null

this.dragObject.startTime = new Date()

this.touchStart(e)

if (!this.isTouch) this.isTouch = e.touches.length > 1

})

$el.addEventListener('touchmove', (e) => {

....

})

$el.addEventListener('touchend', (e) => {

....

}

})

图片加载完后执行imgLoad()事件,设置图片初始显示的宽imgWidth高imgHeight以及放缩比compress

/**

* 图片加载成功事件

*/

imgLoad(e) {

const compress = e.target.width / this.elWidth

const scale = this.scale > 3 ? this.scale : 3

this.imgWidth = compress > 1 ? this.elWidth : e.target.width

this.imgHeight = compress > 1 ? e.target.height / compress : e.target.height

this.compress = compress > scale ? compress : scale

this.loading = 1

},

滑动开始,区分放缩事件or滑动事件

$el.addEventListener('touchmove', (e) => {

e.preventDefault()

if (this.animating) return

this.isTouch = true

if (e.touches.length === 2) this.touchTwoMove(e)

if (e.touches.length === 1) this.touchMove(e)

})

touchStart()滑动开始事件

/**

* 触发开发

*/

touchStart(e) {

const touch = e.touches[0]

if (e.touches.length > 1) {

// 放缩初始俩点的距离

const touch2 = e.touches[1]

const diffX = touch.pageX - touch2.pageX

const diffY = touch.pageY - touch2.pageY

this.starLine = Math.pow((diffX * diffX + diffY * diffY), 0.5)

}

// 缓存初始的margin-left和margin-top的比值

this.dragObject.topThan = this.mTop !== 0 ? this.mTop / this.reckonHeight(this.zoom) : 0

this.dragObject.leftThan = this.mLeft !== 0 ? this.mLeft / this.reckonWidth(this.zoom) : 0

this.dragObject.startLeft = touch.pageX

this.dragObject.startTop = touch.pageY

this.dragObject.zoom = this.zoom

}

touchMove()触发滑动事件

/**

* 触发移动

*/

touchMove(e) {

if (this.scrolling) return

const dragObject = this.dragObject

const touch = e.touches[0]

let xx = touch.pageX - (dragObject.oldLeft || dragObject.startLeft)

let yy = touch.pageY - (dragObject.oldTop || dragObject.startTop)

dragObject.oldLeft = touch.pageX

dragObject.oldTop = touch.pageY

if (this.imgWidth * dragObject.zoom > this.elWidth) {

if (Math.abs(this.mLeft) > this.reckonWidth(dragObject.zoom)) xx *= 0.3

this.mLeft += xx

}

if (this.imgHeight * dragObject.zoom > this.elHeight) {

if (Math.abs(this.mTop) > this.reckonHeight(dragObject.zoom)) yy *= 0.3

this.mTop += yy

}

},

touchEnd()触发结束事件,计算滑动后的位置,并执行动画事件continueTranslate()

/**

* 解发结束

* @param {Number} dragDuration 间隔

*/

touchEnd(dragDuration) {

....

this.continueTranslate(top, left, this.mLeft, this.mTop)

},

continueTranslate()动画事件,借助requestAnimationFrame()方法

/**

* 继续执行一段距离滑行

* @param {Number} top 将要到达的top值

* @param {Number} left 将要到达的left值

* @param {Number} oldX 动画执行前left值

* @param {Number} oldY 动画执行前top值

*/

continueTranslate(top, left, oldX, oldY) {

this.animating = true

const xx = left - oldX

const yy = top - oldY

let diffX = 0

let diffY = 0

let ALPHA = 0.88

const animationLoop = () => {

ALPHA *= 0.95

const resultX = Math.abs(diffX - xx) < 1

const resultY = Math.abs(diffY - yy) < 1

if (resultX && resultY) {

this.animating = false

this.mLeft = left

this.mTop = top

} else {

diffX = diffX * ALPHA + (1 - ALPHA) * xx

diffY = diffY * ALPHA + (1 - ALPHA) * yy

if (!resultX) this.mLeft = oldX + diffX

if (!resultY) this.mTop = oldY + diffY

animationFrame(animationLoop)

}

}

animationLoop()

},

touchTwoMove()放缩滑动事件

/**

* 放缩移动

*/

touchTwoMove(e) {

this.scrolling = true

const dragObject = this.dragObject

const touch = e.touches[0]

const touch2 = e.touches[1]

const diffX = touch.pageX - touch2.pageX

const diffY = touch.pageY - touch2.pageY

const line = Math.pow((diffX * diffX + diffY * diffY), 0.5) - this.starLine

let zoom = Number(dragObject.zoom + (line / 2 / 75))

if (zoom < 1) zoom = 1 - (1 - zoom) * 0.15

if (zoom > this.compress) zoom = this.compress + (zoom - 3) * 0.2

this.zoom = zoom

this.mLeft = dragObject.leftThan * this.reckonWidth(zoom)

this.mTop = dragObject.topThan * this.reckonHeight(zoom)

},

touchEnd()事件,当touches.length===0才执行事件,区分滑动事件、单击、双击事件。

$el.addEventListener('touchend', (e) => {

if (this.animating || e.touches.length > 0) return

const dragObject = this.dragObject

// 单次间隔时长

const duration = new Date() - this.dragObject.startTime

let zoom = this.zoom

if (this.isTouch) {

// 滑动事件

clearTimeout(this.timeFunc)

this.timeFunc = null

// 滑动执行事件

if (!this.scrolling) this.touchEnd(duration)

// 放缩执行事件

if (this.scrolling) {

if (zoom > this.compress) zoom = this.compress

if (zoom < 1) zoom = 1

if (dragObject.leftThan) this.mLeft = dragObject.leftThan * this.reckonWidth(zoom)

if (dragObject.topThan) this.mTop = dragObject.topThan * this.reckonHeight(zoom)

}

this.isTouch = false

this.zoom = zoom

this.scrolling = false

this.starLine = 0

this.dragObject = {}

} else {

// 俩次点击时长<250双击

if (dragObject.duration && dragObject.duration < 250) {

// 双击事件

clearTimeout(this.timeFunc)

this.timeFunc = null

this.zoom = zoom > 1 ? 1 : 2

this.mLeft = this.mTop = 0

this.dragObject = {}

} else {

// 单击事件

if (this.timeFunc) return

this.timeFunc = setTimeout(() => {

this.timeFunc = null

this.dragObject = {}

this.startTime = null

this.zoom = 1

this.mLeft = this.mTop = 0

this.$emit('input', false)

}, 250)

}

}

})

结束...

效果图

扫码预览

欢迎buging

pc 图片预览放大 端vue_移动端Vue.js的图片预览组件,支持放缩、滑动功能!相关推荐

  1. vue本地上传并预览php,vue.js 实现图片本地预览 裁剪 压缩 上传功能

    以下代码涉及 Vue 2.0 及 ES6 语法. 目标 纯 javascrpit 实现,兼容ie9及以上浏览器,在本地做好文件格式.长宽.大小的检测,减少浏览器交互. 现实是残酷的,为了兼容Ie9 还 ...

  2. vue 图片裁剪工具_使用Vue.js的图片裁剪工具,包括预览

    vue 图片裁剪工具 Vue作物 (vue-crop) Images Crop tool with Vue.js including preview. 使用Vue.js的图片裁剪工具,包括预览. Vi ...

  3. 本地如何预览php文件上传,如何实现js上传图片本地预览同时支持预览截图的功能...

    在项目中经常会用到js上传图片本地预览的效果,同时需要在预览图上直接预览截图的范围. 下面是我写的简单的demo,是用js结合cropper.js模拟实现此项前端的功能,后台则不考虑. 准备:引入文件 ...

  4. 计算机毕业设计SpringBoot+Vue.js学前教育图片智能识别系统(百度AI平台)

    功能 本系统七个部分分别是用户管理模块.用户信息模块.用户留言模块.管理员模块.图片识别模块.学习收藏模块,它们的功能如下: (1) 用户管理模块 用户管理模块包含了注册(账号.昵称.密码).登录(不 ...

  5. 在vue.js引用图片的问题

    <div id="img"> <img src="img.png" class="img"> </div> ...

  6. VUE.JS 实现图片随鼠标变换的动画效果

    先来看演示效果 首先我们设置一个这样的图片样式 <template><div class="login100-pic"><img src=" ...

  7. vue——js实现图片/文件的拖拽上传(复制粘贴就能用,还有优化空间)

    首先先创建元素容器 <template><div id="drop"><span v-show="isUpload" class= ...

  8. vue.js实现图片、视频文件压缩后再上传

    这里只展示图片上传代码 在这里插入代码片 ``` //html部分// 上传图片<div class="fileBox"><span class="fi ...

  9. layui日期与vue_详解Vue.js和layui日期控件冲突问题解决办法

    详解Vue.js和layui日期控件冲突问题解决办法 发布于 2020-8-10| 复制链接 摘记: 事故还原: 今天在用layui的日期控件的时候发现一个问题,就是form表单中的日期选择之后,如果 ...

最新文章

  1. Solr 4.x定时、实时增量索引 - 修改、删除和新增索引
  2. 经验 | OpenCV图像旋转的原理与技巧
  3. 能打开java文件_用java打开一个本地文件
  4. freemaker介绍及常见的用法解析
  5. led拼接屏报价_LED拼接屏的装饰
  6. jenkins与SonarQube集成
  7. Java:Overriding与Overloading
  8. 23. 客户默认选项(Default Customer Options)
  9. 树算法系列之三:GBDT
  10. Leetcode 372.超级次方
  11. OpenGL.Superbible.7th.Edition(openGL超级宝典第七版)随书例子运行
  12. 【Unity Shaders】ShadowGun系列之一——飞机坠毁的浓烟效果
  13. HTML做一个节日页面【六一儿童节】纯HTML代码
  14. html页面嵌入百度地图
  15. 网络编程(二)- 检查网络的工具
  16. sql中如何按拼音笔画排序
  17. 讯时O口MX8网关对接昆石软交换vos3000
  18. python实现从oracle读数据写入mysql(1)
  19. figma的一些用法(一)
  20. Ubuntu系统SSH免密登录,以及SSH免密登录原理

热门文章

  1. Spring JdbcTemplate查询实例
  2. 关于错误提示:此实现不是 Windows 平台 FIPS 验证的加密算法的一部分的解决方案...
  3. PHP SOAP 教程 实例一
  4. Composer The openssl extension is required for SSL/TLS protection
  5. PHP CURL 多线程 GET/POST 类
  6. ELK的What files do you want me to watch? Exiting: no modules or inputs enabled and configuration
  7. Bug之PHPMailer附件名字不支持中文的
  8. auto errored after 报错解决_MySQL5.7 group_by报错问题解决办法,大部分程序员都收藏了...
  9. java 只显示文本文件_Java设计并实现一个应用程序,能够读取一个文本文件中的内容并显示,同时能够计算出文本中的行数。...
  10. ddr5内存上市时间_辣评烩:SK海力士首发DDR5内存:频率冲上5600MHz