jssdk设计思路
一、JSSDK是什么
jssdk一般是指提供给第三方人员使用的一段js,通过这个js实现一些平台化产品提供的服务,比如微博jssdk、微信jssdk。
二、设计jssdk的几个核心问题
- 代码如何被使用页面接入
- 如何实现跨域通信
- 如何实现优雅api的设计
- 公共资源的使用
- 代码组件化
1、代码如何被使用页面接入
这里涉及到几个小问题需要考虑
- 命名空间
- 样式冲突
- 版本维护
- appid等参数的传入
(1)命名空间
需要做到不污染环境,保护好自己,即不要对本来的页面造成命名的破坏,只是用一个命名空间,又要考虑到第三方页面的复杂性,防止跟错综复杂的命名空间冲突。
要做到这点,需要我们在命名空间命名的时候多注意下,尽量不要使用业内通用的命名方法,比如驼峰,名字尽量起的怪一些,偏一些,一般,要么使用_开头(甚至多个),要么使用项目代号这些不太被别人想到的名字。
还有一种方式是动态的命名空间,在url中带上namespace=xxx
(2)样式冲突
如果jssdk带有UI组件,那么还需要考虑css的样式冲突问题,这里不用多说,记住以下几点:
- 一些复杂的widget可以使用iframe方式引入
- 不使用id
- 使用带前缀的class命名,前面用一个class最好包裹
- 自己做reset!
- 跟js相关的class要有特殊的约定(比如_J-xxx )或者使用data-id代替
其实利用sass、less这些预编译语言很容易
(3)版本维护
版本维护的目的是保证代码最新,功能最全,而不用每次做了升级,通知所有使用的第三方开发者把自己页面的代码挨个更换。
一般有两种比较好的方式:
- 小拖大,动拖静:即第三方引入的js是一个动态的,或者没有缓存没有cdn的,然后由它带出后面的cdn
- 隔段时间动态创建script
推荐使用「小拖大,动拖静」,后面介绍组件化也要使用这个方式来按需加载代码
核心代码示例
1 2 3 4 5 6 7 8 | ( function (){ ..... var url = '最新版本cdn的地址' ; load(url); }()) |
隔段时间动态创建script代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ( function () { var s = document.createElement( 'script' ); s.type = 'text/javascript' ; var t = + new Date; t -= %864E5; s.src = '//xxx.com/sdk.js?t=' +t; var x = document.getElementsByTagName( 'script' )[0]; x.parentNode.insertBefore(s, x); })(); |
(4)appid等参数的传入
一般在引入sdkjs代码的时候需要加参数或者版本号,比如开放平台需要配置appid,所以url写法是:
sdk.js?appid=xxxx&namespace=xxx 。
jssdk需要拿到url中的这些参数,方法有以下两种比较通用的:
- 给script标签增加特殊属性,例如<script src="path/sdk.js?appid=123" id="_jssdk">
- 使用查找script标签方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | //get url args function function parserUrl(){ var scripts = document.getElementsByTagName( "script" ), len = scripts.length, url; if (len > 0) { for ( var i = 0; i < len; i++) { if (scripts[i].src.indexOf( "path/to/sdk.js" ) !== -1) { return scripts[i].src.split( "?" ).pop(); } } } } |
所以appid,namespace这些都可以解析出来
2、如何实现跨域通信
对于不在一个域名下的第三方页面引入的jssdk少不了的是跨域请求,这块移动上可以直接使用postMessage方法,将来可以使用xhr2+CORS,相兼容IE。
3、如何实现优雅api的设计
这里的api指的是开放平台提供的http接口,一般都会有一些标准的规范,比如:
- 获取用户信息://domain.com/api/getUserInfo.json
- 更新用户信息://domain.com/api/updateUserInfo.json
我们设计这个函数接口的时候,应该充分考虑到将来server接口的增加,所以应该做成通用的服务,比如我们设计个sdkjs.api方法,接受四个参数:url\data\callback\method,默认如果data是函数就后面参数自动前提。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | api: function (url, data, callback, method) { var _args = $.toArray(arguments), _callback = _args[2] || $.emptyFn; if (_args.length < 3) { throw Error( "api arguments length wrong" ); } if (!$.isString(_args[0]) || !$.isObject(_args[1]) || !$.isFunction(_callback)) { throw Error( "api arguments format error" ); } var _cbid = 0; if ($.isFunction(_callback)) { _cbid = _CallbackManager.add(_callback); } //跨域发起请求 xDomain.send( "api" , { url: _args[0], data: _args[1], method: _args[3] || "get" , _cbid: _cbid }); return back; } |
4、公共资源的使用
公共资源的使用,指的是一些跟宿主环境共享的资源,比如cookie、localstorage这些,使用的时候应该做前缀处理,尽量不污染宿主页面环境,同时保证不被轻易的删除。
5、代码组件化
代码的组织在一些带有UI的jssdk中使用较多,比如按需加载某个UI模块。
这时候就充分利用到了第一节提到的「小拖大,动拖静」的引入方式,一开始小文件我们叫seed,里面有UI组件和sdk主代码的url,seed.js加载后,先加载sdk的核心js文件,然后如果使用某个UI组件,就按需加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | var MAP = { core: [ 'sdk-core.js' ], ui: { loginDialog: [ 'path/loginDialog.css' , 'path/loginDialog.js' ] } } load(MAP.core); //使用 SDKJS.ready( function ($){ //$实际是SDKJS $.use( 'loginDialog' , function (loginDialog){ loginDialog(xxxxx); }) }); |
其中.use方法,有些类似require方法,起到按需加载的功能。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了