共计 9319 个字符,预计需要花费 24 分钟才能阅读完成。
改造起点
github L6zt
项目前端与后端紧耦合, 分享信息 放在 jsp 里, 例如:
<script>
window.$shareInformation = {
title: ‘….’,
desc: ‘…..’,
link: ‘…..’,
}
</script>
前端还要获取全局变量里的值, 初始化分享 2. 分享功能没有进行统一的合并,所以每个页面都需要重写分享逻辑,很 low 低效的很,而且不利于维护。3. 每次都需要 引入 钉钉 和 微信 分享的 sdk js 感觉浪费流量,而且 影响页面加载速度,这个两个 js 都需要同时引入。
技术细节
对以上问题解决方案,我采用:
端对端懒加载 不同平台的 sdk,分享逻辑 统一由后端控制 即 页面里 只需要引入一个 js 脚本。
总体引用方法
// data-ajax 放置获取分享信息 ajax 的入参
//data-exclud 排除 不需要 那种分享
<script src=”/js/share.js” data-ajax=”{‘a’: ‘1’, ‘b’: ‘2’}” data-exclud=”[‘wx’, ‘dd’]” data-slector=”share”></script>
。。。。。。部分代码公共函数
var noop = function() {};
var hasOwnP = function(obj, prop) {
return Object.hasOwnProperty.call(obj, prop);
};
var toString = function(obj) {
return Object.prototype.toString.call(obj);
};
var isHardVar = function(obj) {
var result = toString(obj);
return result === ‘[object Object]’ || result === ‘[object Array]’;
}
var merge = function() {
var lg = arguments.length;
var result = {};
if (lg < 2) {
return arguments[0]
};
for (var i = 0; i < lg; i++) {
for (var key in arguments[i]) {
console.log(hasOwnP(arguments[i], key), key);
if (hasOwnP(arguments[i], key)) {
var value = arguments[i][key];
result[key] = value;
}
}
}
return result;
};
对异步处理 自己模拟的 promise 实现
var JcPromise = (function() {
function JcPromise(fn) {
fn = fn || noop;
var statusList = [‘start’, ‘pending’, ‘succeed’, ‘err’];
var cbStatus = [0, 1];
var status = statusList[0];
var data = null;
var err = null;
var that = this;
var successFn = [];
var errFn = [];
function resolve(d) {
data = d;
that._changeStatus(2);
};
function reject(e) {
err = e;
that._changeStatus(3);
};
this.getData = function() {
return data;
};
this.getErr = function() {
return err
};
this.getStatus = function() {
return status
};
this._changeStatus = function(idx) {
switch (status) {
case statusList[2]:
case statusList[3]:
{
return false
}
};
status = statusList[idx];
if (status === statusList[3]) {
setTimeout(function() {
that._triggerCatch();
}, 0)
}
if (status === statusList[2]) {
setTimeout(function() {
that._triggerThen();
}, 0)
}
};
this._pushThenCb = function(cb) {
successFn.push({
status: cbStatus[0],
cb: cb
});
if (status === statusList[2]) {
this._triggerThen();
}
};
this._pushCatchCb = function(cb) {
errFn.push({
status: cbStatus[0],
cb: cb
});
if (status === statusList[3]) {
this._triggerCatch();
}
};
this._triggerThen = function() {
successFn.map(function(item) {
if (item.status === cbStatus[0]) {
item.cb(data);
item.status = cbStatus[1];
}
})
};
this._triggerCatch = function() {
errFn.map(function(item) {
if (item.status === cbStatus[0]) {
item.cb(err);
item.status = cbStatus[1];
}
})
};
this._changeStatus(1);
this.uuid = uuid++;
try {
fn(resolve, reject);
} catch (e) {
reject(e)
}
return this
};
JcPromise.fn = JcPromise.prototype;
// 返回一个 promise
JcPromise.fn.then = function(cb) {
var promiseR = null;
var promiseJ = null;
var result = null;
var that = this;
var fn = function() {
setTimeout(function() {
try {
var data = that.getData();
result = cb(data);
if (typeof result === ‘object’ && result !== null && result.constructor === JcPromise) {
result.then(function(data) {
promiseR(data)
}).catch(function(e) {
promiseJ(e)
})
} else {
promiseR(result)
}
} catch (e) {
promiseJ(e)
}
}, 0);
};
this._pushThenCb(fn);
// 触发 promise
return new JcPromise(function(r, j) {
promiseR = r;
promiseJ = j;
});
};
// 返回一个 promise
JcPromise.fn.catch = function(cb) {
var promiseR = null;
var promiseJ = null;
var result = null;
var that = this;
var fn = function() {
setTimeout(function() {
try {
var data = that.getErr();
result = cb(data);
if (typeof result === ‘object’ && result !== null && result.constructor === JcPromise) {
result.then(function(data) {
promiseR(data)
}).catch(function(e) {
promiseJ(e)
})
} else {
promiseR(result)
}
} catch (e) {
promiseJ(e)
}
}, 0)
};
this._pushCatchCb(fn);
// 触发 promise
return new JcPromise(function(r, j) {
promiseR = r;
promiseJ = j;
});
};
return JcPromise
})();
懒加载加载 js 方法
function loadScript(src) {
return new JcPromise(function(r, j) {
var el = document.createElement(‘script’);
el.onload = function() {
r(el);
};
el.onerror = function() {
j();
};
el.src = src;
document.body.appendChild(el);
});
};
判断 是钉???? 还是微信
function checkIsWx() {
var userAgent = global.navigator.userAgent;
var checkWx = /MicroMessenger/i;
var splitWxVersion = /MicroMessenger\/([\d\.]+)/i;
var version = 0;
var flag = false;
if (checkWx.test(userAgent)) {
flag = true;
version = splitWxVersion.exec(userAgent)[1];
version = parseFloat(version.replace(‘.’, ”));
}
return {
type: ‘wx’,
flag: flag,
version: version
}
};
// 检查是不是钉钉
function checkIsDd() {
var userAgent = global.navigator.userAgent;
var checkDd = /DingTalk/i;
var splitDdVersion = /DingTalk\/([a-zA-Z0-9.-]+)/;
var version = 0;
var flag = false;
if (checkDd.test(userAgent)) {
flag = true;
version = splitDdVersion.exec(userAgent)[1];
}
return {
type: ‘dd’,
flag: flag,
version: version
}
};
// 自己照着 mdn 和其他文档 写的 ajax
var jcAjax = (function() {
/*
@data
@type
@url
@setHeader
@createXhr
*/
function jcAjax(options) {
var defaultHeaders = {
‘X-Requested-With’: ‘XMLHttpRequest’
};
var type = options.type,
headers = options.headers,
data = options.data,
cb = options.cb,
url = options.url,
data = options.data;
this.defaultHeaders = defaultHeaders;
this.type = (type || ‘get’).toUpperCase();
this.headers = options.headers || {};
this.cb = cb || noop;
this.url = url;
this.data = data || {};
this.init();
};
jcAjax.fn = jcAjax.prototype;
jcAjax.fn.setRequestHeader = function() {
var headers = this.headers;
var defaultHeaders = this.defaultHeaders;
var xhr = this.xhr;
var type = this.type;
this.headers = headers = merge(defaultHeaders, headers);
type === ‘POST’ && !headers[‘Content-Type’] && (headers[‘Content-Type’] = ‘application/x-www-form-urlencoded’);
if (headers) {
for (var key in headers) {
if (hasOwnP(headers, key)) {
xhr.setRequestHeader(key, headers[key]);
}
}
}
};
jcAjax.fn.createXhr = function() {
this.xhr = new XMLHttpRequest();
};
jcAjax.fn.listenAjax = function() {
var xhr = this.xhr;
var cb = this.cb;
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
var data = JSON.parse(xhr.responseText);
cb(data)
}
};
};
jcAjax.fn.openHttp = function(type, url) {
var xhr = this.xhr;
xhr.open(type, url);
};
jcAjax.fn.sendData = function(data) {
var xhr = this.xhr;
var type = this.type;
data = data || null;
type === ‘GET’ && (data === null)
xhr.send(data);
};
jcAjax.fn.transSendData = function() {
var result = null;
var headers = this.headers;
var contentType = headers[‘Content-Type’];
var data = this.data;
switch (contentType) {
case ‘multipart/form-data’:
{
result = new FormData();
for (var key in data) {
var value = data[key];
if (hasOwnP(data, key)) {
result.append(key, value)
}
}
return result;
}
case ‘application/json’:
{
result = data;
return result
}
default:
{
result = ”;
for (var key in data) {
var value = data[key];
if (hasOwnP(data, key)) {
isHardVar(value) && (value = JSON.stringify(value))
result = result + key + ‘=’ + value + ‘&’
}
}
result = result.replace(/&$/, ”)
return result
}
}
};
jcAjax.fn.get = function() {
var data = this.data;
var url = this.url;
var mdUrl = ”;
for (var key in data) {
var value = data[key];
if (hasOwnP(data, key)) {
mdUrl = mdUrl + encodeURIComponent(key) + ‘=’ + encodeURIComponent(value) + ‘&’
}
}
mdUrl.replace(/&$/, ”);
this.createXhr();
this.openHttp(‘GET’, mdUrl);
this.setRequestHeader();
this.listenAjax();
this.sendData();
};
jcAjax.fn.post = function() {
var sendData = null;
var url = this.url;
console.log(url);
this.createXhr();
this.openHttp(‘POST’, url);
this.setRequestHeader();
this.listenAjax();
sendData = this.transSendData();
this.sendData(sendData);
};
jcAjax.fn.init = function() {
var type = this.type.toLowerCase();
this[type]();
}
return function(options) {
return new jcAjax(options);
}
})()
微信分享 钉???? 分享具体 api
// 微信分享 由版本问题兼容问题
function wxShare(baseConfig, shareData, wxJsVersion) {
function findWxSupportApi(wxJsVersion) {
var jsApiList = null;
var bindEvent = null;
var api = null;
switch (wxJsVersion) {
case 1.3:
{
api = ‘onMenuShareTimeline|onMenuShareAppMessage|onMenuShareQQ|onMenuShareWeibo|onMenuShareQZone’;
jsApiList = api.split(‘|’);
bindEvent = api.split(‘|’);
break;
}
case 1.4:
{
api = ‘updateAppMessageShareData|updateTimelineShareData|onMenuShareWeibo’;
jsApiList = api.split(‘|’);
bindEvent = api.split(‘|’);
break;
}
};
return {
jsApiList: jsApiList,
bindEvent: bindEvent
}
};
var wxSupport = findWxSupportApi(wxJsVersion);
var jsApiList = wxSupport.jsApiList;
var bindEvent = wxSupport.bindEvent;
var title = shareData.title;
var desc = shareData.desc;
var link = shareData.link;
var imgUrl = shareData.imgUrl;
wx.config({
appId: baseConfig.appId,
timestamp: baseConfig.timestamp,
nonceStr: baseConfig.nonceStr,
signature: baseConfig.signature,
jsApiList: jsApiList
});
wx.ready(function() {
bindEvent.forEach(function(key) {
console.log(key);
wx[key] && wx[key]({
title,
desc,
link,
imgUrl,
success() {
var fnKey = key + ‘TriggerSuccess’;
var cb = wxShareTriggerCb[fnKey];
cb && cb();
},
error() {
var fnKey = key + ‘TriggerError’;
var cb = wxShareTriggerCb[fnKey];
cb && cb();
}
})
})
})
};
function ddShare(shareMsgData) {
dd.ready(function() {
var title = shareMsgData.title;
var desc = shareMsgData.desc;
var link = shareMsgData.link;
var imgUrl = shareMsgData.imgUrl;
dd.biz.navigation.setRight({
show: true,
control: true,
onSuccess: function(result) {
dd.biz.util.share({
url: link,
title: title,
content: desc,
image: imgUrl
});
}
})
});
};
初始化分享
function initShare() {
try {
ajaxData = eval(‘(‘ + getAttr(scriptElem, ‘data-ajax’) + ‘)’);
excludeUa = eval(‘(‘ + getAttr(scriptElem, ‘data-exclude’) + ‘)’) || [];
} catch (e) {
console.log(e)
}
if (isWx.flag && excludeUa.indexOf(‘wx’) === -1) {
var wxVersion = isWx.version;
var wxUrl = null;
var wxJsVersion = 0;
if (wxVersion >= 672) {
wxUrl = ‘//res.wx.qq.com/open/js/jweixin-1.4.0.js’;
wxJsVersion = 1.4;
} else {
wxUrl = ‘//res.wx.qq.com/open/js/jweixin-1.3.0.js’;
wxJsVersion = 1.3;
}
loadScript(wxUrl).then(function(data) {
return loadScript(getWxShareSignatureApi)
}).then(function(baseConfig) {
getShareUserMsg(ajaxData).then(function(data) {
var shareFrom = data.shareH5Form;
var shareData = {
title: shareFrom.title,
link: shareFrom.link,
imgUrl: shareFrom.msgImg,
desc: shareFrom.desc
};
wxShare(global.weixinConfigInfo, shareData, wxJsVersion);
hadGetShareMsgHook(data);
})
})
}
if (isDd.flag && excludeUa.indexOf(‘dd’) === -1) {
loadScript(ddUrl).then(function(data) {
getShareUserMsg(ajaxData).then(function(data) {
var shareFrom = data.shareH5Form;
var shareData = {
title: shareFrom.title,
link: shareFrom.link,
imgUrl: shareFrom.msgImg,
desc: shareFrom.desc
};
ddShare(shareData)
hadGetShareMsgHook(data)
})
})
}
}