other.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  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. if (query?.tagsViewName || params?.tagsViewName) {
  53. if (/\/zh-cn|en|zh-tw\//.test(query?.tagsViewName) || /\/zh-cn|en|zh-tw\//.test(params?.tagsViewName)) {
  54. // 国际化
  55. const urlTagsParams = (query?.tagsViewName && JSON.parse(query?.tagsViewName)) || (params?.tagsViewName && JSON.parse(params?.tagsViewName));
  56. tagsViewName = urlTagsParams[i18n.global.locale.value];
  57. } else {
  58. // 非国际化
  59. tagsViewName = query?.tagsViewName || params?.tagsViewName;
  60. }
  61. } else {
  62. // 非自定义 tagsView 名称
  63. tagsViewName = i18n.global.t(meta.title);
  64. }
  65. return tagsViewName;
  66. }
  67. /**
  68. * 图片懒加载
  69. * @param el dom 目标元素
  70. * @param arr 列表数据
  71. * @description data-xxx 属性用于存储页面或应用程序的私有自定义数据
  72. */
  73. export const lazyImg = (el: string, arr: EmptyArrayType) => {
  74. const io = new IntersectionObserver((res) => {
  75. res.forEach((v: any) => {
  76. if (v.isIntersecting) {
  77. const { img, key } = v.target.dataset;
  78. v.target.src = img;
  79. v.target.onload = () => {
  80. io.unobserve(v.target);
  81. arr[key]['loading'] = false;
  82. };
  83. }
  84. });
  85. });
  86. nextTick(() => {
  87. document.querySelectorAll(el).forEach((img) => io.observe(img));
  88. });
  89. };
  90. /**
  91. * 全局组件大小
  92. * @returns 返回 `window.localStorage` 中读取的缓存值 `globalComponentSize`
  93. */
  94. export const globalComponentSize = (): string => {
  95. const stores = useThemeConfig(pinia);
  96. const { themeConfig } = storeToRefs(stores);
  97. return Local.get('themeConfig')?.globalComponentSize || themeConfig.value?.globalComponentSize;
  98. };
  99. /**
  100. * 对象深克隆
  101. * @param obj 源对象
  102. * @returns 克隆后的对象
  103. */
  104. export function deepClone(obj: EmptyObjectType) {
  105. let newObj: EmptyObjectType;
  106. try {
  107. newObj = obj.push ? [] : {};
  108. } catch (error) {
  109. newObj = {};
  110. }
  111. for (let attr in obj) {
  112. if (obj[attr] && typeof obj[attr] === 'object') {
  113. newObj[attr] = deepClone(obj[attr]);
  114. } else {
  115. newObj[attr] = obj[attr];
  116. }
  117. }
  118. return newObj;
  119. }
  120. /**
  121. * 判断是否是移动端
  122. */
  123. export function isMobile() {
  124. if (
  125. navigator.userAgent.match(
  126. /('phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone')/i
  127. )
  128. ) {
  129. return true;
  130. } else {
  131. return false;
  132. }
  133. }
  134. /**
  135. * 判断数组对象中所有属性是否为空,为空则删除当前行对象
  136. * @description @感谢大黄
  137. * @param list 数组对象
  138. * @returns 删除空值后的数组对象
  139. */
  140. export function handleEmpty(list: EmptyArrayType) {
  141. const arr = [];
  142. for (const i in list) {
  143. const d = [];
  144. for (const j in list[i]) {
  145. d.push(list[i][j]);
  146. }
  147. const leng = d.filter((item) => item === '').length;
  148. if (leng !== d.length) {
  149. arr.push(list[i]);
  150. }
  151. }
  152. return arr;
  153. }
  154. /**
  155. * 打开外部链接
  156. * @param val 当前点击项菜单
  157. */
  158. export function handleOpenLink(val: RouteItem) {
  159. const { origin, pathname } = window.location;
  160. router.push(val.path);
  161. if (verifyUrl(<string>val.meta?.isLink)) window.open(val.meta?.isLink);
  162. else window.open(`${origin}${pathname}#${val.meta?.isLink}`);
  163. }
  164. /**
  165. * 统一批量导出
  166. * @method elSvg 导出全局注册 element plus svg 图标
  167. * @method useTitle 设置浏览器标题国际化
  168. * @method setTagsViewNameI18n 设置 自定义 tagsView 名称、 自定义 tagsView 名称国际化
  169. * @method lazyImg 图片懒加载
  170. * @method globalComponentSize() element plus 全局组件大小
  171. * @method deepClone 对象深克隆
  172. * @method isMobile 判断是否是移动端
  173. * @method handleEmpty 判断数组对象中所有属性是否为空,为空则删除当前行对象
  174. * @method handleOpenLink 打开外部链接
  175. */
  176. const other = {
  177. elSvg: (app: App) => {
  178. elSvg(app);
  179. },
  180. useTitle: () => {
  181. useTitle();
  182. },
  183. setTagsViewNameI18n(route: RouteToFrom) {
  184. return setTagsViewNameI18n(route);
  185. },
  186. lazyImg: (el: string, arr: EmptyArrayType) => {
  187. lazyImg(el, arr);
  188. },
  189. globalComponentSize: () => {
  190. return globalComponentSize();
  191. },
  192. deepClone: (obj: EmptyObjectType) => {
  193. return deepClone(obj);
  194. },
  195. isMobile: () => {
  196. return isMobile();
  197. },
  198. handleEmpty: (list: EmptyArrayType) => {
  199. return handleEmpty(list);
  200. },
  201. handleOpenLink: (val: RouteItem) => {
  202. handleOpenLink(val);
  203. },
  204. };
  205. // 统一批量导出
  206. export default other;