Last active
February 20, 2019 03:31
-
-
Save john-yuan/baac7204edd98f76cc3fee9e9688c011 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 主域名跨标签轻量级事件通知机制 | |
* | |
* 主要用于具有相同主域名的多个浏览器标签之间的事件通知。比如现在浏览器中有两个标签, | |
* 第一个标签的域名为: site1.example.com;第二个标签的域名为:site2.example.com。 | |
* 两个标签中都可以进行登录操作,但在登录之后需要通知另一个标签。此时便可以使用这个类。 | |
* | |
* 注意: | |
* | |
* 1. 这个类使用 cookie 作为通信媒介 | |
* 2. 这个类使用 setInterval 定期检查 cookie 中对应的值是否改变 | |
* | |
* @typedef {Object.<string, *>} MainDomainCrossTabNotificationOptions 配置信息 | |
* @property {string} eventName 事件名称:这个值会作为 cookie 的键名,推荐使用变量名规则进行命名 | |
* @property {string} domain 主域名:一个以点开头的主域名,比如 .example.com | |
* @property {number} [interval=300] 时间间隔:定期检查 cookie 值变化的时间间隔,默认 300 毫秒 | |
* @property {(notification: MainDomainCrossTabNotification) => void} listener | |
* 监听回调:事件发生时会调用此函数,并停止继续监听(用户可以在这个回调选择手动继续监听) | |
* | |
* @class | |
* @param {MainDomainCrossTabNotificationOptions} options 配置信息 | |
*/ | |
var MainDomainCrossTabNotification = function (options) { | |
if (!options || typeof options !== 'object') { | |
throw new Error('options is required'); | |
} | |
var store = this.store = {}; | |
var eventName = options.eventName; | |
var domain = options.domain; | |
var interval = options.interval; | |
var listener = options.listener; | |
// 检查是否设置 eventName | |
if (!eventName) { | |
throw new Error('options.eventName is required'); | |
} else if (typeof eventName !== 'string') { | |
throw new Error('options.eventName is not a string') | |
} | |
eventName = eventName.replace(/^\s+|\s+$/g, ''); | |
if (!eventName) { | |
throw new Error('options.eventName can not be empty'); | |
} | |
// 检查是否设置 domain | |
if (!domain) { | |
throw new Error('options.domain is required'); | |
} else if (typeof domain !== 'string') { | |
throw new Error('options.domain is not a string') | |
} | |
domain = domain.replace(/^\s+|\s+$/g, ''); | |
if (!domain) { | |
throw new Error('options.domain can not be empty'); | |
} | |
// 检查是否设置 interval | |
if ('interval' in options) { | |
if (typeof interval !== 'number' || isNaN(interval)) { | |
throw new Error('options.interval is not a number'); | |
} else if (interval <= 0) { | |
throw new Error('options.interval must be greater than 0'); | |
} | |
} else { | |
interval = 300; | |
} | |
// 检查是否设置 listener | |
if (typeof listener !== 'function') { | |
throw new Error('options.listener must be a function'); | |
} | |
store.eventName = encodeURIComponent(eventName); | |
store.domain = domain; | |
store.interval = interval; | |
store.listener = listener; | |
store.intervalId = null; | |
store.value = this.value(); | |
}; | |
/** | |
* 获取当前事件值 | |
* | |
* @returns {number} | |
*/ | |
MainDomainCrossTabNotification.prototype.value = function () { | |
var store = this.store; | |
var eventName = store.eventName; | |
var cookieStr = document.cookie || ''; | |
var cookies = cookieStr.split(/\;\s*/); | |
var i = 0; | |
var l = cookies.length; | |
var cookie = null; | |
var value = 0; | |
for ( ; i < l; i += 1) { | |
cookie = cookies[i].split('='); | |
if (cookie[0] === eventName) { | |
value = cookie[1]; | |
break; | |
} | |
} | |
value = parseInt(value || 0, 10) || 0; | |
return value; | |
}; | |
/** | |
* 改变当前事件值,并通知其它标签页事件发生 | |
* | |
* @returns {ThisType} | |
*/ | |
MainDomainCrossTabNotification.prototype.notify = function () { | |
var store = this.store; | |
var eventName = store.eventName; | |
var domain = store.domain; | |
var value = (new Date()).getTime(); | |
var cookieStr = eventName + '=' + value + '; path=/; domain=' + domain; | |
store.value = value; | |
document.cookie = cookieStr; | |
return this; | |
}; | |
/** | |
* 停止监听事件 | |
* | |
* @returns {ThisType} | |
*/ | |
MainDomainCrossTabNotification.prototype.stop = function () { | |
var store = this.store; | |
if (store.intervalId !== null) { | |
clearInterval(store.intervalId); | |
store.intervalId = null; | |
} | |
return this; | |
}; | |
/** | |
* 开始监听事件 | |
* | |
* @returns {ThisType} | |
*/ | |
MainDomainCrossTabNotification.prototype.listen = function () { | |
var self = this; | |
var store = this.store; | |
this.stop(); | |
store.intervalId = setInterval(function () { | |
var value = self.value(); | |
if (value !== store.value) { | |
self.stop(); | |
store.value = value; | |
store.listener.call(null, self); | |
} | |
}, store.interval); | |
return this; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment