Loading: full screen loading is now singleton

pull/1503/merge
Leopoldthecoder 2016-11-29 16:04:58 +08:00 committed by cinwell.li
parent 4b9a0125c2
commit 707a0d5a60
4 changed files with 58 additions and 14 deletions

View File

@ -200,6 +200,14 @@ The parameter `options` is the configuration of Loading, and its details can be
let loadingInstance = Loading.service(options);
loadingInstance.close();
```
Note that in this case the full screen Loading is singleton. If a new full screen Loading is invoked before an existing one is closed, the existing full screen Loading instance will be returned instead of actually creating another Loading instance:
```javascript
let loadingInstance1 = Loading.service({ fullscreen: true });
let loadingInstance2 = Loading.service({ fullscreen: true });
console.log(loadingInstance1 === loadingInstance2); // true
```
Calling the `close` method on any one of them can close this full screen Loading.
If Element is imported entirely, a globally method `$loading` will be registered to Vue.prototype. You can invoke it like this: `this.$loading(options)`, and it also returns a Loading instance.
### Options

View File

@ -204,6 +204,14 @@ Loading.service(options);
let loadingInstance = Loading.service(options);
loadingInstance.close();
```
需要注意的是,以服务的方式调用的全屏 Loading 是单例的:若在前一个全屏 Loading 关闭前再次调用全屏 Loading并不会创建一个新的 Loading 实例,而是返回现有全屏 Loading 的实例:
```javascript
let loadingInstance1 = Loading.service({ fullscreen: true });
let loadingInstance2 = Loading.service({ fullscreen: true });
console.log(loadingInstance1 === loadingInstance2); // true
```
此时调用它们中任意一个的 `close` 方法都能关闭这个全屏 Loading。
如果完整引入了 Element那么 Vue.prototype 上会有一个全局方法 `$loading`,它的调用方式为:`this.$loading(options)`,同样会返回一个 Loading 实例。
### Options

View File

@ -12,16 +12,22 @@ const defaults = {
customClass: ''
};
let originalPosition, originalOverflow;
let fullscreenLoading;
LoadingConstructor.prototype.originalPosition = '';
LoadingConstructor.prototype.originalOverflow = '';
LoadingConstructor.prototype.close = function() {
if (this.fullscreen && originalOverflow !== 'hidden') {
document.body.style.overflow = originalOverflow;
if (this.fullscreen && this.originalOverflow !== 'hidden') {
document.body.style.overflow = this.originalOverflow;
}
if (this.fullscreen || this.body) {
document.body.style.position = originalPosition;
document.body.style.position = this.originalPosition;
} else {
this.target.style.position = originalPosition;
this.target.style.position = this.originalPosition;
}
if (this.fullscreen) {
fullscreenLoading = undefined;
}
this.$el &&
this.$el.parentNode &&
@ -29,13 +35,13 @@ LoadingConstructor.prototype.close = function() {
this.$destroy();
};
const addStyle = (options, parent, element) => {
const addStyle = (options, parent, instance) => {
let maskStyle = {};
if (options.fullscreen) {
originalPosition = document.body.style.position;
originalOverflow = document.body.style.overflow;
instance.originalPosition = document.body.style.position;
instance.originalOverflow = document.body.style.overflow;
} else if (options.body) {
originalPosition = document.body.style.position;
instance.originalPosition = document.body.style.position;
['top', 'left'].forEach(property => {
let scroll = property === 'top' ? 'scrollTop' : 'scrollLeft';
maskStyle[property] = options.target.getBoundingClientRect()[property] +
@ -47,10 +53,10 @@ const addStyle = (options, parent, element) => {
maskStyle[property] = options.target.getBoundingClientRect()[property] + 'px';
});
} else {
originalPosition = parent.style.position;
instance.originalPosition = parent.style.position;
}
Object.keys(maskStyle).forEach(property => {
element.style[property] = maskStyle[property];
instance.$el.style[property] = maskStyle[property];
});
};
@ -65,6 +71,9 @@ const Loading = (options = {}) => {
} else {
options.body = true;
}
if (options.fullscreen && fullscreenLoading) {
return fullscreenLoading;
}
let parent = options.body ? document.body : options.target;
let instance = new LoadingConstructor({
@ -72,14 +81,17 @@ const Loading = (options = {}) => {
data: options
});
addStyle(options, parent, instance.$el);
if (originalPosition !== 'absolute') {
addStyle(options, parent, instance);
if (instance.originalPosition !== 'absolute') {
parent.style.position = 'relative';
}
if (options.fullscreen && options.lock) {
parent.style.overflow = 'hidden';
}
parent.appendChild(instance.$el);
if (options.fullscreen) {
fullscreenLoading = instance;
}
return instance;
};

View File

@ -4,10 +4,11 @@ import LoadingRaw from 'packages/loading';
const Loading = LoadingRaw.service;
describe('Loading', () => {
let vm, loadingInstance;
let vm, loadingInstance, loadingInstance2;
afterEach(() => {
destroyVM(vm);
loadingInstance && loadingInstance.close();
loadingInstance2 && loadingInstance2.close();
});
describe('as a directive', () => {
@ -207,6 +208,21 @@ describe('Loading', () => {
expect(mask.classList.contains('is-fullscreen')).to.true;
});
it('fullscreen singleton', done => {
loadingInstance = Loading({ fullScreen: true });
setTimeout(() => {
loadingInstance2 = Loading({ fullScreen: true });
setTimeout(() => {
let masks = document.querySelectorAll('.el-loading-mask');
expect(masks.length).to.equal(1);
loadingInstance2.close();
masks = document.querySelectorAll('.el-loading-mask');
expect(masks.length).to.equal(0);
done();
}, 100);
}, 100);
});
it('lock', () => {
loadingInstance = Loading({ lock: true });
expect(document.body.style.overflow).to.equal('hidden');