view.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /**
  2. @Name:layuiAdmin 视图模块
  3. @Author:贤心
  4. @Site:http://www.layui.com/admin/
  5. @License:LPPL
  6. */
  7. layui.define(['laytpl', 'layer'], function(exports){
  8. var $ = layui.jquery
  9. ,laytpl = layui.laytpl
  10. ,layer = layui.layer
  11. ,setter = layui.setter
  12. ,device = layui.device()
  13. ,hint = layui.hint()
  14. //对外接口
  15. ,view = function(id){
  16. return new Class(id);
  17. }
  18. ,SHOW = 'layui-show', LAY_BODY = 'LAY_app_body'
  19. //构造器
  20. ,Class = function(id){
  21. this.id = id;
  22. this.container = $('#'+(id || LAY_BODY));
  23. };
  24. //加载中
  25. view.loading = function(elem){
  26. elem.append(
  27. this.elemLoad = $('<i class="layui-anim layui-anim-rotate layui-anim-loop layui-icon layui-icon-loading layadmin-loading"></i>')
  28. );
  29. };
  30. //移除加载
  31. view.removeLoad = function(){
  32. this.elemLoad && this.elemLoad.remove();
  33. };
  34. //清除 token,并跳转到登入页
  35. view.exit = function(callback){
  36. //清空本地记录的 token
  37. layui.data(setter.tableName, {
  38. key: setter.request.tokenName
  39. ,remove: true
  40. });
  41. //跳转到登入页
  42. //location.hash = '/user/login';
  43. callback && callback();
  44. };
  45. //Ajax请求
  46. view.req = function(options){
  47. var that = this
  48. ,success = options.success
  49. ,error = options.error
  50. ,request = setter.request
  51. ,response = setter.response
  52. ,debug = function(){
  53. return setter.debug
  54. ? '<br><cite>URL:</cite>' + options.url
  55. : '';
  56. };
  57. options.data = options.data || {};
  58. options.headers = options.headers || {};
  59. if(request.tokenName){
  60. var sendData = typeof options.data === 'string'
  61. ? JSON.parse(options.data)
  62. : options.data;
  63. //自动给参数传入默认 token
  64. options.data[request.tokenName] = request.tokenName in sendData
  65. ? options.data[request.tokenName]
  66. : (layui.data(setter.tableName)[request.tokenName] || '');
  67. //自动给 Request Headers 传入 token
  68. options.headers[request.tokenName] = request.tokenName in options.headers
  69. ? options.headers[request.tokenName]
  70. : (layui.data(setter.tableName)[request.tokenName] || '');
  71. }
  72. delete options.success;
  73. delete options.error;
  74. return $.ajax($.extend({
  75. type: 'get'
  76. ,dataType: 'json'
  77. ,success: function(res){
  78. var statusCode = response.statusCode;
  79. //只有 response 的 code 一切正常才执行 done
  80. if(res[response.statusName] == statusCode.ok) {
  81. typeof options.done === 'function' && options.done(res);
  82. }
  83. //登录状态失效,清除本地 access_token,并强制跳转到登入页
  84. else if(res[response.statusName] == statusCode.logout){
  85. view.exit();
  86. }
  87. //其它异常
  88. else {
  89. var error = [
  90. '<cite>Error:</cite> ' + (res[response.msgName] || '返回状态码异常')
  91. ,debug()
  92. ].join('');
  93. view.error(error);
  94. }
  95. //只要 http 状态码正常,无论 response 的 code 是否正常都执行 success
  96. typeof success === 'function' && success(res);
  97. }
  98. ,error: function(e, code){
  99. var error = [
  100. '请求异常,请重试<br><cite>错误信息:</cite>'+ code
  101. ,debug()
  102. ].join('');
  103. view.error(error);
  104. typeof error === 'function' && error(res);
  105. }
  106. }, options));
  107. };
  108. //弹窗
  109. view.popup = function(options){
  110. var success = options.success
  111. ,skin = options.skin;
  112. delete options.success;
  113. delete options.skin;
  114. return layer.open($.extend({
  115. type: 1
  116. ,title: '提示'
  117. ,content: ''
  118. ,id: 'LAY-system-view-popup'
  119. ,skin: 'layui-layer-admin' + (skin ? ' ' + skin : '')
  120. ,shadeClose: true
  121. ,closeBtn: false
  122. ,success: function(layero, index){
  123. var elemClose = $('<i class="layui-icon" close>&#x1006;</i>');
  124. layero.append(elemClose);
  125. elemClose.on('click', function(){
  126. layer.close(index);
  127. });
  128. typeof success === 'function' && success.apply(this, arguments);
  129. }
  130. }, options))
  131. };
  132. //异常提示
  133. view.error = function(content, options){
  134. return view.popup($.extend({
  135. content: content
  136. ,maxWidth: 300
  137. //,shade: 0.01
  138. ,offset: 't'
  139. ,anim: 6
  140. ,id: 'LAY_adminError'
  141. }, options))
  142. };
  143. //请求模板文件渲染
  144. Class.prototype.render = function(views, params){
  145. var that = this, router = layui.router();
  146. views = setter.views + views + setter.engine;
  147. $('#'+ LAY_BODY).children('.layadmin-loading').remove();
  148. view.loading(that.container); //loading
  149. //请求模板
  150. $.ajax({
  151. url: views
  152. ,type: 'get'
  153. ,dataType: 'html'
  154. ,data: {
  155. v: layui.cache.version
  156. }
  157. ,success: function(html){
  158. html = '<div>' + html + '</div>';
  159. var elemTitle = $(html).find('title')
  160. ,title = elemTitle.text() || (html.match(/\<title\>([\s\S]*)\<\/title>/)||[])[1];
  161. var res = {
  162. title: title
  163. ,body: html
  164. };
  165. elemTitle.remove();
  166. that.params = params || {}; //获取参数
  167. if(that.then){
  168. that.then(res);
  169. delete that.then;
  170. }
  171. that.parse(html);
  172. view.removeLoad();
  173. if(that.done){
  174. that.done(res);
  175. delete that.done;
  176. }
  177. }
  178. ,error: function(e){
  179. view.removeLoad();
  180. if(that.render.isError){
  181. return view.error('请求视图文件异常,状态:'+ e.status);
  182. };
  183. if(e.status === 404){
  184. that.render('template/tips/404');
  185. } else {
  186. that.render('template/tips/error');
  187. }
  188. that.render.isError = true;
  189. }
  190. });
  191. return that;
  192. };
  193. //解析模板
  194. Class.prototype.parse = function(html, refresh, callback){
  195. var that = this
  196. ,isScriptTpl = typeof html === 'object' //是否模板元素
  197. ,elem = isScriptTpl ? html : $(html)
  198. ,elemTemp = isScriptTpl ? html : elem.find('*[template]')
  199. ,fn = function(options){
  200. var tpl = laytpl(options.dataElem.html())
  201. ,res = $.extend({
  202. params: router.params
  203. }, options.res);
  204. options.dataElem.after(tpl.render(res));
  205. typeof callback === 'function' && callback();
  206. try {
  207. options.done && new Function('d', options.done)(res);
  208. } catch(e){
  209. console.error(options.dataElem[0], '\n存在错误回调脚本\n\n', e)
  210. }
  211. }
  212. ,router = layui.router();
  213. elem.find('title').remove();
  214. that.container[refresh ? 'after' : 'html'](elem.children());
  215. router.params = that.params || {};
  216. //遍历模板区块
  217. for(var i = elemTemp.length; i > 0; i--){
  218. (function(){
  219. var dataElem = elemTemp.eq(i - 1)
  220. ,layDone = dataElem.attr('lay-done') || dataElem.attr('lay-then') //获取回调
  221. ,url = laytpl(dataElem.attr('lay-url')|| '').render(router) //接口 url
  222. ,data = laytpl(dataElem.attr('lay-data')|| '').render(router) //接口参数
  223. ,headers = laytpl(dataElem.attr('lay-headers')|| '').render(router); //接口请求的头信息
  224. try {
  225. data = new Function('return '+ data + ';')();
  226. } catch(e) {
  227. hint.error('lay-data: ' + e.message);
  228. data = {};
  229. };
  230. try {
  231. headers = new Function('return '+ headers + ';')();
  232. } catch(e) {
  233. hint.error('lay-headers: ' + e.message);
  234. headers = headers || {}
  235. };
  236. if(url){
  237. view.req({
  238. type: dataElem.attr('lay-type') || 'get'
  239. ,url: url
  240. ,data: data
  241. ,dataType: 'json'
  242. ,headers: headers
  243. ,success: function(res){
  244. fn({
  245. dataElem: dataElem
  246. ,res: res
  247. ,done: layDone
  248. });
  249. }
  250. });
  251. } else {
  252. fn({
  253. dataElem: dataElem
  254. ,done: layDone
  255. });
  256. }
  257. }());
  258. }
  259. return that;
  260. };
  261. //自动渲染数据模板
  262. Class.prototype.autoRender = function(id, callback){
  263. var that = this;
  264. $(id || 'body').find('*[template]').each(function(index, item){
  265. var othis = $(this);
  266. that.container = othis;
  267. that.parse(othis, 'refresh');
  268. });
  269. };
  270. //直接渲染字符
  271. Class.prototype.send = function(views, data){
  272. var tpl = laytpl(views || this.container.html()).render(data || {});
  273. this.container.html(tpl);
  274. return this;
  275. };
  276. //局部刷新模板
  277. Class.prototype.refresh = function(callback){
  278. var that = this
  279. ,next = that.container.next()
  280. ,templateid = next.attr('lay-templateid');
  281. if(that.id != templateid) return that;
  282. that.parse(that.container, 'refresh', function(){
  283. that.container.siblings('[lay-templateid="'+ that.id +'"]:last').remove();
  284. typeof callback === 'function' && callback();
  285. });
  286. return that;
  287. };
  288. //视图请求成功后的回调
  289. Class.prototype.then = function(callback){
  290. this.then = callback;
  291. return this;
  292. };
  293. //视图渲染完毕后的回调
  294. Class.prototype.done = function(callback){
  295. this.done = callback;
  296. return this;
  297. };
  298. //对外接口
  299. exports('view', view);
  300. });