view.js 9.3 KB

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