前端动态接口使用说明
-
介绍
前端动态接口实现了第三方JS文件的加载机制以及通用的事件生命周期,从而降低客开后期升级成本。
-
起步
引入load.js
需要在使用的前端动态接口的Html文件中引入 <script src="/seeyon/common/cap-dynamic-front/load.js"></script>
其中路径中的 /seeyon 需要根据实际项目中的 StaticPath 来确定。如不确定实际值,需要使用相对路径来引入
建议将 load.js 最先加载,从而保证客开JS相较其它JS最先得到解析
客开JS文件新建
如项目走构建流程,可在 cap-dynamic-front 工程下的js目录下新增JS文件,见工程下示例文件 /js/eg/eg.js
如直接在产品打包后的代码中进行客开,需要在 /seeyon/common/cap-dynamic-front/js 目录下新增JS文件,同时需要保持上级目录中的 dev-app.exe 运行
-
文件动态加载
上一步创建JS文件想要实现动态加载,需要在文件首行实现 customManage.load 方法
match.url 用来指定需要加载该js的页面url
cssLoadPath 加载该js的同时,将会加载该css文件
order指定加载顺序
customManage.load({ match: { url: ['test.html'], }, cssLoadPath: ['/css/eg/eg.css'], // 加载顺序 order: 99 })
-
事件钩子
事件钩子有 before -> work -> after 的生命周期
每个生命周期流程函数中第一个参数都是 handler 对象
调用 handler.next 标志此步骤完成,将会进入下一步操作,例如 before 方法调用 next 后,将会进入 work 流程
调用 handler.resolve 标志此事件完成,后面操作将会阻断,例如 before 方法调用 resolve 后,work 流程将不会执行
调用 handler.reject 标志此事件发生错误,后面操作同样将会阻断,并进入 error 方法回调
事件钩子埋点
下面代码实现了一个名为 app-save 的事件埋点
customManage.eventEmit 第一个参数中的 name 为事件钩子的名称,beforeParams 为提供给 before 流程的参数
第二个参数为一个函数,实现的是生命周期中的 work 流程
customManage.eventEmit( { name: 'app-save', beforeParams: [{ id: 123 }] }, function (handler, data) { console.log(data); setTimeout(function(){ handler.next('saved') }, 1000) } )
事件钩子回调
下面代码实现的是 app-save 的 before 与 after 流程
customManage.eventHook( 'app-save', { before: function (handler, data) { console.log(data); setTimeout(function(){ // handler.resolve('before ok') handler.next('before ok') }, 500) }, after: function (handler, data) { console.log(data,'after ok'); // handler.reject('after error') handler.next('after ok') }, error: function (err, data) { console.log(err.type, data); } } )
事件钩子 Demo 示例
点击按钮,触发 app-save 事件, 完成 before -> work -> after 全部流程
beforeParams 参数传递给 before 流程
before 流程执行 next 后,将参数传递给 work 流程
work 流程执行 next 后,将参数传递给 after 流程
// 标准产品中埋点 document.querySelector('#demo1').addEventListener('click',function(){ customManage.eventEmit( { name: 'app-save', beforeParams: [{ id: 123 }] }, function (handler, data) { alert(data) setTimeout(function(){ handler.next('save ok') }, 1000) } ) }) // 动态加载上的JS中写 customManage.eventHook( 'app-save', { before: function (handler, data) { alert(data.id) setTimeout(function(){ handler.next('before ok') }, 500) }, after: function (handler, data) { alert(data) handler.next() } } )
点击按钮,触发 app-save2 事件, 仅完成 before 流程,后续流程将不会执行,标志事件正确结束
before 中 调用了 handler.resolve()
// 标准产品中埋点 document.querySelector('#demo2').addEventListener('click',function(){ customManage.eventEmit( { name: 'app-save2', beforeParams: [{ id: 123 }] }, function (handler, data) { alert(data) setTimeout(function(){ handler.next('save ok') }, 1000) } ) }) // 动态加载上的JS中写 customManage.eventHook( 'app-save2', { before: function (handler, data) { alert(data.id) setTimeout(function(){ handler.resolve() }, 500) } } )
点击按钮,触发 app-save3 事件, 调用了 handler.reject,后续流程将不会执行,会进入 error 回调,标志事件发生异常停止
// 标准产品中埋点 document.querySelector('#demo3').addEventListener('click',function(){ customManage.eventEmit( { name: 'app-save3', beforeParams: [{ id: 123 }] }, function (handler, data) { alert(data) setTimeout(function(){ handler.next('save ok') }, 1000) } ) }) // 动态加载上的JS中写 customManage.eventHook( 'app-save3', { before: function (handler, data) { alert(data.id) setTimeout(function(){ handler.reject('error') }, 500) }, error: function (err, data) { alert(data) console.log(err.type, data); } } )
-
-
方法钩子
当方法钩子触发,可以把引用传递的变量作为上下文,触发 methodHook 的回调
list 的 lenght 将会加1
val 的值不会改变,因为 val 为值引用传递
// 标准产品中埋点 var list = []; // 引用传递变量 var val = 0; // Number 为基本类型 document.querySelector('#demo4').addEventListener('click',function(){ customManage.methodEmit('app-set', {list:list,val:val}); alert('list length 为' + list.length); alert('val 值为'+ val); }) // 动态加载上的JS中写 customManage.methodHook('app-set', function () { this.list.push('1'); this.val++; })
-
触发判断
方法钩子或事件钩子触发前,会调用 customManage.beforeRunHook,
若该方法不存在或返回 true 则继续调用后续钩子
若该方法返回 false ,将不触发后续钩子
当开关关闭时,上面的demo中的钩子函数都不会触发
// 动态加载上的JS中写 customManage.beforeRunHook = function (hookType, hookName) { console.log(hookType, hookName) return document.querySelector('#demo5').checked }