Skip to content

Instantly share code, notes, and snippets.

@john-yuan
Last active February 20, 2019 03:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save john-yuan/baac7204edd98f76cc3fee9e9688c011 to your computer and use it in GitHub Desktop.
Save john-yuan/baac7204edd98f76cc3fee9e9688c011 to your computer and use it in GitHub Desktop.
/**
* 主域名跨标签轻量级事件通知机制
*
* 主要用于具有相同主域名的多个浏览器标签之间的事件通知。比如现在浏览器中有两个标签,
* 第一个标签的域名为: 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