123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- <!--
- * @Author: 贺永胜
- * @Date: 2021-04-19 16:39:30
- * @email: 1378431028@qq.com
- * @LastEditors: 贺永胜
- * @LastEditTime: 2023-03-28 16:28:25
- * @Description: file content
- -->
- <!--
- * __----~~~~~~~~~~~------___
- * . . ~~//====...... __--~ ~~
- * -. \_|// |||\\ ~~~~~~::::... /~
- * ___-==_ _-~o~ \/ ||| \\ _/~~-
- * __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~
- * _-~~ .=~ | \\-_ '-~7 /- / || \ /
- * .~ .~ | \\ -_ / /- / || \ /
- * / ____ / | \\ ~-_/ /|- _/ .|| \ /
- * |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\
- * ' ~-| /| |-~\~~ __--~~
- * |-~~-_/ | | ~\_ _-~ /\
- * / \ \__ \/~ \__
- * _--~ _/ | .-~~____--~-/ ~~==.
- * ((->/~ '.|||' -_| ~~-/ , . _||
- * -_ ~\ ~~---l__i__i__i--~~_/
- * _-~-__ ~) \--______________--~~
- * //.-~~~-~_--~- |-------~~~~~~~~
- * //.-~~~--\
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * 神兽保佑 永无BUG
- -->
- <template>
- <transition name="fade">
- <div
- class="hevue-imgpreview-wrap"
- id="hevue-imgpreview-wrap"
- v-if="visible"
- ref="heImg"
- @mouseup="removeMove('pc')"
- @touchend="removeMove('mobile')"
- @click.stop="clickMask"
- >
- <div class="he-img-wrap">
- <div
- class="heimgfont hevue-img-status-icon rotate-animation"
- v-show="imgState === 1"
- >
- 
- </div>
- <!-- <div class="heimgfont loading"></div> -->
- <img
- :src="imgurl"
- ref="heImView"
- @click.stop=""
- v-show="imgState === 2"
- class="he-img-view"
- :style="
- 'transform: scale(' +
- imgScale +
- ') rotate(' +
- imgRotate +
- 'deg);margin-top:' +
- imgTop +
- 'px;margin-left:' +
- imgLeft +
- 'px;' +
- maxWH
- "
- @mousedown="addMove"
- @touchstart="addMoveMobile"
- />
- <!-- 图片加载失败 -->
- <div class="heimgfont hevue-img-status-icon" v-show="imgState === 3">
- 
- </div>
- <!-- 关闭按钮 -->
- <div
- class="heimgfont he-close-icon"
- @click.stop="close({ way: 'closeBtn' })"
- v-if="closeBtn"
- >
- 
- </div>
- <!-- 左箭头 -->
- <div
- class="arrow arrow-left heimgfont"
- @click.stop="toogleImg(false, 'btn')"
- v-if="arrowBtn && multiple"
- >
- 
- </div>
- <!-- 右箭头 -->
- <div
- class="arrow arrow-right heimgfont"
- @click.stop="toogleImg(true, 'btn')"
- v-if="arrowBtn && multiple"
- >
- 
- </div>
- <!-- 控制条 -->
- <div class="he-control-bar-wrap" v-if="controlBar">
- <div class="he-control-bar" @click.stop>
- <!-- 缩小 -->
- <div
- class="he-control-btn heimgfont"
- @click.stop="scaleFunc(-0.15)"
- >
- 
- </div>
- <!-- 放大 -->
- <div class="he-control-btn heimgfont" @click.stop="scaleFunc(0.15)">
- 
- </div>
- <!-- 复位 -->
- <div
- class="he-control-btn heimgfont"
- v-show="isFull"
- @click.stop="imgToggle"
- >
- 
- </div>
- <!-- 复位 -->
- <div
- class="he-control-btn heimgfont"
- v-show="!isFull"
- @click.stop="imgToggle"
- >
- 
- </div>
- <!-- 左转 -->
- <div class="he-control-btn heimgfont" @click.stop="rotateFunc(-90)">
- 
- </div>
- <!-- 右转 -->
- <div class="he-control-btn heimgfont" @click.stop="rotateFunc(90)">
- 
- </div>
- <!-- 下载 -->
- <!-- <div class="he-control-btn heimgfont" @click.stop="downloadIamge">
- 
- </div> -->
- </div>
- </div>
- <!-- 页码指示器 -->
- <div class="he-control-num" v-if="controlBar && multiple">
- {{ imgIndex + 1 }} / {{ imgList.length }}
- </div>
- </div>
- </div>
- </transition>
- </template>
- <script>
- export default {
- name: 'hevue-img-preview',
- data() {
- return {
- // imgWidth: 0,
- // imgHeight: 0,
- visible: false, // 插件显示,默认为false
- imgScale: 1,
- imgTop: 0,
- imgLeft: 0,
- imgRotate: 0,
- isFull: false,
- maxWH: 'max-width:100%;max-height:100%;',
- clientX: 0,
- clientY: 0,
- imgIndex: 0,
- canRun: true,
- imgurl: '',
- imgState: 1,
- start: [{}, {}],
- mobileScale: 0, // 手指离开时图片的缩放比例
- // 以下内容为用户传入配置
- // show: true, // 插件显示,默认为false
- url: '', // 预览图片的地址
- nowImgIndex: 0,
- multiple: false,
- imgList: [],
- // 以下为可全局配置
- controlBar: true,
- closeBtn: true,
- arrowBtn: true,
- keyboard: false,
- clickMaskCLose: false, // 是否点击遮罩关闭,默认false
- closeFn: null, // 关闭回调函数
- changeFn: null, // 切换图片回调函数
- }
- },
- mounted() {
- this.initImg()
- },
- watch: {
- url() {
- this.initImg()
- },
- visible: {
- handler(newV) {
- if (newV) {
- this.$nextTick(() => {
- let _dom = document.getElementById('hevue-imgpreview-wrap')
- _dom.onmousewheel = this.scrollFunc
- // 火狐浏览器没有onmousewheel事件,用DOMMouseScroll代替(滚轮事件)
- document.body.addEventListener('DOMMouseScroll', this.scrollFunc)
- // 禁止火狐浏览器下拖拽图片的默认事件
- document.ondragstart = function () {
- return false
- }
- // 判断是否多图
- if (this.multiple) {
- if (Array.isArray(this.imgList) && this.imgList.length > 0) {
- this.imgIndex = Number(this.nowImgIndex) || 0
- // this.url = this.imgList[this.imgIndex]
- this.changeUrl(this.imgList[this.imgIndex], this.imgIndex)
- } else {
- // console.error("imgList 为空或格式不正确");
- }
- } else {
- this.changeUrl(this.url)
- }
- // 判断是否开启键盘事件
- if (this.keyboard) {
- document.addEventListener('keydown', this.keyHandleDebounce)
- }
- })
- }
- },
- immediate: true,
- },
- },
- methods: {
- show() {
- this.visible = true
- },
- close(data) {
- this.initImg()
- // this.maxWH = "max-width:100%;max-height:100%;";
- // this.isFull = false;
- // 移除火狐浏览器下的鼠标滚动事件
- document.body.removeEventListener('DOMMouseScroll', this.scrollFunc)
- //恢复火狐及Safari浏览器下的图片拖拽
- document.ondragstart = null
- // 移除键盘事件
- if (this.keyboard) {
- document.removeEventListener('keydown', this.keyHandleDebounce)
- }
- this.visible = false
- this.closeFn && this.closeFn(data)
- },
- initImg() {
- this.mobileScale = 1
- this.imgScale = 1
- this.imgRotate = 0
- this.imgTop = 0
- this.imgLeft = 0
- },
- /**
- * 切换图片
- * true 下一张
- * false 上一张
- */
- toogleImg(bool, way) {
- let fromIndex = this.imgIndex
- if (bool) {
- this.imgIndex++
- if (this.imgIndex > this.imgList.length - 1) {
- this.imgIndex = 0
- }
- } else {
- this.imgIndex--
- if (this.imgIndex < 0) {
- this.imgIndex = this.imgList.length - 1
- }
- }
- this.changeFn &&
- this.changeFn({
- type: bool ? 'next' : 'prev',
- fromImgIndex: fromIndex,
- fromImgUrl: this.imgList[fromIndex],
- toImgIndex: this.imgIndex,
- toImgUrl: this.imgList[this.imgIndex],
- way,
- })
- // this.url = this.imgList[this.imgIndex]
- this.changeUrl(this.imgList[this.imgIndex], this.imgIndex)
- },
- // 改变图片地址
- /**
- * @description:
- * @param {String} url 要显示的图片的url
- * @param {Number} index 当前显示当图片下标,防止用户点击切换图片过快
- * @return {*}
- */
- changeUrl(url, index) {
- this.imgState = 1
- let img = new Image()
- img.src = url
- img.onload = () => {
- // 如果加载出来图片当下标不是当前显示图片当下标,则不予显示(用户点击过快当时候,会出现用户点到第三张了,此时第一张图片才加载完当情况)
- if (index != undefined && index == this.imgIndex) {
- this.imgState = 2
- this.imgurl = url
- } else if (index == undefined) {
- this.imgState = 2
- this.imgurl = url
- }
- }
- img.onerror = () => {
- if (index != undefined && index == this.imgIndex) {
- this.imgState = 3
- } else if (index == undefined) {
- this.imgState = 3
- }
- }
- },
- // 旋转图片
- rotateFunc(deg) {
- this.imgRotate += deg
- },
- // 图片缩放
- scaleFunc(num, bool) {
- if (this.imgScale <= 0.2 && num < 0) return
- if (bool) {
- this.imgScale = num
- } else {
- this.imgScale += num
- }
- },
- // 图片原尺寸切换
- imgToggle() {
- this.initImg()
- if (this.isFull) {
- this.maxWH = 'max-width:100%;max-height:100%;'
- } else {
- this.maxWH = ''
- }
- this.isFull = !this.isFull
- },
- // 鼠标滚轮缩放
- scrollFunc(e) {
- e = e || window.event
- // e.returnValue = false // ie
- // 火狐下没有wheelDelta,用detail代替,由于detail值的正负和wheelDelta相反,所以取反
- e.delta = e.wheelDelta || -e.detail
- e.preventDefault()
- if (e.delta > 0) {
- //当滑轮向上滚动时
- this.scaleFunc(0.05)
- }
- if (e.delta < 0) {
- //当滑轮向下滚动时
- this.scaleFunc(-0.05)
- }
- },
- // 鼠标按下
- addMove(e) {
- e = e || window.event
- this.clientX = e.clientX
- this.clientY = e.clientY
- this.$refs.heImg.onmousemove = this.moveFunc
- },
- // 手指按下事件
- addMoveMobile(e) {
- e.preventDefault()
- e = e || window.event
- if (e.touches.length > 1) {
- this.start = e.touches
- } else {
- this.clientX = e.touches[0].pageX
- this.clientY = e.touches[0].pageY
- }
- // 添加手指拖动事件
- this.$refs.heImg.ontouchmove = this.moveFuncMobile
- },
- // 鼠标拖动
- moveFunc(e) {
- e = e || window.event
- e.preventDefault()
- let movementX = e.clientX - this.clientX
- let movementY = e.clientY - this.clientY
- // event.clientY;
- this.imgLeft += movementX * 2
- this.imgTop += movementY * 2
- this.clientX = e.clientX
- this.clientY = e.clientY
- },
- // 手指拖动
- moveFuncMobile(e) {
- e = e || window.event
- if (e.touches.length > 1) {
- var now = e.touches
- var scale =
- this.getDistance(now[0], now[1]) /
- this.getDistance(this.start[0], this.start[1])
- // 判断是否手指缩放过,如果缩放过,要在上次缩放的比例基础上进行缩放
- if (this.mobileScale) {
- if (scale > 1) {
- // 放大
- this.scaleFunc(scale + this.mobileScale - 1, true)
- } else {
- // 缩小
- this.scaleFunc(scale * this.mobileScale, true)
- }
- } else {
- this.scaleFunc(scale, true)
- }
- } else {
- let touch = e.touches[0]
- e.preventDefault()
- let movementX = touch.pageX - this.clientX
- let movementY = touch.pageY - this.clientY
- // event.clientY;
- this.imgLeft += movementX * 2
- this.imgTop += movementY * 2
- this.clientX = touch.pageX
- this.clientY = touch.pageY
- }
- },
- // 移除拖动事件
- removeMove(type) {
- if (type === 'pc') {
- this.$refs.heImg.onmousemove = null
- } else {
- this.mobileScale = this.imgScale
- this.$refs.heImg.ontouchmove = null
- }
- },
- keyHandleDebounce(e) {
- if (this.canRun) {
- // 如果this.canRun为true证明当前可以执行函数
- this.keyHandle(e)
- this.canRun = false // 执行函数后一段时间内不可再次执行
- setTimeout(() => {
- this.canRun = true // 等到了我们设定的时间之后,把this.canRun改为true,可以再次执行函数
- }, 300)
- }
- },
- // 键盘事件
- keyHandle(e) {
- e = window.event || e
- var key = e.keyCode || e.which || e.charCode
- switch (key) {
- case 27: // esc
- this.close({ way: 'esc' })
- break
- case 65: // a键-上一张
- if (this.multiple) {
- this.toogleImg(false, 'key-a')
- }
- break
- case 68: // d键-下一张
- if (this.multiple) {
- this.toogleImg(true, 'key-d')
- }
- break
- case 87: // w键-放大
- this.scaleFunc(0.15)
- break
- case 83: // s键-缩小
- this.scaleFunc(-0.15)
- break
- case 81: // q键-逆时针旋转
- this.rotateFunc(-90)
- break
- case 69: // e键-顺时针旋转
- this.rotateFunc(90)
- break
- case 82: // r键-复位键
- this.initImg()
- break
- default:
- break
- }
- },
- // 点击遮罩层
- clickMask() {
- if (this.clickMaskCLose) {
- this.close({ way: 'mask' })
- }
- },
- //缩放 勾股定理方法-求两点之间的距离
- getDistance(p1, p2) {
- var x = p2.pageX - p1.pageX,
- y = p2.pageY - p1.pageY
- return Math.sqrt(x * x + y * y)
- },
- /**
- * @description:
- * @param {String} imgsrc
- * @param {*} name
- * @return {*}
- */
- downloadIamge() {
- //下载图片地址和图片名
- let image = new Image()
- // 解决跨域 Canvas 污染问题
- image.setAttribute('crossOrigin', 'anonymous')
- image.onload = function () {
- let canvas = document.createElement('canvas')
- canvas.width = image.width
- canvas.height = image.height
- let context = canvas.getContext('2d')
- context.drawImage(image, 0, 0, image.width, image.height)
- let url = canvas.toDataURL('image/png') //得到图片的base64编码数据
- let a = document.createElement('a') // 生成一个a元素
- let event = new MouseEvent('click') // 创建一个单击事件
- a.download = 'photo' + +new Date() // 设置图片名称
- a.href = url // 将生成的URL设置为a.href属性
- a.dispatchEvent(event) // 触发a的单击事件
- }
- image.onerror = function (err) {
- console.log('图片信息不正确或图片服务器禁止访问')
- console.log(err)
- }
- if (this.multiple) {
- image.src = this.imgList[this.imgIndex]
- } else {
- image.src = this.url
- }
- },
- },
- }
- </script>
- <style scoped>
- @import './iconfont/iconfont.css';
- @import './css/default.css';
- </style>
|