other.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import { nextTick, defineAsyncComponent } from 'vue';
  2. import type { App } from 'vue';
  3. import * as svg from '@element-plus/icons-vue';
  4. import router from '/@/router/index';
  5. import pinia from '/@/stores/index';
  6. import { storeToRefs } from 'pinia';
  7. import { useThemeConfig } from '/@/stores/themeConfig';
  8. import { i18n } from '/@/i18n/index';
  9. //import { Local } from '/@/utils/storage';
  10. import { verifyUrl } from '/@/utils/toolsValidate';
  11. // 引入组件
  12. const SvgIcon = defineAsyncComponent(() => import('/@/components/svgIcon/index.vue'));
  13. /**
  14. * 导出全局注册 element plus svg 图标
  15. * @param app vue 实例
  16. * @description 使用:https://element-plus.gitee.io/zh-CN/component/icon.html
  17. */
  18. export function elSvg(app: App) {
  19. const icons = svg as any;
  20. for (const i in icons) {
  21. app.component(`ele-${icons[i].name}`, icons[i]);
  22. }
  23. app.component('SvgIcon', SvgIcon);
  24. }
  25. /**
  26. * 设置浏览器标题国际化
  27. * @method const title = useTitle(); ==> title()
  28. */
  29. export function useTitle() {
  30. const stores = useThemeConfig(pinia);
  31. const { themeConfig } = storeToRefs(stores);
  32. nextTick(() => {
  33. let webTitle = '';
  34. let globalTitle: string = themeConfig.value.globalTitle;
  35. const { path, meta } = router.currentRoute.value;
  36. if (path === '/login') {
  37. webTitle = <string>meta.title;
  38. } else {
  39. webTitle = setTagsViewNameI18n(router.currentRoute.value);
  40. }
  41. document.title = `${webTitle} - ${globalTitle}` || globalTitle;
  42. });
  43. }
  44. /**
  45. * 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
  46. * @param params 路由 query、params 中的 tagsViewName
  47. * @returns 返回当前 tagsViewName 名称
  48. */
  49. export function setTagsViewNameI18n(item: any) {
  50. let tagsViewName: string = '';
  51. const { query, params, meta } = item;
  52. // 修复tagsViewName匹配到其他含下列单词的路由
  53. const pattern = /^\{("(zh-cn|en|zh-tw)":"[^,]+",?){1,3}}$/;
  54. if (query?.tagsViewName || params?.tagsViewName) {
  55. if (pattern.test(query?.tagsViewName) || pattern.test(params?.tagsViewName)) {
  56. // 国际化
  57. const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName));
  58. tagsViewName = urlTagsParams[i18n.global.locale.value];
  59. } else {
  60. // 非国际化
  61. tagsViewName = query?.tagsViewName || params?.tagsViewName;
  62. }
  63. } else {
  64. // 非自定义 tagsView 名称
  65. tagsViewName = i18n.global.t(meta.title);
  66. }
  67. return tagsViewName;
  68. }
  69. /**
  70. * 图片懒加载
  71. * @param el dom 目标元素
  72. * @param arr 列表数据
  73. * @description data-xxx 属性用于存储页面或应用程序的私有自定义数据
  74. */
  75. export const lazyImg = (el: string, arr: EmptyArrayType) => {
  76. const io = new IntersectionObserver((res) => {
  77. res.forEach((v: any) => {
  78. if (v.isIntersecting) {
  79. const { img, key } = v.target.dataset;
  80. v.target.src = img;
  81. v.target.onload = () => {
  82. io.unobserve(v.target);
  83. arr[key]['loading'] = false;
  84. };
  85. }
  86. });
  87. });
  88. nextTick(() => {
  89. document.querySelectorAll(el).forEach((img) => io.observe(img));
  90. });
  91. };
  92. /**
  93. * 全局组件大小
  94. * @returns 返回 `window.localStorage` 中读取的缓存值 `globalComponentSize`
  95. */
  96. export const globalComponentSize = (): string => {
  97. const stores = useThemeConfig(pinia);
  98. const { themeConfig } = storeToRefs(stores);
  99. return themeConfig.value.globalComponentSize;
  100. };
  101. /**
  102. * 对象深克隆
  103. * @param obj 源对象
  104. * @returns 克隆后的对象
  105. */
  106. export function deepClone(obj: EmptyObjectType) {
  107. let newObj: EmptyObjectType;
  108. try {
  109. newObj = obj.push ? [] : {};
  110. } catch (error) {
  111. newObj = {};
  112. }
  113. for (let attr in obj) {
  114. if (obj[attr] && typeof obj[attr] === 'object') {
  115. newObj[attr] = deepClone(obj[attr]);
  116. } else {
  117. newObj[attr] = obj[attr];
  118. }
  119. }
  120. return newObj;
  121. }
  122. /**
  123. * 判断是否是移动端
  124. */
  125. export function isMobile() {
  126. if (navigator.userAgent.match(/('phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone')/i)) {
  127. return true;
  128. } else {
  129. return false;
  130. }
  131. }
  132. /**
  133. * 判断数组对象中所有属性是否为空,为空则删除当前行对象
  134. * @description @感谢大黄
  135. * @param list 数组对象
  136. * @returns 删除空值后的数组对象
  137. */
  138. export function handleEmpty(list: EmptyArrayType) {
  139. const arr = [];
  140. for (const i in list) {
  141. const d = [];
  142. for (const j in list[i]) {
  143. d.push(list[i][j]);
  144. }
  145. const leng = d.filter((item) => item === '').length;
  146. if (leng !== d.length) {
  147. arr.push(list[i]);
  148. }
  149. }
  150. return arr;
  151. }
  152. /**
  153. * 打开外部链接
  154. * @param val 当前点击项菜单
  155. */
  156. export function handleOpenLink(val: RouteItem) {
  157. const { origin, pathname } = window.location;
  158. router.push(val.path);
  159. if (verifyUrl(<string>val.meta?.isLink)) window.open(val.meta?.isLink);
  160. else window.open(`${origin}${pathname}#${val.meta?.isLink}`);
  161. }
  162. /**
  163. * 统一批量导出
  164. * @method elSvg 导出全局注册 element plus svg 图标
  165. * @method useTitle 设置浏览器标题国际化
  166. * @method setTagsViewNameI18n 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
  167. * @method lazyImg 图片懒加载
  168. * @method globalComponentSize() element plus 全局组件大小
  169. * @method deepClone 对象深克隆
  170. * @method isMobile 判断是否是移动端
  171. * @method handleEmpty 判断数组对象中所有属性是否为空,为空则删除当前行对象
  172. * @method handleOpenLink 打开外部链接
  173. */
  174. const other = {
  175. elSvg: (app: App) => {
  176. elSvg(app);
  177. },
  178. useTitle: () => {
  179. useTitle();
  180. },
  181. setTagsViewNameI18n(route: RouteToFrom) {
  182. return setTagsViewNameI18n(route);
  183. },
  184. lazyImg: (el: string, arr: EmptyArrayType) => {
  185. lazyImg(el, arr);
  186. },
  187. globalComponentSize: () => {
  188. return globalComponentSize();
  189. },
  190. deepClone: (obj: EmptyObjectType) => {
  191. return deepClone(obj);
  192. },
  193. isMobile: () => {
  194. return isMobile();
  195. },
  196. handleEmpty: (list: EmptyArrayType) => {
  197. return handleEmpty(list);
  198. },
  199. handleOpenLink: (val: RouteItem) => {
  200. handleOpenLink(val);
  201. },
  202. };
  203. // 统一批量导出
  204. export default other;