view.js 10 KB

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