/** * ishare.js * @author singsong * @email zhansingsong@gmail.com * @date 2016.3.6 */ ; (function (root, factory) { if (typeof define === 'function' && define.amd) { define([], factory(root)); } else if (typeof exports === 'object') { module.exports = factory(root); } else { root.ishare = factory(root); } })(typeof global !== 'undefined' ? global : this.window || this.global, function (root) { /** * 严格模式 */ 'use strict'; /** * util 单例工具类 */ var util = { /** * event 事件注册与注销 * addevent 注册事件 * removeevent 注销事件 */ event: { addevent: function (element, type, handler) { if (element.addeventlistener) { element.addeventlistener(type, handler, false); } else if (element.attachevent) { element.attachevent('on' + type, handler); } else { element['on' + type] = handler; } }, removeevent: function (element, type, handler) { if (element.removeeventlistener) { element.removeeventlistener(type, handler, false); } else if (element.detachevent) { element.detachevent('on' + type, handler); } else { element['on' + type] = null; } }, stoppropagation: function (event) { if (event.stoppropagation) { event.stoppropagation(); } else { event.cancelbubble = true; } }, preventdefault: function (event) { if (event.preventdefault) { event.preventdefault(); } else { event.returnvalue = false; } } }, /** * trim * @param {string} str 字符串 * @return {string} */ trim: function (str) { if (string.prototype.trim) { return str.trim(); } return str.replace(/^\s+|s+$/g, ''); }, /** * indexof * @param {array} arr 数组 * @param {object} item 项 * @return {number} 索引 */ indexof: function (arr, item) { if (!this.isarray(arr)) { throw new error(arr.tostring() + ' is a non-array!'); } if (array.prototype.indexof) { return arr.indexof(item); } for (var i = 0, len = arr.length; i < len; i++) { if (arr[i] === item) { return i; } } }, /** * isarray 判断是否是数组 * @param {ojbect} arr 被判断对象 * @return {boolean} */ isarray: function (arr) { if (array.isarray) { return array.isarray(arr); } return object.prototype.tostring.call(arr) === '[object array]'; }, /** * validate 验证用户输入的有效性 * @param {object} ref 参考对象 * @param {object} o 验证对象 * @return {array} 错误队列 */ validate: function (ref, o) { var _key, _result = []; if (this.isarray(o)) { for (var i = 0, item; item = o[i++];) { if (this.indexof(ref, item) < 0) { _result.push(item); } } } else { for (_key in o) { if (!(_key in ref)) { _result.push(_key); } } } if (_result.length !== 0) { throw new error('there is such no property: ' + _result.join(', ')); } }, /** * getelementtop 获取元素的offsettop * @param {domobject} element 元素 * @return {number} offsettop值 */ getelementtop: function (element) { var _actualtop = element.offsettop, _current = element.offsetparent; while (_current !== null) { _actualtop += _current.offsettop; _current = _current.offsetparent; } return _actualtop; }, /** * getelementleft 获取元素的offsetleft * @param {domobject} element 元素 * @return {number} offsetleft值 */ getelementleft: function (element) { var _actualtop = element.offsetleft, _current = element.offsetparent; while (_current !== null) { _actualtop += _current.offsetleft; _current = _current.offsetparent; } return _actualtop; }, /** * handleparameters 处理url参数 * @param {object} options 配置项 * @return {string} */ handleparameters: function (options) { var _str = ''; for (var key in options) { _str = _str + key + '=' + encodeuricomponent(options[key]) + '&'; } return _str; }, /** * extend mix-in * @return {ojbect} */ extend: function () { var _arg, _prop, _child = {}; for (_arg = 0; _arg < arguments.length; _arg++) { for (_prop in arguments[_arg]) { if (arguments[_arg].hasownproperty(_prop)) { _child[_prop] = arguments[_arg][_prop]; } } } return _child; }, /** * each 遍历数组 * @param {array} o 数组 * @param {function} callback 回调函数 * @return {object} */ each: function (o, callback) { if (!o) { return; } var _r; for (var i = 0, l = o.length; i < l; i++) { _r = callback.call(o[i], i, o[i]); } return _r; }, /** * getelementbyclassn 通过class获取元素 * @param {string} classnamestr 类名 * @param {node} parent 父元素 * @return {domobject} * * @example * getelementbyclassn('.test'); */ getelementbyclassn: function (classnamestr, parent) { if (!classnamestr) { return; } var _result = []; if (!parent && document.queryselectorall) { _result = document.queryselectorall(classnamestr); if (_result.length > 0) { return _result; } } var _cnarr = classnamestr.split('.'), _prefix = _cnarr[0] || '*', _suffix = _cnarr[1], _parent = parent ? parent : document.body, _elements = _parent.getelementsbytagname(_prefix), _classnames, _target; var _me = this; this.each(_elements, function (index, item) { if (item.nodetype === 1) { _classnames = item.classname.split(/\s+/g); _target = item; _me.each(_classnames, function (cindex, citem) { if ((citem + '') === _suffix) { _result.push(_target); } }); } }); return _result; }, /** * getmeta 通过name获取对应meta的content值 * @param {string} name meta的name * @return {string} */ getmeta: function (name) { var _metas = document.getelementsbytagname('meta'); for (var i = 0, _item; _item = _metas[i++];) { if (_item.getattribute('name') && _item.getattribute('name').tolowercase() === name) { return _item.content; } } }, /** * getimg 获取页面中第一张图片的url * @return {string} */ getimg: function () { var _imgs = this.converttoarray(document.body.getelementsbytagname('img')); if (_imgs.length === 0) { return; } return encodeuricomponent(_imgs[0].src); }, /** * getelement 获取指定元素 * @param {string} selector 选择器(仅支持class和id) */ getelement: function (selector) { var _node; if (selector.charat(0) === '#') { _node = document.getelementbyid(selector); } else { _node = this.getelementbyclassn(selector)[0]; } return _node; }, /** * parseurl 解析url * @param {object} tpl 模板 * @param {object} data 数据 * @return {object} */ parseurl: function (tpl, data) { var _tplstr = {}; for (var _name in tpl) { _tplstr[_name] = tpl[_name].replace(/{{([a-z]*)}}/g, function (match, p1) { var _key = p1.tolowercase(); if (data[_key]) { return encodeuricomponent(data[_key]); } else { return ''; } }); } return _tplstr; }, /** * isweixinbrowser 判断是否在微信中 * @return {boolean} */ isweixinbrowser: function () { var _ua = navigator.useragent.tolowercase(); return (/micromessenger/.test(_ua)) ? true : false; }, /** * converttoarray 转换为数组 * @param {nodelist} nodes nodes数组 * @return {array} */ converttoarray: function (nodes) { var _array = null; try { _array = array.prototype.slice.call(nodes, 0); } catch (ex) { // 针对ie8及之前版本 _array = new array(); for (var i = 0, len = nodes.length; i < len; i++) { _array.push(nodes[i]); } } return _array; }, /** * parseclassname 解析类名 * @param {string} classname 类名 * @param {object} tpl 模板数据 * @return {string} */ parseclassname: function (classname, tpl) { var _result = null; var _arr = classname.split(/\s+/); for (var i = 0, item; item = _arr[i++];) { if (item in tpl) { return tpl[item]; } } }, /** * getwindimension 获取可视页面的尺寸 * @return {object} */ getwindimension: function () { var _pagewidth = window.innerwidth, _pageheight = window.innerheight; if (typeof _pagewidth !== 'number') { if (document.compatmode === 'css1compat') { _pagewidth = document.documentelement.clientwidth; _pageheight = document.documentelement.clientheight; } else { _pagewidth = document.body.clientwidth; _pageheight = document.body.clientheight; } } return { pagewidth: _pagewidth, pageheight: _pageheight }; }, /** * throttle 节流优化 * @param {function} fn 回调函数 * @param {number} delay 时间间隔 */ throttle: function (fn, delay) { var timer = null; return function () { var context = this, args = arguments; cleartimeout(timer); timer = settimeout(function () { fn.apply(context, args); }, delay); }; }, /** * loadjs 加载js文件 * @param {string} url 路径 * @param {function} callback 回调函数 */ loadjs: function () { var ready = false, cb = []; return function (url, callback) { var head = document.getelementsbytagname('head')[0], node = document.createelement('script'), isloaded = document.getelementbyid('loaded'), w3c = document.dispatchevent; cb.push(callback); if (!ready) { node.setattribute('type', 'text/javascript'); node.setattribute('id', 'loaded'); node.setattribute('src', url); node[w3c ? 'onload' : 'onreadystatechange'] = function () { if (ready) { return; } if (w3c || /loaded|complete/i.test(node.readystate)) { ready = true; var temp; while (temp = cb.pop()) { temp(); } } }; (!isloaded) && (head.appendchild(node)); } else { if (callback) { callback(); } } } }() }; /** * wx 微信类 * @param {domobject} element 微信按钮节点 * @param {object} options 配置项 * */ function wx(element, url, options) { this.element = element; this.wxbox = document.createelement('div'); // 配置项 this.url = url; this.settings = options; this.style = options.style; this.bgcolor = options.bgcolor; this.eventype = options.eventype || 'mouseover'; // 默认触发方式 this.istitlevisibility = (options.istitlevisibility === void (0)) ? true : options.istitlevisibility; // 是否有标题 this.title = options.title || '分享到微信'; this.istipvisibility = (options.istipvisibility === void (0)) ? true : options.istipvisibility; // 是否有提示 this.tip = options.tip || '“扫一扫” 即可将网页分享到朋友圈。'; this.updownflag = '';// 保存up|down this.status = false; // 保存状态 this.visibility = false;// 保存可见性 this.qrcode = null; // 保存二维码 } wx.prototype.qrcode = null;// 保存二维码 wx.prototype = function () { return { constructor: wx, init: function () { //this.render(); this.init = this.show; this.bindevent(); }, loadqrcode: function () { // 加载qrcode库 var js = document.scripts; var path = ""; var c = js.length; for (var i = 0; i < c; i++) { var it = js[i]; var src = it.src; if (src.indexof("ishare") >= 0) { path = src.substring(0, src.lastindexof('/') + 1) } } util.loadjs(path + 'qrcode.min.js', this.startqr()); }, render: function () { var _upflag = '', _downflag = '', // _widthstyle = (!this.istitlevisibility || !this.istipvisibility) ? 'width: 110px;' : 'width : 150px;', _imgstyle = '',//待定 _titlestyle = '',//待定 _tipstyle = '', //待定 _bgcolor = this.bgcolor ? this.bgcolor : '#ddd', _radius = ''; // 判断上下 if (util.getwindimension().pageheight / 2 < util.getelementtop(this.element)) { _downflag = ''; _upflag = 'display:none;'; this.updownflag = 'down'; _radius = 'border-bottom-left-radius: 0;'; } else { _downflag = 'display:none;'; _upflag = ''; this.updownflag = 'up'; _radius = 'border-top-left-radius: 0;'; } var _containerhtml = '
', _titlehtml = this.istitlevisibility ? '

' + this.title + '

' : '', _imghtml = '
', _tiphtml = this.istipvisibility ? '

' + this.tip + '

' : '', _uparrowhtml = '
', _downarrowhtml = '
'; // 拼接wxhtml var wxstr = _uparrowhtml + _containerhtml + _titlehtml + _imghtml + _tiphtml + _downarrowhtml; this.wxbox.innerhtml = wxstr; this.wxbox.style.csstext = 'position:absolute; left: -99999px;'; this.element.appendchild(this.wxbox); this.loadqrcode(); }, setlocation: function (flag) { var _boxh = this.wxbox.offsetheight, _ew = this.element.offsetwidth, _eh = this.element.offsetheight, _boxstyle = 'position:absolute; color: #000;z-index: 99999;'; _boxstyle = _boxstyle + 'left: ' + (_ew / 2 - 12) + 'px;'; if (this.updownflag === 'down') { _boxstyle = _boxstyle + 'bottom: ' + (_eh) + 'px;'; } else { _boxstyle = _boxstyle + 'top: ' + (_eh) + 'px;'; } this.wxbox.style.csstext = _boxstyle + this.style; flag && (this.hide()); }, bindevent: function () { var _me = this; if (this.eventype === 'click') { util.event.addevent(this.element, 'click', function (e) { var event = e || window.event; util.event.stoppropagation(event); util.event.preventdefault(event); if (!_me.visibility) { _me.show(); } else { _me.hide(); } }); } else { util.event.addevent(this.element, 'mouseover', function (e) { var event = e || window.event; // util.event.stoppropagation(event); _me.show(); }); util.event.addevent(this.element, 'mouseout', function (e) { var event = e || window.event; // util.event.stoppropagation(event); _me.hide(); }); } }, startqr: function () { var me = this; return function () { if (!me.qrcode) { me.qrcode = new qrcode(util.getelementbyclassn('.qrcode', me.wxbox)[0], { text: me.url, width: me.settings.qrcodew, height: me.settings.qrcodeh, colordark: me.settings.qrcodefgc, colorlight: me.settings.qrcodebgc }); } } }, show: function () { this.status = true; this.render(); this.setlocation(true); this.wxbox.style.display = 'block'; this.visibility = true; this.show = function () { this.wxbox.style.display = 'block'; this.visibility = true; } }, hide: function () { this.wxbox.style.display = 'none'; this.visibility = false; } }; }(); /** * ishare 分享 * @param {object} options 配置项 * @property container * @property config * * @description 提供两种初始化方式 * #1 单例模式 * #2 实例化模式 */ function ishare(options) { var defaults = { title: document.title, url: location.href, host: location.origin || '', description: util.getmeta('description'), image: util.getimg(), sites: ['ishare_weibo', 'ishare_qq', 'ishare_wechat', 'ishare_tencent', 'ishare_douban', 'ishare_qzone', 'ishare_renren', 'ishare_youdaonote', 'ishare_facebook', 'ishare_linkedin', 'ishare_twitter', 'ishare_googleplus', 'ishare_tumblr', 'ishare_pinterest'], initialized: true, istitle: true, isabroad: false, wxoptions: { qrcodew: 120, qrcodeh: 120, qrcodebgc: '#fff', qrcodefgc: '#000', bgcolor: '#2bad13' } }; var configuration = options || window.ishare_config; if (configuration) { if (configuration.container) { if (util.getelement(configuration.container)) { this.container = util.getelement(configuration.container); } else { throw new error('there is such no classname|id: "' + configuration.container + '".'); } } else { throw new error('container property is required.'); } } else { throw new error('container property is required.'); } var datasites = this.container.getattribute('data-sites'), datasitesarr = datasites ? datasites.split(/\s*,\s*/g) : null; /* 验证用户输入的有效性 */ (datasitesarr) && (util.validate(defaults.sites, datasitesarr)); (configuration.config) && (util.validate(defaults, configuration.config)); (configuration.config.sites) && (util.validate(defaults.sites, configuration.config.sites)); /* wx */ this.wx = null; /* 保存defaults */ this.defaults = defaults; this.datasites = datasitesarr ? { sites: datasitesarr } : {}; this.config = configuration.config ? configuration.config : {}; // 处理isabroad if ((this.config.isabroad === void (0))) { this.config.sites = this.defaults.sites; // 默认 } else { if (this.config.isabroad) { this.config.sites = defaults.sites.slice(8); // 国外 } else { this.config.sites = defaults.sites.slice(0, 8); // 国内 } } /* 验证是否在微信中 */ if (util.isweixinbrowser()) { (this.defaults.indexof('ishare_wechat') > -1) && (this.defaults.splice(this.defaults.indexof('ishare_wechat'), 1)); (this.datasites.indexof('ishare_wechat') > -1) && (this.datasites.splice(this.datasites.indexof('ishare_wechat'), 1)); (this.config.indexof('ishare_wechat') > -1) && (this.config.splice(this.config.indexof('ishare_wechat'), 1)); } this.settings = util.extend(defaults, this.config, this.datasites); this.settings.wxoptions = util.extend(defaults.wxoptions, this.config.wxoptions); this.init(); } ishare.prototype = (function () { // 接口模板 var _templates = { ishare_qq: 'http://connect.qq.com/widget/shareqq/index.html?url={{url}}&title={{title}}&desc={{description}}&summary=&pics={{image}}', ishare_qzone: 'http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url={{url}}&title={{title}}&summary={{description}}&pics={{image}}&desc=&site=', ishare_tencent: 'http://share.v.t.qq.com/index.php?c=share&a=index&title={{title}}&url={{url}}&pic={{image}}', ishare_weibo: 'http://service.weibo.com/share/share.php?url={{url}}&title={{title}}&pic={{image}}', ishare_wechat: '', ishare_douban: 'http://shuo.douban.com/!service/share?href={{url}}&name={{title}}&text={{description}}&image={{image}}', ishare_renren: 'http://widget.renren.com/dialog/share?resourceurl={{url}}&title={{title}}&pic={{image}}&description={{description}}', ishare_youdaonote: 'http://note.youdao.com/memory/?title={{title}}&pic={{image}}&summary={{description}}&url={{url}}', ishare_linkedin: 'http://www.linkedin.com/sharearticle?mini=true&ro=true&title={{title}}&url={{url}}&summary={{description}}&armin=armin', ishare_facebook: 'https://www.facebook.com/sharer/sharer.php?s=100&p[title]={{title}}p[summary]={{description}}&p[url]={{url}}&p[images]={{image}}', ishare_twitter: 'https://twitter.com/intent/tweet?text={{title}}&url={{url}}', ishare_googleplus: 'https://plus.google.com/share?url={{url}}&t={{title}}', ishare_pinterest: 'https://www.pinterest.com/pin/create/button/?url={{url}}&description={{description}}&media={{image}}', ishare_tumblr: 'https://www.tumblr.com/widgets/share/tool?sharesource=legacy&canonicalurl=&url={{url}}&title={{title}}' }, _names = { ishare_qq: 'qq好友', ishare_qzone: 'qq空间', ishare_tencent: '腾讯微博', ishare_weibo: '新浪微博', ishare_wechat: '微信', ishare_douban: '豆瓣', ishare_renren: '人人', ishare_youdaonote: '有道笔记', ishare_linkedin: 'linkedin', ishare_facebook: 'facebook', ishare_twitter: 'twitter', ishare_googleplus: 'google+', ishare_pinterest: 'pinterest', ishare_tumblr: 'tumblr' }, _icons = { ishare_qq: '', ishare_qzone: '', ishare_tencent: '', ishare_weibo: '', ishare_wechat: '', ishare_douban: '', ishare_renren: '', ishare_youdaonote: '', ishare_linkedin: '', ishare_facebook: '', ishare_twitter: '', ishare_googleplus: '', ishare_pinterest: '', ishare_tumblr: '' }; /** * _updateurl 更新添加分享的a标签 */ function _updateurl() { if (!this.container.haschildnodes()) { return; } var _children = this.container.childnodes, _tempurl; for (var i = 0, item; item = _children[i++];) { if (item.nodetype === 1) { _tempurl = util.parseclassname(item.classname, util.parseurl(_templates, this.settings)); if ((item.classname).indexof('ishare_wechat') > -1) { // this.wx = new wx(item, _tempurl, this.settings.wxoptions); this.wx = new wx(item, this.settings.url, this.settings.wxoptions); } else { _tempurl && (item.href = _tempurl); item.target = '_blank'; } } } } /** * _createshareelements 创建分享元素 * @param {string} url 分享接口 * @param {string} item key * @param {boolean} iswechat 是否是微信 * @return {domobject} */ function _createshareelements(url, item, iswechat) { var _e = document.createelement('a'); _e.innerhtml = _icons[item]; if (this.settings.istitle) { _e.title = _names[item]; } if (iswechat) { this.wx = new wx(_e, url, this.settings.wxoptions); _e.href = 'javascript:void(0);'; } else { _e.href = url; _e.target = '_blank'; } return _e; } /** * _autoupdate 动态创建分享 */ function _autoupdate() { var _docfrag = document.createdocumentfragment(), _tpls = util.parseurl(_templates, this.settings), _element, _me = this; util.each(_me.settings.sites, function (index, item) { if (item === 'ishare_wechat') { // _element = _createshareelements.call(_me, _tpls[item], item, true); _element = _createshareelements.call(_me, _me.settings.url, item, true); } else { _element = _createshareelements.call(_me, _tpls[item], item); } _docfrag.appendchild(_element); }); this.container.innerhtml = ''; this.container.appendchild(_docfrag); } //prototype return { constructor: ishare, init: function () { if (this.settings.initialized) { _autoupdate.call(this); } else { _updateurl.call(this); } if (this.wx) { this.bindevent(); this.wx.init(); } }, bindevent: function () { var me = this; // 只绑定一次,进行初始化 function mouseentercb() { util.event.removeevent(me.container, 'mouseover', mouseentercb); } util.event.addevent(this.container, 'mouseover', mouseentercb); } } })(); if (window.ishare_config) { return (new ishare()); } else { return ishare; } });