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