PageSourceSearch

https://heiliao.com/static/v4/__base/js/menu.js?v=20260924ndtermin…0260910ndentrycss-20260811sharelinkrealtime

js heiliao.com collected 2026-09-25 19:51:51 UTC 9,801 bytes, 217 lines download raw bytes

1/**
2 * 全局菜单
3 */
4(function (doc, win) {
5    class MenuLoader {
6
7        // 初始构建
8        constructor() {
9            this.popupName = `popup-menu`;
10            this.popupNameRight = `popup-menu-right`
11            this.builder();
12        }
13
14        // 构建菜单
15        builder() {
16            const _this = this;
17            return new Promise((resolve, reject) => {
18                try {
19                    const { createApp, ref, h, resolveComponent } = Vue;
20
21
22                    // 如不存在
23                    if ($("body").find(`#${_this.popupName}`).length === 0) {
24                        return false;
25                    }
26
27                    // 建根元素
28                    $(`#${_this.popupName}`).show();
29
30                    // 构建弹窗
31                    const app = createApp({
32                        // 变量定义
33                        data() {
34                            return {
35                                // 是否登录
36                                hasLogin: false,
37                            };
38                        },
39                        methods: {
40                            onMenuClose() {
41                                $(`#${_this.popupName}`).removeClass('show').addClass('hide');
42                                $("body").removeClass("navbar fixbody");
43                            },
44
45                            onTagSelected(el, k, j) {
46                                $(`#navbar .tag-text a.selected`).removeClass('selected').end().find(el).addClass('selected');
47                            },
48
49                            onLogin() {
50                                this.onMenuClose();
51                                win.$WinOpen({
52                                    event: 'open',
53                                    datas: { key: 'LOGIN',    url: `/登陆` }
54                                });
55                            },
56
57                            onRegister() {
58                                this.onMenuClose();
59                                win.$WinOpen({
60                                    event: 'open',
61                                    datas: { key: 'REGISTER',    url: `/注册` }
62                                });
63                            },
64
65                            onSign() {
66                                top.location.href = `${win.base_url}/pages/签到.html`;
67                            },
68
69                            onUserCenter() {
70                                top.location.href = `${win.base_url}/pages/个人中心/会员中心.html`;
71                            }
72                        },
73
74                        mounted() {
75
76                        }
77
78                    }).mount(`#${_this.popupName}`)
79
80                    // 右侧用户面板(与左侧互斥)
81                    if ($("body").find(`#${_this.popupNameRight}`).length) {
82                        $(`#${_this.popupNameRight}`).show();
83                        _this.rightPanelApp = createApp({
84                            data() {
85                                // 右侧面板的登录态:复用全局 token
86                                return {
87                                    isLogin: $LocalStorage.get(win.__TOKEN__ || '__token__') ? true : false,
88                                    userInfo: {
89                                        nickname: '用户',
90                                        shareCount: 0
91                                    },
92                                    unsubscribeUserInfo: null
93                                };
94                            },
95                            methods: {
96                                onMenuClose() {
97                                    $(`#${_this.popupNameRight}`).removeClass('show').addClass('hide');
98                                    $("body").removeClass("navbar fixbody");
99                                },
100
101                                fillUserInfo(userInfo = {}) {
102                                    const normalizedUserInfo = win.$UserManager?.normalize
103                                        ? win.$UserManager.normalize(userInfo)
104                                        : userInfo;
105                                    const coins = normalizedUserInfo?.coins ?? 0;
106
107                                    this.userInfo = normalizedUserInfo;
108                                    this.syncHeaderAvatar(normalizedUserInfo?.thumb || '');
109
110                                    $('#popup-menu-right .coins-item .left > .count').text(`当前余额:${coins}`);
111                                },
112
113                                syncHeaderAvatar(thumb) {
114                                    const accountButton = doc.querySelector('.nav-mobile-header .account-btn');
115                                    if (!accountButton) return;
116
117                                    const currentAvatar = accountButton.querySelector('.account-avatar');
118                                    if (!thumb) {
119                                        currentAvatar?.remove();
120                                        return;
121                                    }
122                                    if (currentAvatar?.getAttribute('z-image-loader-url') === thumb) return;
123
124                                    const avatar = doc.createElement('img');
125                                    avatar.className = 'account-avatar';
126                                    avatar.alt = '用户头像';
127                                    avatar.setAttribute('z-image-loader-url', thumb);
128                                    avatar.addEventListener('load', () => avatar.classList.add('is-loaded'), { once: true });
129                                    avatar.addEventListener('error', () => avatar.remove(), { once: true });
130
131                                    if (currentAvatar) {
132                                        currentAvatar.replaceWith(avatar);
133                                    } else {
134                                        accountButton.appendChild(avatar);
135                                    }
136                                },
137
138                                refreshUserInfo() {
139                                    if (!this.isLogin || !win.$UserManager?.refresh) {
140                                        return Promise.resolve(null);
141                                    }
142
143                                    return win.$UserManager.refresh()
144                                        .catch((error) => {
145                                            console.log('刷新用户信息失败:', error);
146                                            return null;
147                                        });
148                                },
149                            },
150                            mounted() {
151                                const initUserInfo = () => {
152                                    this.isLogin = win.$isLogin?.() || false;
153                                    if (!this.isLogin || !win.$UserManager) {
154                                        this.syncHeaderAvatar('');
155                                        return;
156                                    }
157
158                                    this.unsubscribeUserInfo = win.$UserManager.subscribe(userInfo => {
159                                        this.fillUserInfo(userInfo || {});
160                                    });
161                                    this.refreshUserInfo();
162                                };
163
164                                if (doc.readyState === 'complete') {
165                                    initUserInfo();
166                                } else {
167                                    doc.addEventListener('DOMContentLoaded', initUserInfo, { once: true });
168                                }
169                            },
170                            beforeUnmount() {
171                                this.unsubscribeUserInfo?.();
172                            },
173                        }).mount(`#${_this.popupNameRight}`);
174                    }
175
176                    resolve(app);
177                } catch (error) {
178                    reject(error);
179                }
180            });
181        }
182
183        // 打开左侧菜单
184        open() {
185            $(`#${this.popupNameRight}`).removeClass('show').addClass('hide');
186            $(`#${this.popupName}`).removeClass('hide').addClass('show');
187        }
188
189        // 打开右侧用户面板
190        openRight() {
191            $(`#${this.popupName}`).removeClass('show').addClass('hide');
192            $(`#${this.popupNameRight}`).removeClass('hide').addClass('show');
193            if (this.rightPanelApp) {
194                this.rightPanelApp.isLogin = win.$isLogin?.();
195                if (this.rightPanelApp.isLogin && typeof this.rightPanelApp.refreshUserInfo === 'function') {
196                    // 不 reload 的登录(红包雨回流)后首开面板:mou
196nted 时未登录没订阅,这里补上
197                    if (!this.rightPanelApp.unsubscribeUserInfo && win.$UserManager?.subscribe) {
198                        this.rightPanelApp.unsubscribeUserInfo = win.$UserManager.subscribe(userInfo => {
199                            this.rightPanelApp.fillUserInfo(userInfo || {});
200                        });
201                    }
202                    this.rightPanelApp.refreshUserInfo();
203                }
204            } else if (win.$isLogin?.() && win.$UserManager?.refreshCoins) {
205                win.$UserManager.refreshCoins().catch((error) => {
206                    console.log('刷新金币余额失败:', error);
207                });
208            }
209        }
210    }
211
212    // 初始化
213    const menuLoader = new MenuLoader();
214    win.onPupopMenu = () => menuLoader.open();
215    win.onPupopMenuRight = () => menuLoader.openRight();
216
217})(document, window);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.