[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:
neverland 2017-10-12 20:26:28 -05:00 committed by GitHub
parent 4dfa56e796
commit d7cee6e8f4
4 changed files with 78 additions and 154 deletions

View File

@ -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;
});
} }
} }
}; };

View File

@ -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;

View File

@ -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 {

View File

@ -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);
}); });
}); });