mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[bugfix] Toast: overlay blocked by other element (#740)
This commit is contained in:
parent
11f9715793
commit
bca3401d81
@ -1,5 +1,5 @@
|
|||||||
const PopupContext = {
|
export default {
|
||||||
idSeed: 1,
|
id: 1,
|
||||||
zIndex: 2000,
|
zIndex: 2000,
|
||||||
stack: [],
|
stack: [],
|
||||||
|
|
||||||
@ -11,5 +11,3 @@ const PopupContext = {
|
|||||||
return this.stack[this.stack.length - 1];
|
return this.stack[this.stack.length - 1];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PopupContext;
|
|
||||||
|
@ -26,17 +26,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
|
||||||
this._popupId = 'popup-' + context.plusKey('idSeed');
|
|
||||||
return {
|
|
||||||
opened: false,
|
|
||||||
pos: {
|
|
||||||
x: 0,
|
|
||||||
y: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
value(val) {
|
value(val) {
|
||||||
this[val ? 'open' : 'close']();
|
this[val ? 'open' : 'close']();
|
||||||
@ -44,6 +33,21 @@ export default {
|
|||||||
|
|
||||||
getContainer() {
|
getContainer() {
|
||||||
this.move();
|
this.move();
|
||||||
|
},
|
||||||
|
|
||||||
|
overlay() {
|
||||||
|
this.renderOverlay();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this._popupId = 'popup-' + context.plusKey('id');
|
||||||
|
this.pos = {
|
||||||
|
x: 0,
|
||||||
|
y: 0
|
||||||
|
};
|
||||||
|
if (this.value) {
|
||||||
|
this.open();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -51,24 +55,61 @@ export default {
|
|||||||
if (this.getContainer) {
|
if (this.getContainer) {
|
||||||
this.move();
|
this.move();
|
||||||
}
|
}
|
||||||
if (this.value) {
|
|
||||||
this.open();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.doAfterClose();
|
this.close();
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
recordPosition(e) {
|
open() {
|
||||||
|
/* istanbul ignore next */
|
||||||
|
if (this.$isServer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果属性中传入了`zIndex`,则覆盖`context`中对应的`zIndex`
|
||||||
|
if (this.zIndex !== undefined) {
|
||||||
|
context.zIndex = this.zIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lockScroll) {
|
||||||
|
document.body.classList.add('van-overflow-hidden');
|
||||||
|
on(document, 'touchstart', this.onTouchStart);
|
||||||
|
on(document, 'touchmove', this.onTouchMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renderOverlay();
|
||||||
|
this.$emit('input', true);
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
if (this.lockScroll) {
|
||||||
|
document.body.classList.remove('van-overflow-hidden');
|
||||||
|
off(document, 'touchstart', this.onTouchStart);
|
||||||
|
off(document, 'touchmove', this.onTouchMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
manager.close(this._popupId);
|
||||||
|
this.$emit('input', false);
|
||||||
|
},
|
||||||
|
|
||||||
|
move() {
|
||||||
|
if (this.getContainer) {
|
||||||
|
this.getContainer().appendChild(this.$el);
|
||||||
|
} else if (this.$parent) {
|
||||||
|
this.$parent.$el.appendChild(this.$el);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onTouchStart(e) {
|
||||||
this.pos = {
|
this.pos = {
|
||||||
x: e.touches[0].clientX,
|
x: e.touches[0].clientX,
|
||||||
y: e.touches[0].clientY
|
y: e.touches[0].clientY
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
watchTouchMove(e) {
|
onTouchMove(e) {
|
||||||
const { pos } = this;
|
const { pos } = this;
|
||||||
const dx = e.touches[0].clientX - pos.x;
|
const dx = e.touches[0].clientX - pos.x;
|
||||||
const dy = e.touches[0].clientY - pos.y;
|
const dy = e.touches[0].clientY - pos.y;
|
||||||
@ -97,64 +138,17 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
open() {
|
renderOverlay() {
|
||||||
/* istanbul ignore next */
|
|
||||||
if (this.opened || this.$isServer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果属性中传入了`zIndex`,则覆盖`context`中对应的`zIndex`
|
|
||||||
if (this.zIndex !== undefined) {
|
|
||||||
context.zIndex = this.zIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.overlay) {
|
if (this.overlay) {
|
||||||
manager.open(this, {
|
manager.open(this, {
|
||||||
id: this._popupId,
|
|
||||||
dom: this.$el,
|
|
||||||
zIndex: context.plusKey('zIndex'),
|
zIndex: context.plusKey('zIndex'),
|
||||||
className: this.overlayClass,
|
className: this.overlayClass,
|
||||||
customStyle: this.overlayStyle
|
customStyle: this.overlayStyle
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
manager.close(this._popupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.lockScroll) {
|
|
||||||
document.body.classList.add('van-overflow-hidden');
|
|
||||||
on(document, 'touchstart', this.recordPosition);
|
|
||||||
on(document, 'touchmove', this.watchTouchMove);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$el.style.zIndex = context.plusKey('zIndex');
|
this.$el.style.zIndex = context.plusKey('zIndex');
|
||||||
this.$emit('input', true);
|
|
||||||
this.opened = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
close() {
|
|
||||||
if (!this.opened || this.$isServer) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$emit('input', false);
|
|
||||||
this.opened = false;
|
|
||||||
this.doAfterClose();
|
|
||||||
},
|
|
||||||
|
|
||||||
doAfterClose() {
|
|
||||||
manager.close(this._popupId);
|
|
||||||
|
|
||||||
if (this.lockScroll) {
|
|
||||||
document.body.classList.remove('van-overflow-hidden');
|
|
||||||
off(document, 'touchstart', this.recordPosition);
|
|
||||||
off(document, 'touchmove', this.watchTouchMove);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
move() {
|
|
||||||
if (this.getContainer) {
|
|
||||||
this.getContainer().appendChild(this.$el);
|
|
||||||
} else if (this.$parent) {
|
|
||||||
this.$parent.$el.appendChild(this.$el);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -9,13 +9,13 @@ const defaultConfig = {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
open(vm, config) {
|
open(vm, config) {
|
||||||
const { id, dom } = config;
|
const exist = context.stack.some(item => item.id === vm._popupId);
|
||||||
const exist = context.stack.some(item => item.id === id);
|
|
||||||
|
|
||||||
/* istanbul ignore next */
|
/* istanbul ignore next */
|
||||||
if (!exist) {
|
if (!exist) {
|
||||||
const targetNode = dom && dom.parentNode && dom.parentNode.nodeType !== 11 ? dom.parentNode : document.body;
|
const el = vm.$el;
|
||||||
context.stack.push({ vm, id, config, targetNode });
|
const targetNode = el && el.parentNode && el.parentNode.nodeType !== 11 ? el.parentNode : document.body;
|
||||||
|
context.stack.push({ vm, config, targetNode });
|
||||||
this.update();
|
this.update();
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -24,11 +24,11 @@ export default {
|
|||||||
const { stack } = context;
|
const { stack } = context;
|
||||||
|
|
||||||
if (stack.length) {
|
if (stack.length) {
|
||||||
if (context.top.id === id) {
|
if (context.top.vm._popupId === id) {
|
||||||
stack.pop();
|
stack.pop();
|
||||||
this.update();
|
this.update();
|
||||||
} else {
|
} else {
|
||||||
context.stack = stack.filter(item => item.id !== id);
|
context.stack = stack.filter(item => item.vm._popupId !== id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -65,10 +65,8 @@ export default {
|
|||||||
onClick() {
|
onClick() {
|
||||||
if (context.top) {
|
if (context.top) {
|
||||||
const { vm } = context.top;
|
const { vm } = context.top;
|
||||||
if (vm) {
|
vm.$emit('click-overlay');
|
||||||
vm.$emit('click-overlay');
|
vm.closeOnClickOverlay && vm.close();
|
||||||
vm.closeOnClickOverlay && vm.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -6,10 +6,11 @@ const defaultOptions = {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
mask: false,
|
mask: false,
|
||||||
message: '',
|
message: '',
|
||||||
visible: true,
|
value: true,
|
||||||
duration: 3000,
|
duration: 3000,
|
||||||
position: 'middle',
|
position: 'middle',
|
||||||
forbidClick: false
|
forbidClick: false,
|
||||||
|
overlayStyle: {}
|
||||||
};
|
};
|
||||||
const parseOptions = message => isObj(message) ? message : { message };
|
const parseOptions = message => isObj(message) ? message : { message };
|
||||||
|
|
||||||
@ -28,6 +29,16 @@ function createInstance() {
|
|||||||
return queue[queue.length - 1];
|
return queue[queue.length - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// transform toast options to popup props
|
||||||
|
function transformer(options) {
|
||||||
|
options.overlay = options.mask;
|
||||||
|
if (options.forbidClick && !options.overlay) {
|
||||||
|
options.overlay = true;
|
||||||
|
options.overlayStyle = { background: 'transparent' };
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
function Toast(options = {}) {
|
function Toast(options = {}) {
|
||||||
const toast = createInstance();
|
const toast = createInstance();
|
||||||
|
|
||||||
@ -35,11 +46,11 @@ function Toast(options = {}) {
|
|||||||
...currentOptions,
|
...currentOptions,
|
||||||
...parseOptions(options),
|
...parseOptions(options),
|
||||||
clear() {
|
clear() {
|
||||||
toast.visible = false;
|
toast.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(toast, options);
|
Object.assign(toast, transformer(options));
|
||||||
clearTimeout(toast.timer);
|
clearTimeout(toast.timer);
|
||||||
|
|
||||||
if (options.duration > 0) {
|
if (options.duration > 0) {
|
||||||
|
@ -1,35 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<transition name="van-fade">
|
<transition name="van-fade">
|
||||||
<div class="van-toast-wrapper" v-show="visible">
|
<div class="van-toast" :class="[`van-toast--${displayStyle}`, `van-toast--${position}`]" v-show="value">
|
||||||
<div class="van-toast" :class="[`van-toast--${displayStyle}`, `van-toast--${position}`]">
|
<!-- text only -->
|
||||||
<!-- text only -->
|
<div v-if="displayStyle === 'text'">{{ message }}</div>
|
||||||
<div v-if="displayStyle === 'text'">{{ message }}</div>
|
<div v-if="displayStyle === 'html'" v-html="message" />
|
||||||
<div v-if="displayStyle === 'html'" v-html="message" />
|
|
||||||
|
|
||||||
<!-- with icon -->
|
<!-- with icon -->
|
||||||
<template v-if="displayStyle === 'default'">
|
<template v-if="displayStyle === 'default'">
|
||||||
<loading v-if="type === 'loading'" color="white" />
|
<loading v-if="type === 'loading'" color="white" />
|
||||||
<icon v-else class="van-toast__icon" :name="type" />
|
<icon v-else class="van-toast__icon" :name="type" />
|
||||||
<div v-if="hasMessage" class="van-toast__text">{{ message }}</div>
|
<div v-if="hasMessage" class="van-toast__text">{{ message }}</div>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
|
||||||
<div class="van-toast__overlay" :class="{ 'van-toast__overlay--mask': mask }" v-if="forbidClick || mask" />
|
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import create from '../utils/create';
|
import create from '../utils/create';
|
||||||
|
import Popup from '../mixins/popup';
|
||||||
|
|
||||||
const STYLE_LIST = ['success', 'fail', 'loading'];
|
const STYLE_LIST = ['success', 'fail', 'loading'];
|
||||||
|
|
||||||
export default create({
|
export default create({
|
||||||
name: 'toast',
|
name: 'toast',
|
||||||
|
|
||||||
|
mixins: [Popup],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
mask: Boolean,
|
|
||||||
message: [String, Number],
|
message: [String, Number],
|
||||||
forbidClick: Boolean,
|
|
||||||
type: {
|
type: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'text'
|
default: 'text'
|
||||||
@ -37,15 +35,13 @@ export default create({
|
|||||||
position: {
|
position: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'middle'
|
default: 'middle'
|
||||||
|
},
|
||||||
|
lockScroll: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
visible: false
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
displayStyle() {
|
displayStyle() {
|
||||||
return STYLE_LIST.indexOf(this.type) !== -1 ? 'default' : this.type;
|
return STYLE_LIST.indexOf(this.type) !== -1 ? 'default' : this.type;
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
display: flex;
|
display: flex;
|
||||||
color: $white;
|
color: $white;
|
||||||
z-index: 3001;
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
@ -18,20 +17,6 @@
|
|||||||
transform: translate3d(-50%, -50%, 0);
|
transform: translate3d(-50%, -50%, 0);
|
||||||
background-color: rgba(0, 0, 0, .7);
|
background-color: rgba(0, 0, 0, .7);
|
||||||
|
|
||||||
&__overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: 3000;
|
|
||||||
background-color: transparent;
|
|
||||||
|
|
||||||
&--mask {
|
|
||||||
background-color: rgba(0, 0, 0, .5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--text {
|
&--text {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
min-width: 220px;
|
min-width: 220px;
|
||||||
|
@ -8,13 +8,13 @@ describe('Toast', () => {
|
|||||||
|
|
||||||
it('create a empty toast', () => {
|
it('create a empty toast', () => {
|
||||||
Toast();
|
Toast();
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('create a toast', () => {
|
it('create a toast', () => {
|
||||||
const toast = Toast('toast');
|
const toast = Toast('toast');
|
||||||
|
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
expect(toast.message).to.equal('toast');
|
expect(toast.message).to.equal('toast');
|
||||||
expect(toast.type).to.equal('text');
|
expect(toast.type).to.equal('text');
|
||||||
expect(toast.displayStyle).to.equal('text');
|
expect(toast.displayStyle).to.equal('text');
|
||||||
@ -24,7 +24,7 @@ describe('Toast', () => {
|
|||||||
it('create a loading toast', () => {
|
it('create a loading toast', () => {
|
||||||
const toast = Toast.loading();
|
const toast = Toast.loading();
|
||||||
|
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
expect(toast.type).to.equal('loading');
|
expect(toast.type).to.equal('loading');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ describe('Toast', () => {
|
|||||||
message: 'toast'
|
message: 'toast'
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
expect(toast.message).to.equal('toast');
|
expect(toast.message).to.equal('toast');
|
||||||
expect(toast.type).to.equal('loading');
|
expect(toast.type).to.equal('loading');
|
||||||
});
|
});
|
||||||
@ -41,7 +41,7 @@ describe('Toast', () => {
|
|||||||
it('create a success toast', () => {
|
it('create a success toast', () => {
|
||||||
const toast = Toast.success('success');
|
const toast = Toast.success('success');
|
||||||
|
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
expect(toast.displayStyle).to.equal('default');
|
expect(toast.displayStyle).to.equal('default');
|
||||||
expect(toast.type).to.equal('success');
|
expect(toast.type).to.equal('success');
|
||||||
});
|
});
|
||||||
@ -51,7 +51,7 @@ describe('Toast', () => {
|
|||||||
message: 'toast'
|
message: 'toast'
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
expect(toast.message).to.equal('toast');
|
expect(toast.message).to.equal('toast');
|
||||||
expect(toast.type).to.equal('success');
|
expect(toast.type).to.equal('success');
|
||||||
});
|
});
|
||||||
@ -59,7 +59,7 @@ describe('Toast', () => {
|
|||||||
it('create a fail toast', () => {
|
it('create a fail toast', () => {
|
||||||
const toast = Toast.fail('fail');
|
const toast = Toast.fail('fail');
|
||||||
|
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
expect(toast.displayStyle).to.equal('default');
|
expect(toast.displayStyle).to.equal('default');
|
||||||
expect(toast.type).to.equal('fail');
|
expect(toast.type).to.equal('fail');
|
||||||
});
|
});
|
||||||
@ -69,7 +69,7 @@ describe('Toast', () => {
|
|||||||
message: 'toast'
|
message: 'toast'
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
expect(toast.message).to.equal('toast');
|
expect(toast.message).to.equal('toast');
|
||||||
expect(toast.type).to.equal('fail');
|
expect(toast.type).to.equal('fail');
|
||||||
});
|
});
|
||||||
@ -80,9 +80,9 @@ describe('Toast', () => {
|
|||||||
forbidClick: true
|
forbidClick: true
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(document.querySelector('.van-toast-wrapper')).to.exist;
|
expect(document.querySelector('.van-toast')).to.exist;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(document.querySelector('.van-toast__overlay')).to.exist;
|
expect(document.querySelector('.van-modal')).to.exist;
|
||||||
done();
|
done();
|
||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
@ -116,11 +116,11 @@ describe('Toast', () => {
|
|||||||
const toast1 = Toast.success('1');
|
const toast1 = Toast.success('1');
|
||||||
const toast2 = Toast.success('2');
|
const toast2 = Toast.success('2');
|
||||||
Toast.clear();
|
Toast.clear();
|
||||||
expect(toast1.visible).to.be.false;
|
expect(toast1.value).to.be.false;
|
||||||
expect(toast2.visible).to.be.true;
|
expect(toast2.value).to.be.true;
|
||||||
Toast.clear();
|
Toast.clear();
|
||||||
Toast.clear();
|
Toast.clear();
|
||||||
expect(toast2.visible).to.be.false;
|
expect(toast2.value).to.be.false;
|
||||||
Toast.allowMultiple(false);
|
Toast.allowMultiple(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user