view.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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 errorText = [
  90. '<cite>错误信息:</cite> ' + (res[response.msgName] || '返回状态码异常')
  91. , debug()
  92. ].join('');
  93. view.error(errorText);
  94. }
  95. //只要 http 状态码正常,无论 response 的 code 是否正常都执行 success
  96. typeof success === 'function' && success(res);
  97. }
  98. , error: function (e, code) {
  99. var errorText = [
  100. '请求异常,请重试<br><cite>错误信息:</cite>' + code
  101. , debug()
  102. ].join('');
  103. view.error(errorText);
  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. ;
  184. if (e.status === 404) {
  185. that.render('template/tips/404');
  186. } else {
  187. that.render('template/tips/error');
  188. }
  189. that.render.isError = true;
  190. }
  191. });
  192. return that;
  193. };
  194. //解析模板
  195. Class.prototype.parse = function (html, refresh, callback) {
  196. var that = this
  197. , isScriptTpl = typeof html === 'object' //是否模板元素
  198. , elem = isScriptTpl ? html : $(html)
  199. , elemTemp = isScriptTpl ? html : elem.find('*[template]')
  200. , fn = function (options) {
  201. var tpl = laytpl(options.dataElem.html())
  202. , res = $.extend({
  203. params: router.params
  204. }, options.res);
  205. options.dataElem.after(tpl.render(res));
  206. typeof callback === 'function' && callback();
  207. try {
  208. options.done && new Function('d', options.done)(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. ;
  232. try {
  233. headers = new Function('return ' + headers + ';')();
  234. } catch (e) {
  235. hint.error('lay-headers: ' + e.message);
  236. headers = headers || {}
  237. }
  238. ;
  239. if (url) {
  240. view.req({
  241. type: dataElem.attr('lay-type') || 'get'
  242. , url: url
  243. , data: data
  244. , dataType: 'json'
  245. , headers: headers
  246. , success: function (res) {
  247. fn({
  248. dataElem: dataElem
  249. , res: res
  250. , done: layDone
  251. });
  252. }
  253. });
  254. } else {
  255. fn({
  256. dataElem: dataElem
  257. , done: layDone
  258. });
  259. }
  260. }());
  261. }
  262. return that;
  263. };
  264. //自动渲染数据模板
  265. Class.prototype.autoRender = function (id, callback) {
  266. var that = this;
  267. $(id || 'body').find('*[template]').each(function (index, item) {
  268. var othis = $(this);
  269. that.container = othis;
  270. that.parse(othis, 'refresh');
  271. });
  272. };
  273. //直接渲染字符
  274. Class.prototype.send = function (views, data) {
  275. var tpl = laytpl(views || this.container.html()).render(data || {});
  276. this.container.html(tpl);
  277. return this;
  278. };
  279. //局部刷新模板
  280. Class.prototype.refresh = function (callback) {
  281. var that = this
  282. , next = that.container.next()
  283. , templateid = next.attr('lay-templateid');
  284. if (that.id != templateid) return that;
  285. that.parse(that.container, 'refresh', function () {
  286. that.container.siblings('[lay-templateid="' + that.id + '"]:last').remove();
  287. typeof callback === 'function' && callback();
  288. });
  289. return that;
  290. };
  291. //视图请求成功后的回调
  292. Class.prototype.then = function (callback) {
  293. this.then = callback;
  294. return this;
  295. };
  296. //视图渲染完毕后的回调
  297. Class.prototype.done = function (callback) {
  298. this.done = callback;
  299. return this;
  300. };
  301. //对外接口
  302. exports('view', view);
  303. });