关于图片缩放 移动

====================================================================
image.vue
====================================================================
<template>
    <transition name="viewer-fade">
        <div ref="bigImg" class="bigImg" v-show="visible">
            <div class="back_mask"></div>
            <span class="bigImg_close" @click='closebigImg'>
                <Icon type="md-close-circle" class="bigImg_close_Icon"/>
            </span>
            <div class="bigImg_action" v-if="zoomFlag">
                    <span @click="handleActions('zoomOut')">缩小</span>
                    <span @click="handleActions('zoomIn')">放大</span>
                    <span @click="handleActions('anticlocelise')"><Icon type="ios-undo"/></span>
                    <span @click="handleActions('clocelise')"><Icon type="ios-redo"/></span>
            </div>
            <div class="bigImg_Box">
                <img 
                    :src="showUrl" 
                    ref="img" 
                    alt="" 
                    class="bigImg_image" 
                    :style='imgStyle'
                    @mousedown="handleMouseDown"
                    @load="handleImgLoad"
                    @error="handleImgError"
                    >
            </div>
        </div>
        
    </transition>
</template>
<script>
    export default {
        name:'ShowLargeImage',
        props:{
            imageList:{
                type: Array,
                default: () => []
            },
            initialIndex: {
                type: Number,
                default: 0
            },
            zoomFlag:{
                type: Boolean,
                default: false
            }
        },
        data(){
            return {
                index: this.initialIndex,
                visible: false,
                isloading: false,
                isGrab: false,
                transform: {
                    scale: 1,
                    deg: 0,
                    offsetX: 0,
                    offsetY: 0,
                    enableTransition: false
                }
            }
        },
        mounted(){
            this.bingWheelKeyBaordEvent()
            
        },
        methods:{
            handleActions(action, options = {}) {
                if (this.loading) return;
                const { zoomRate, rotateDeg, enableTransition } = {
                    zoomRate: 0.2,
                    rotateDeg: 90,
                    enableTransition: true,
                    ...options
                };
                const { transform } = this;
                switch (action) {
                    case 'zoomOut':
                        if (transform.scale > 0.2) {
                            transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3));
                        }
                        break;
                    case 'zoomIn':
                        transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3));
                        break;
                    case 'clocelise':
                        transform.deg += rotateDeg;
                        break;
                    case 'anticlocelise':
                        transform.deg -= rotateDeg;
                        break;
                }
                transform.enableTransition = enableTransition;
            },
            bingWheelKeyBaordEvent(){
                this._mouseWheelHandler = this.rafThrottle(e => {
                    const delta = e.wheelDelta ? e.wheelDelta : -e.detail;
                    if (delta > 0) {
                        this.handleActions('zoomIn', {
                            zoomRate: 0.03,
                            enableTransition: false
                        });
                    } else {
                        this.handleActions('zoomOut', {
                            zoomRate: 0.03,
                            enableTransition: false
                        });
                    }
                });
                document.addEventListener('mousewheel', this._mouseWheelHandler, false);
            },
            handleImgLoad(){
                this.isloading = false
            },
            handleImgError(){
                this.isloading = false;
                console.log('图片加载出错');
                
            },
            rafThrottle(fn) {
                let locked = false;
                return function(...args) {
                    if (locked) return;
                    locked = true;
                    window.requestAnimationFrame(_ => {
                        fn.apply(this, args);
                        locked = false;
                    });
                };
            },
            closebigImg(){
                this.visible = false
                this.$emit('close-bigImg');
            },
            handleMouseDown(e) {
                if (this.loading || e.button !== 0) return;
                const { offsetX, offsetY } = this.transform;
                const startX = e.pageX;
                const startY = e.pageY;
                this._dragHandler = this.rafThrottle(ev => {
                    this.transform.offsetX = offsetX + ev.pageX - startX;
                    this.transform.offsetY = offsetY + ev.pageY - startY;
                });
                this.isGrab = true
                document.addEventListener('mousemove', this._dragHandler, false);
                document.addEventListener('mouseup', ev => {
                    this.isGrab = false
                    document.removeEventListener('mousemove', this._dragHandler, false);
                }, false);
                e.preventDefault();
            },
        },
        computed: {
            showUrl(){
                return this.imageList[this.index];
            },
            isfirst(){
                return this.index === 0;
            },
            isLast(){
                return this.index === this.imageList.length - 1;
            },
            imgStyle(){
                const { scale, deg, offsetX, offsetY, enableTransition } = this.transform;
                const { isGrab } = this
                const style = {
                    transform: `scale(${scale}) rotate(${deg}deg)`,
                    transition: enableTransition ? 'transform .3s' : '',
                    'margin-left': `${offsetX}px`,
                    'margin-top': `${offsetY}px`,
                    cursor: isGrab ? 'grabbing' : 'grab'
                };
                // if (this.mode === Mode.CONTAIN) {
                //     style.maxWidth = style.maxHeight = '100%';
                // }
                return style;
            }
        },
        watch:{
            showUrl(val){
                this.$nextTick(() => {
                    if(!this.$refs['img'].complete){
                        this.isloading = true
                    }
                })
            }
        },
    }
</script>
<style scoped>
    .bigImg {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 20000;
        -webkit-user-select: none;
        -moz-user-select: none;
        -ms-user-select: none;
        user-select: none
    }
    .bigImg_Box{
        position: absolute;
        z-index: 230;
         100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
    }
    .back_mask{
        position: absolute;
         100%;
        height: 100%;
        top: 0;
        left: 0;
        opacity: .5;
        background: #000
    }
    .bigImg_image{
        max-height: 95%;
        max- 90%;
        position: absolute;
        cursor: grab;
    }
    .bigImg_close{
        position: absolute;
        top: 50px;
        right: 100px;
        height: 30px;
         30px;
        z-index: 2222;
    }
    .bigImg_close_Icon{
        font-size: 30px;
        color: white;
    }
    .bigImg_action{
        position: absolute;
        bottom: 50px;
        left: calc(50% - 100px);
         200px;
        z-index: 250;
        height: 36px;
        display: flex;
        justify-content: space-evenly;
        align-items: center;
        border-radius: 18px;
        background: #eaeaea;
        color: #333333;
    }
    .bigImg_action span{
         24%;
        display: block;
        height: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
    }
</style>
 
 
================================================================
image.js      //新建vue    将上面的子组件包裹起来      初始化的将父vue初始化   然后将子组件显示。      中心思想就是: 道生一,一生二,二生三,三生万物,
================================================================
 
import ShowLargeImage from './image.vue'
import Vue from 'vue';

ShowLargeImage.initialization = (props) =>{
    const _props = props || {};

    const Initialization = new Vue({
        data: Object.assign({}, _props, {
            imageList: [],
            initialIndex: 0,
            zoomFlag: false,
        }),
        render(h){
            return h(ShowLargeImage, {
                props: Object.assign({}, _props, {
                    imageList: this.imageList,
                    initialIndex: this.initialIndex,
                    zoomFlag: this.zoomFlag,
                }),
                on:{
                   "close-bigImg": this.closeBigImg
                }
            })
        },
        methods:{
            closeBigImg(){
                this.$destroy();
                document.body.removeChild(this.$el);
                this.onRemove();
            },
        }
    })

    const component = Initialization.$mount();
    document.body.appendChild(component.$el);
    const showLargeImage = Initialization.$children[0];
    
    return {
        show(propsFun= {}){
            if ('imageList' in propsFun){
                showLargeImage.$parent.imageList = propsFun.imageList
            }
            if ('initialIndex' in propsFun) {
                showLargeImage.$parent.initialIndex = propsFun.initialIndex;
            }
            
            if('zoomFlag' in propsFun){
                showLargeImage.$parent.zoomFlag = propsFun.zoomFlag
            }
            showLargeImage.$parent.onRemove = propsFun.onRemove;
            showLargeImage.visible = true;

        },
        remove(){
            showLargeImage.visible = false;
        },
        component: showLargeImage
    }   
}


export default ShowLargeImage;
 
 
================================================================
index.js   将组件全局化
================================================================
import ShowLargeImage from './image.js'

let newShowLargeImage

ShowLargeImage.show = function(props= {}){
    newShowLargeImage = newShowLargeImage || ShowLargeImage.initialization({props});
    props.onRemove = function(){
        newShowLargeImage = null;
    }
    newShowLargeImage.show(props);
}

ShowLargeImage.remove = function(){
    if(!newShowLargeImage){
        return
    }
    newShowLargeImage = null
}


const IShowLargeImage = {
    install: function(Vue){
        // Vue.component('IShowLargeImage', ShowLargeImage)
        Vue.prototype.IShowLargeImage = ShowLargeImage
    }
}


export default IShowLargeImage;
原文地址:https://www.cnblogs.com/HePandeFeng/p/13032456.html