mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[new feature] ImagePreview reconstruct (#201)
* [Document] add english document of Checkbox * [Document] add english document of Field * [Document] add english document of NumberKeyboard * [bugfix] NumberKeyboard should not dispaly title when title is empty * [Document] add english document of PasswordInput * [Document] add english document of Radio * [document] add english document of Switch * [bugfix] remove redundent styles in english document * [Document] fix details * fix Switch test cases * [bugfix] Swipe shouid reinitialize when item changes * [new feature] ImagePreview reconstruct
This commit is contained in:
parent
4dfa56e796
commit
d7cee6e8f4
@ -1,17 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition name="image-fade">
|
<div
|
||||||
<div class="van-image-preview" ref="previewContainer" v-show="value">
|
v-show="value"
|
||||||
|
class="van-image-preview"
|
||||||
|
@touchstart="onTouchStart"
|
||||||
|
@touchmove="onTouchMove"
|
||||||
|
@touchend="onTouchEnd"
|
||||||
|
@touchcancel="onTouchEnd"
|
||||||
|
>
|
||||||
<van-swipe>
|
<van-swipe>
|
||||||
<van-swipe-item v-for="(item, index) in images" :key="index">
|
<van-swipe-item v-for="(item, index) in images" :key="index">
|
||||||
<img class="van-image-preview__image" @load="handleLoad" :src="item" alt="">
|
<img class="van-image-preview__image" :src="item" >
|
||||||
</van-swipe-item>
|
</van-swipe-item>
|
||||||
</van-swipe>
|
</van-swipe>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue';
|
|
||||||
import Popup from '../mixins/popup';
|
import Popup from '../mixins/popup';
|
||||||
import Swipe from '../swipe';
|
import Swipe from '../swipe';
|
||||||
import SwipeItem from '../swipe-item';
|
import SwipeItem from '../swipe-item';
|
||||||
@ -30,11 +34,9 @@ export default {
|
|||||||
overlay: {
|
overlay: {
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
|
||||||
lockOnScroll: {
|
lockOnScroll: {
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
|
||||||
closeOnClickOverlay: {
|
closeOnClickOverlay: {
|
||||||
default: true
|
default: true
|
||||||
}
|
}
|
||||||
@ -42,73 +44,31 @@ export default {
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
images: [],
|
images: []
|
||||||
viewportSize: null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
handleLoad(event) {
|
onTouchStart(event) {
|
||||||
const container = this.$refs.previewContainer;
|
this.touchStartTime = new Date();
|
||||||
const containerSize = container.getBoundingClientRect();
|
this.touchStartX = event.touches[0].clientX;
|
||||||
const ratio = containerSize.width / containerSize.height;
|
this.touchStartY = event.touches[0].clientY;
|
||||||
const target = event.currentTarget;
|
this.deltaX = 0;
|
||||||
const targetRatio = target.width / target.height;
|
this.deltaY = 0;
|
||||||
|
|
||||||
const centerClass = 'van-image-preview__image--center';
|
|
||||||
const bigClass = 'van-image-preview__image--big';
|
|
||||||
|
|
||||||
if (targetRatio > ratio) {
|
|
||||||
target.className += (' ' + centerClass);
|
|
||||||
} else {
|
|
||||||
target.className += (' ' + bigClass);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
close() {
|
onTouchMove(event) {
|
||||||
/* istanbul ignore if */
|
event.preventDefault();
|
||||||
if (this.closing) return;
|
this.deltaX = event.touches[0].clientX - this.touchStartX;
|
||||||
|
this.deltaY = event.touches[0].clientY - this.touchStartY;
|
||||||
this.closing = true;
|
|
||||||
|
|
||||||
this.value = false;
|
|
||||||
|
|
||||||
/* istanbul ignore else */
|
|
||||||
if (this.lockOnScroll) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (this.overlay && this.bodyOverflow !== 'hidden') {
|
|
||||||
document.body.style.overflow = this.bodyOverflow;
|
|
||||||
}
|
|
||||||
this.bodyOverflow = null;
|
|
||||||
}, 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.opened = false;
|
|
||||||
this.doAfterClose();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
onTouchEnd() {
|
||||||
const supportTouch = !Vue.prototype.$isServer && 'ontouchstart' in window;
|
// prevent long tap to close component
|
||||||
const container = this.$refs.previewContainer;
|
const deltaTime = new Date() - this.touchStartTime;
|
||||||
|
if (deltaTime < 100 && Math.abs(this.deltaX) < 20 && Math.abs(this.deltaY) < 20) {
|
||||||
/* istanbul ignore else */
|
|
||||||
if (supportTouch) {
|
|
||||||
let touchStartTime;
|
|
||||||
|
|
||||||
container.addEventListener('touchstart', () => {
|
|
||||||
touchStartTime = new Date();
|
|
||||||
});
|
|
||||||
container.addEventListener('touchend', () => {
|
|
||||||
/* istanbul ignore else */
|
|
||||||
if (new Date() - touchStartTime < 100) {
|
|
||||||
this.value = false;
|
this.value = false;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
} else {
|
|
||||||
container.addEventListener('click', () => {
|
|
||||||
this.value = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -6,30 +6,19 @@ let instance;
|
|||||||
const ImagePreviewConstructor = Vue.extend(ImagePreview);
|
const ImagePreviewConstructor = Vue.extend(ImagePreview);
|
||||||
|
|
||||||
const initInstance = () => {
|
const initInstance = () => {
|
||||||
/* istanbul ignore if */
|
|
||||||
if (Vue.prototype.$isServer) return;
|
|
||||||
instance = new ImagePreviewConstructor({
|
instance = new ImagePreviewConstructor({
|
||||||
el: document.createElement('div')
|
el: document.createElement('div')
|
||||||
});
|
});
|
||||||
|
document.body.appendChild(instance.$el);
|
||||||
};
|
};
|
||||||
|
|
||||||
var ImagePreviewBox = images => {
|
const ImagePreviewBox = images => {
|
||||||
/* istanbul ignore if */
|
|
||||||
if (Vue.prototype.$isServer) return;
|
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
initInstance();
|
initInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* istanbul ignore else */
|
|
||||||
if (!instance.value) {
|
|
||||||
instance.images = images;
|
instance.images = images;
|
||||||
|
|
||||||
document.body.appendChild(instance.$el);
|
|
||||||
|
|
||||||
Vue.nextTick(() => {
|
|
||||||
instance.value = true;
|
instance.value = true;
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ImagePreviewBox;
|
export default ImagePreviewBox;
|
||||||
|
@ -1,30 +1,21 @@
|
|||||||
@import './common/var.css';
|
@import './common/var.css';
|
||||||
|
|
||||||
.van-image-preview {
|
.van-image-preview {
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
position: fixed;
|
||||||
|
|
||||||
&__image {
|
&__image {
|
||||||
position: absolute;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
right: 0;
|
||||||
&--center {
|
bottom: 0;
|
||||||
width: 100%;
|
margin: auto;
|
||||||
height: auto;
|
max-width: 100%;
|
||||||
top: 50%;
|
max-height: 100%;
|
||||||
transform: translate3d(0, -50%, 0);
|
position: absolute;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.van-image-preview__image--big {
|
|
||||||
height: 100%;
|
|
||||||
width: auto;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate3d(-50%, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.van-swipe {
|
.van-swipe {
|
||||||
|
@ -1,65 +1,49 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import { mount } from 'avoriaz';
|
||||||
|
import { triggerTouch } from '../utils';
|
||||||
import ImagePreview from 'packages/image-preview';
|
import ImagePreview from 'packages/image-preview';
|
||||||
import Wrapper from 'avoriaz/dist/Wrapper';
|
import ImagePreviewVue from 'packages/image-preview/image-preview';
|
||||||
|
|
||||||
|
const images = [
|
||||||
|
'https://img.yzcdn.cn/upload_files/2017/03/15/FkubrzN7AgGwLlTeb1E89-T_ZjBg.png',
|
||||||
|
'https://img.yzcdn.cn/upload_files/2017/03/14/FmTPs0SeyQaAOSK1rRe1sL8RcwSY.jpeg',
|
||||||
|
'https://img.yzcdn.cn/upload_files/2017/03/15/FvexrWlG_WxtCE9Omo5l27n_mAG_.jpeg'
|
||||||
|
];
|
||||||
|
|
||||||
describe('ImagePreview', () => {
|
describe('ImagePreview', () => {
|
||||||
beforeEach(() => {
|
let wrapper;
|
||||||
document.body.style.overflow = '';
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
const el = document.querySelector('.van-image-preview');
|
wrapper && wrapper.destroy();
|
||||||
if (!el) return;
|
|
||||||
if (el.parentNode) {
|
|
||||||
el.parentNode.removeChild(el);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('create a image preview', (done) => {
|
it('call ImagePreview Function', (done) => {
|
||||||
ImagePreview([
|
ImagePreview(images);
|
||||||
'https://img.yzcdn.cn/upload_files/2017/03/15/FkubrzN7AgGwLlTeb1E89-T_ZjBg.png',
|
Vue.nextTick(() => {
|
||||||
'https://img.yzcdn.cn/upload_files/2017/03/14/FmTPs0SeyQaAOSK1rRe1sL8RcwSY.jpeg',
|
expect(document.querySelectorAll('.van-image-preview img').length).to.equal(3);
|
||||||
'https://img.yzcdn.cn/upload_files/2017/03/15/FvexrWlG_WxtCE9Omo5l27n_mAG_.jpeg'
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(document.querySelector('.van-image-preview')).to.exist;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
const image = document.querySelector('.van-image-preview');
|
|
||||||
const avImage = new Wrapper({ elm: image }, () => {}, false);
|
|
||||||
avImage.trigger('click');
|
|
||||||
avImage.trigger('touchstart');
|
|
||||||
avImage.trigger('touchend');
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(document.querySelector('.van-image-preview').__vue__.$parent.value).to.be.false;
|
|
||||||
expect(document.body.style.overflow).to.equal('');
|
|
||||||
done();
|
done();
|
||||||
}, 500);
|
});
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('create a body hidden image preview', (done) => {
|
it('create a ImagePreview Component', (done) => {
|
||||||
document.body.style.overflow = 'hidden';
|
wrapper = mount(ImagePreviewVue);
|
||||||
|
wrapper.vm.images = images;
|
||||||
|
wrapper.vm.value = true;
|
||||||
|
|
||||||
ImagePreview([
|
expect(wrapper.hasClass('van-image-preview')).to.be.true;
|
||||||
'https://img.yzcdn.cn/upload_files/2017/03/15/FkubrzN7AgGwLlTeb1E89-T_ZjBg.png',
|
|
||||||
'https://img.yzcdn.cn/upload_files/2017/03/14/FmTPs0SeyQaAOSK1rRe1sL8RcwSY.jpeg',
|
|
||||||
'https://img.yzcdn.cn/upload_files/2017/03/15/FvexrWlG_WxtCE9Omo5l27n_mAG_.jpeg'
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(document.querySelector('.van-image-preview')).to.exist;
|
wrapper.vm.$nextTick(() => {
|
||||||
|
expect(wrapper.find('img').length).to.equal(3);
|
||||||
|
triggerTouch(wrapper, 'touchstart', 0, 0);
|
||||||
|
triggerTouch(wrapper, 'touchmove', 100, 100);
|
||||||
|
triggerTouch(wrapper, 'touchend', 0, 0);
|
||||||
|
expect(wrapper.vm.value).to.be.true;
|
||||||
|
|
||||||
setTimeout(() => {
|
triggerTouch(wrapper, 'touchstart', 0, 0);
|
||||||
const image = document.querySelector('.van-image-preview');
|
triggerTouch(wrapper, 'touchmove', 0, 0);
|
||||||
const avImage = new Wrapper({ elm: image }, () => {}, false);
|
triggerTouch(wrapper, 'touchend', 0, 0);
|
||||||
avImage.trigger('click');
|
expect(wrapper.vm.value).to.be.false;
|
||||||
avImage.trigger('touchstart');
|
|
||||||
avImage.trigger('touchend');
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(document.querySelector('.van-image-preview').__vue__.$parent.value).to.be.false;
|
|
||||||
expect(document.body.style.overflow).to.equal('hidden');
|
|
||||||
done();
|
done();
|
||||||
}, 500);
|
});
|
||||||
}, 500);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user