引自:laii7/vue查看图片插件,略作修改,添加了缩放旋转功能。若未使用iview组件,请将ImageViewer.vue中图标Icon换掉,以免报错。
1. 目录结构
2. 代码如下
// config.js,可以根据个人需求进行设置以下选项
export default {
canClickModalHide: false, //控制是否点击遮罩层关闭
closeButtonVisible: true, //控制关闭按钮是否可见,若设置为false则canClickModalHide必定为true
modalOpacity: 0.5, //控制遮罩层的透明度(0-1之间的number类型)
controlButtonVisible: true, //控制按钮是否可见
}
// ImageViewer.vue
<template>
<div v-if="visible" @click="hideImage">
<div class="see-image" :style="{ backgroundColor:background }">
<img v-drag="greet"
id="drag"
class="image"
:src="currentImg"
@wheel.prevent="wheel"
ref="user_image"/>
</div>
<div class="close" v-show="closeButtonVisible">
<Icon @click="close" type="md-close-circle" :size="40" class="close-icon" />
</div>
<div class="control" v-show="controlButtonVisible">
<Icon @click.stop="scaleImage('add')" type="ios-add-circle-outline" :size="24" class="control-icon" />
<Icon @click.stop="scaleImage('remove')" type="ios-remove-circle-outline" :size="24" class="control-icon" />
<Icon @click.stop="rotateImage('left')" type="md-undo" :size="24" class="control-icon" />
<Icon @click.stop="rotateImage('right')" type="md-redo" :size="24" class="control-icon" />
</div>
</div>
</template>
<script>
import config from './config'
const {modalOpacity, canClickModalHide, controlButtonVisible, closeButtonVisible} = config;
export default {
data() {
return {
currentImg: '',
visible: false,
background: modalOpacity > 1 || modalOpacity <= 0 || typeof modalOpacity !== "number" ? null : 'rgba(0,0,0,' + modalOpacity + ')',
controlButtonVisible,
closeButtonVisible,
rotateDeg: 0,
}
},
methods: {
close() {
this.clearImg();
},
//接受传来的位置数据,并将数据绑定给data下的val
greet(val) {
this.val = val;
},
//点击图片之外区域隐藏图片
hideImage(e) {
if (!this.visible || (!canClickModalHide && closeButtonVisible)) return;
document.addEventListener('click', (e) => {
if (e.target.nodeName !== 'IMG' && e.target.nodeName !== 'BUTTON') {
this.clearImg();
}
});
},
//旋转图片
rotateImage(direction) {
if(direction === 'left'){
this.rotateDeg -= 90;
}else{
this.rotateDeg += 90;
}
this.$refs.user_image.style.transform = `rotate(${this.rotateDeg}deg)`;
this.$refs.user_image.style.transition = '.3s';
},
// 按钮缩放图片
scaleImage(scale){
if(scale === 'add'){
this.$refs.user_image.style.transform = this.$refs.user_image.style.transform + ' scale(1.1)';
}else{
this.$refs.user_image.style.transform = this.$refs.user_image.style.transform + ' scale(0.9)';
}
},
// 滚轮缩放图片
wheel(e) {
if (e.wheelDelta) { //判断浏览器IE,谷歌滑轮事件
if (e.wheelDelta > 0) { //当滑轮向上滚动时
this.$refs.user_image.style.transform = this.$refs.user_image.style.transform + ' scale(1.1)';
}
if (e.wheelDelta < 0) { //当滑轮向下滚动时
this.$refs.user_image.style.transform = this.$refs.user_image.style.transform + ' scale(0.9)';
}
} else if (e.deltaY) { //Firefox滑轮事件
if (e.deltaY < 0) { //当滑轮向上滚动时
this.$refs.user_image.style.transform = this.$refs.user_image.style.transform + ' scale(1.1)';
}
if (e.deltaY > 0) { //当滑轮向下滚动时
this.$refs.user_image.style.transform = this.$refs.user_image.style.transform + ' scale(0.9)';
}
}
},
//当图片隐藏时候的回调
clearImg() {
this.visible = false;
this.rotateDeg = 0;
document.removeEventListener('click', null);
setTimeout(() => {
if (this.$refs.user_image) {
this.$refs.user_image.style.transform = 'rotate(0deg)';
this.$refs.user_image.style.left = '';
this.$refs.user_image.style.top = '';
}
}, 100)
},
}
}
</script>
<style scoped>
.see-image {
width: 100%;
z-index: 9999;
background: rgba(0, 0, 0, .3);
height: 100%;
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
animation: .25s showAimation ease;
}
@keyframes showAimation {
from {
opacity: .3;
}
to {
opacity: 1;
}
}
.image {
max-width: 400px;
min-width: 150px;
position: absolute;
}
.close {
position: absolute;
right: 40px;
top: 40px;
height: 40px;
width: 40px;
color: #515a6e;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
transition: .3s;
z-index: 10000;
}
.close:hover {
transform: rotate(90deg);
color: #17233d;
}
.close img {
width: 40px;
height: 40px;
}
.close-icon {
cursor: pointer;
}
.control {
width: 180px;
height: 48px;
line-height: 48px;
margin-left: -90px;
background: #606266;
border-radius: 50%;
position: absolute;
bottom: 40px;
left: 50%;
color: #fff;
border-color: #fff;
border-radius: 24px;
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
}
.control-icon {
margin: 0 6px;
cursor: pointer;
}
</style>
// index.js
import ImageViewerComponent from './ImageViewer'
const ImageViewer = {}
ImageViewer.install = Vue => {
const ImageViewerConstructor = Vue.extend(ImageViewerComponent);
const instance = new ImageViewerConstructor();
instance.$mount(document.createElement('div'))
document.body.appendChild(instance.$el)
//自定义拖动
Vue.directive('drag',
function (el, binding) {
instance.isShowImageDialog = true;
let oDiv = el; //当前元素
oDiv.onmousedown = function (e) {
if (e.button === 2) return;
e.preventDefault();
let bw = document.body.clientWidth;
let bh = document.body.clientHeight;
//鼠标按下,计算当前元素距离可视区的距离
let disX = e.clientX - oDiv.offsetLeft;
let disY = e.clientY - oDiv.offsetTop;
document.onmousemove = function (e) {
//通过事件委托,计算移动的距离
let l = 0, t = 0;
// 拖动边界
if (e.clientX >= bw) {
l = bw - disX;
} else if (e.clientX <= 0) {
{
l =0- disX;
}
} else {
l = e.clientX - disX;
}
if (e.clientY >= bh) {
t = bh - disY;
}else if(e.clientY <= 0) {
t =0- disY;
}
else {
t = e.clientY - disY;
}
//移动当前元素
oDiv.style.left = l + 'px';
oDiv.style.top = t + 'px';
//将此时的位置传出去
binding.value({x: e.pageX, y: e.pageY})
};
// 事件移除
document.onmouseup = function (e) {
document.onmousemove = null;
document.onmouseup = null;
};
};
}
);
// 挂载触发方法
Vue.prototype.$imageViewer = (e) => {
instance.currentImg = e.currentTarget.currentSrc;
instance.visible = true;
}
}
export default ImageViewer;
3. 使用
// vue项目的main.js文件中引用,注意由于组件中用到了ivew相关组件,请放在iview之后引用
import imageViewer from '@/components/vue-imageViewer-master' // 图片查看
Vue.use(imageViewer);
// 组件中直接添加 @click="$imageViewer" 即可
<img :src="url" @click="$imageViewer">
4. 效果图