PageSourceSearch

https://www.aomei.jp/resources/lib/base-utils.js

js aomei.jp collected 2026-09-30 14:17:42 UTC 25,149 bytes, 646 lines download raw bytes

1// 工具
2$.extend({
3    // 定义全局语言设置
4    langs: [
5        "fr",
6        "jp",
7        "de",
8        "it",
9        "pt",
10        "es",
11        "tw",
12        "zh",
13        "en",
14        "ar",
15        "pl",
16        "nl",
17        "ru"
18    ],
19    /**
20     * 获取当前语言
21     * @return {string} 返回当前语言简称
22     */
23    getCurrentLang: function () {
24        var b = window.location.pathname.substring(1).split("/")[0];
25        var c = this.langs.indexOf(b) > -1 ? b : "en";
26        if (/www.aomei.de|92.168.0.27:8023|wwwtest.aomei.de/.test(window.location.host)) {
27            c = "de";
28        } else if (/www.aomei.fr|92.168.0.27:8024|wwwtest.aomei.fr/.test(window.location.host)) {
29            c = "fr";
30        } else if (/www.aomei.jp|partition.aomei.jp|192.168.0.27:8025|wwwtest.aomei.jp/.test(window.location.host)) {
31            c = "jp"
32        } else if (/twtest.aomeitech.com|tw.aomeitech.com|192.168.0.27:8026/.test(window.location.host)) {
33            c = 'tw'
34        }else if(/es.aomeitech.com|192.168.0.27:8028/.test(window.location.host)){
35            c= 'es'
36        }else if(/it.aomeitech.com|192.168.0.27:8027/.test(window.location.host)){
37            c= 'it'
38        }
39        // a.currentLang = c;
40        return c;
41    },
42    /**
43     * @return {string} 返回当前语言前缀例如en=/,de=/de,jp=/jp
44     */
45    getPrefixer: function () {
46        let prefixer = '';
47        if (/www.aomei.de|www.aomei.fr|www.aomei.jp|partition.aomei.jp/.test(window.location.host) || this.getCurrentLang() === "en") {
48            prefixer = '/'
49        } else {
50            prefixer = `/${this.getCurrentLang()}`
51        }
52        return prefixer;
53    },
54    /**
55     * 获取URL参数
56     * @param {string} name 为search的键
57     * @param {string} url 是一个可选项,不传时为当前页面地址
58     * */
59    getUrlParameter: function (name, url) {
60        var e = url || window.location.search;
61        var c = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
62        var d = e.substr(1).match(c);
63        if (d != null) {
64            return decodeURIComponent(d[2]);
65        }
66        return null;
67    },
68    /**
69     * 防抖函数
70     * @param {Function} func: 要执行的函数
71     * @param {number}delay: 延迟时间(毫秒)
72     * @return {Function} 防抖的函数
73     */
74    debounce: function (func, delay = 500) {
75        let timeout;
76        return function () {
77            const context = this,
78                args = arguments;
79            // 清除之前的定时器
80            clearTimeout(timeout);
81            // 设置新的定时器
82            timeout = setTimeout(() => func.apply(context, args), delay);
83        };
84    },
85    /**
86     * 节流函数
87     * @param {Function} func: 要执行的函数
88     * @param {number} limit: 时间间隔(毫秒),在此时间内只执行一次
89     * @return {Function} 节流的函数
90     */
91    throttle: function (func, limit) {
92        let lastFunc;
93        let lastRan;
94        return function () {
95            const context = this,
96                args = arguments;
97            // 如果没有上一次执行时间,立即执行函数
98            if (!lastRan) {
99                func.apply(context, args);
100                lastRan = Date.now();
101            } else {
102                // 清除之前的定时器
103                clearTimeout(lastFunc);
104                lastFunc = setTimeout(function () {
105                    // 判断是否超过时间间隔,如果超过则执行函数
106                    if ((Date.now() - lastRan) >= limit) {
107                        func.apply(context, args);
108                        lastRan = Date.now();
109                    }
110                }, limit - (Date.now() - lastRan));
111            }
112        };
113    },
114    // 检查元素是否在视口中
115    isInViewport: function ($elem) {
116        if (!($elem instanceof jQuery)) {
117            // console.error("请传入jquery对象")
118            return
119        }
120        const rect = $elem[0].getBoundingClientRect();
121        return (
122            rect.top >= 0 &&
123            rect.left >= 0 &&
124            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
125            rect.right <= (window.innerWidth || document.documentElement.clientWidth)
126        );
127    },
128    // 判断当前设备是否时移动端
129    isMobile: function () {
130        return /Mobi|Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
131    },
132    // cookie start
133    // 获取当前域名的主域部分,用于设置cookie的域
134    cookieDomain: function () {
135        const a = window.location.hostname;
136        return "." + a.split(".")[1] + "." + a.split(".")[2];
137    },
138    /**
139     *  设置cookie
140     * @param {string} name: cookie的名称
141     * @param {string} value: cookie的值
142     * @param {object=} options: 可选参数,包括过期天数、路径和域名
143     */
144    setCookie: function (name, value, options = {}) {
145        const {
146            days = null, path = "/", domain = this.cookieDomain()
147        } = options;
148        let expires = "";
149        // 如果指定了过期天数,则计算过期时间
150        if (days !== null) {
151            const date = new Date();
152            date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
153            expires = `expires=${date.toUTCString()};`;
154        }
155        // 生成cookie字符串
156        let cookie = `${name}=${encodeURIComponent(value)};${expires}path=${path}`;
157        if (domain) {
158            cookie += `;domain=${domain}`;
159        }
160        // 设置cookie
161        document.cookie = cookie;
162    },
163
164    /**
165     * 获取指定名称的cookie值
166     * @param {string} name: cookie的名称
167     */
168    getCookie: function (name) {
169        const cookies = document.cookie.split(";");
170        // 遍历所有cookie,查找指定名称的cookie
171        for (let i = 0; i < cookies.length; i++) {
172            const cookie = cookies[i].trim();
173            if (cookie.startsWith(`${name}=`)) {
174                // 返回解码后的cookie值
175                return decodeURIComponent(cookie.substring(name.length + 1));
176            }
177        }
178        // 如果未找到cookie,则返回null
179        return null;
180    },
181    /**
182     * 移除指定名称的cookie
183     * @param {string} name: cookie的名称
184     */
185    removeCookie: function (name) {
186        // 设置cookie的过期时间为过去,来删除cookie
187        document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=${this.cookieDomain()}`;
188    },
189    // cookie end
190    // 货币格式设置
191    currencySettings: {
192        en: {
193            symbol: "$",
194            format: "%s%v",
195            decimal: ".",
196            thousand: ",",
197            precision: 2,
198        },
199        fr: {
200            symbol: "€",
201            format: "%v %s",
202            decimal: ",",
203            thousand: " ",
204            precision: 2,
205        },
206        it: {
207            symbol: "€",
208            format: "%v %s",
209            decimal: ",",
210            thousand: ".",
211            precision: 2,
212        },
213        de: {
214            symbol: "€",
215            format: "%v %s",
216            decimal: ",",
217            thousand: ".",
218            precision: 2,
219        },
220        es: {
221            symbol: "€",
222            format: "%v %s",
223            decimal: ",",
224            thousand: ".",
225            precision: 2,
226        },
227        tw: {
228            symbol: "NT$",
229            format: "%s%v",
230            decimal: ".",
231            thousand: ",",
232            precision: 0,
233        },
234        jp: {
235            symbol: "円",
236            format: "%v%s",
237            decimal: ".",
238            thousand: ",",
239            precision: 0,
240        },
241        pl: {
242            symbol: "€",
243            format: "%v %s",
244            decimal: ",",
245            thousand: ".",
246            precision: 2,
247        },
248        nl: {
249            symbol: "€",
250            format: "%v %s",
251            decimal: ",",
252            thousand: ".",
253            precision: 2,
254        },
255    },
256    /**
257     * 获取当前语言的货币格式
258     * @param {string=} b 是语言简称,默认值当前语言
259     * @return {object} 返回一个当前语言货币格式对象
260     */
261    getCurrencySettings: function (b = this.getCurrentLang()) {
262        var a = this;
263        if (!a.currencySettings.hasOwnProperty(b)) {
264            b = "en";
265        }
266        return a.currencySettings[b];
267    },
268    // 关于货币的 end
269
270    // 复制内容到剪切板
271    copyToClipboard: function (text) {
272        if (navigator.clipboard && navigator.clipboard.writeText) {
273            navigator.clipboard.writeText(text).then(() => {}).catch(err => {
274                console.error('复制失败', err);
275            });
276        } else {
277            // 使用 document.execCommand 作为备选方案
278            const textarea = document.createElement('textarea');
279            textarea.value = text;
280            textarea.style.position = 'fixed'; // 防止页面跳动
281            document.body.appendChild(textarea);
282            textarea.focus();
283            textarea.select();
284
285            try {
286                const successful = document.execCommand('copy');
287                const msg = successful ? '复制成功' : '复制失败';
288            } catch (err) {
289                console.error('无法复制', err);
290            }
291
292            document.body.removeChild(textarea);
293        }
294    }
295})
296
297$.fn.extend({
298    /**
299      * 在元素首次出现在可视区域内添加入场动画
300      * data-animation 属性为每个元素设置自定义动画类
301      * 如果元素没有设置 data-anim 属性,则会使用传入的默认动画类 
302    //   * @param {string} defaultAnimationClass 动画类名,
303      * @param {number} offset 为可视区域下方的偏移量,默认为0
304     */
305    animateOnScroll: function (offset = 0.2) {
306        // 选择所有带有 data-anim 属性的元素
307        var elementsToAnimate = $("[data-anim]");
308        // 创建 IntersectionObserver 实例
309        var observer = new IntersectionObserver(
310            function (entries) {
311                entries.forEach(function (entry) {
312                    if (entry.isIntersecting) {
313                        var $target = $(entry.target);
314                        var $thisClassName = $target.data("anim"); // 获取动画类名
315                        var duration = $target.attr("data-animation-delay"); // 获取动画延迟时间,默认 1s
316
317                        // 设置动画延迟时间
318                        duration && $target.css("animation-delay", duration);
319
320                        // 添加动画触发类
321                        $target.addClass("anim " + $thisClassName);
322
323                        // 一旦动画触发,停止观察此元素
324                        observer.unobserve(entry.target);
325                    }
326                });
327            }, {
328                threshold: offset, // 当元素至少 20% 进入视口时触发
329            }
330        );
331
332        // 观察所有目标元素
333        elementsToAnimate.each(function () {
334            observer.observe(this);
335        });
336    },
337    /**
338     * 选项卡切换功能
339     * @param {string} tabSelector: 选项卡的选择器
340     * @param {string} contentSelector: 内容的选择器
341     */
342    tabSwitch: function (tabSelector, contentSelector) {
343
344        // 遍历每个容器,使其独立工作
345        this.each(function () {
346            const $tabContainer = $(this);
347            // console.log($tabContainer.attr('class'));
348            const type = $tabContainer.attr('data-event') || 'click';
349            $tabContainer.find(tabSelector).css({
350                cursor: "pointer"
351            });
352            $tabContainer.find(contentSelector).hide();
353            $tabContainer.find(contentSelector + '.active').show();
354            // 绑定点击事件到每个选项卡按钮
355            $tabContainer.find(tabSelector).on(type, function () {
356                const $thisBtn = $(this);
357                const $tableBtnParent = $thisBtn.parent(); // 当前选项卡父级
358                // 移除当前组的所有选项卡按钮和内容的激活状态
359                $tabContainer.find(tabSelector).removeClass('active');
360                $tabContainer.find(contentSelector).removeClass('active');
361
362                // 设置当前点击的按钮为激活状态
363                $thisBtn.addClass('active');
364
365                // 设置当前选项卡父级位置变量
366                // $tableBtnParent.css('--tab-btn-slider',  $thisBtn.offset().left - $tableBtnParent.offset().left);
367                $tableBtnParent[0].style.setProperty('--tab-btn-slider', ($thisBtn.offset().left - $tableBtnParent.offset().left) + 'px');
368
369                // 根据索引显示对应的内容
370                const index = $thisBtn.index();
371                $tabContainer.find(contentSelector).hide().eq(index).addClass('active').show();
372
373                // 解决slick容器在初始化为display:none的情况下,slick无法取得正常宽度
374                $('[data-slick="content"]').each(function (i, item) {
375                    $(item).slick('setPosition'); // 在尺寸变化时重新计算
376                })
377            });
378        });
379    },
380
381    /**
382     * 手风琴效果
383     * @param {string} headerSelector: 手风琴标题的选择器
384     * @param {string} contentSelector: 手风琴内容的选择器
385     */
386    accordion: function (headerSelector, contentSelector) {
387        $(headerSelector).css({
388            cursor: "pointer"
389        });
390        // 遍历每个手风琴容器,使其独立工作
391        this.each(function () {
392            const $accordionContainer = $(this);
393
394            // 初始化:隐藏所有内容区域
395
396            $accordionContainer.find(contentSelector).hide();
397            $accordionContainer.find('.active').find(contentSelector).show();
398
399            // 绑定点击事件到每个手风琴标题
400            $accordionContainer.find(headerSelector).on('click', function () {
401                const $thisHeader = $(this);
402                const $content = $thisHeader.next(contentSelector);
403                $accordionContainer.find(contentSelector).not($content).slide
403Up().parent().removeClass('active');
404                $content.slideToggle().parent().toggleClass('active');
405            });
406        });
407    },
408    /**
409     * 表格的是否展示不同的选项,关闭相同选项
410     * @param {object} options
411     * @param {string} options.titleAttr 分组按钮的属性名,默认为groud-title
412     * @param {string} options.contentAttr 分组内容的属性名,默认为groud-content
413     * @param {number} options.mode 展开关闭的模式,有1和非1,默认值为1(表示只展示一组数据), 非1(每组展开关闭互相没有关系)
414     */
415    tableDisplayDifferent: function () {
416        var def = {
417            titleAttr: "groud-title",
418            contentAttr: "groud-content",
419            mode: 1
420        }
421        options = {
422            ...def,
423            ...options
424        }
425        this.each(function (i, it) {
426            var $table = $(it);
427            var $trBtn = $table.find(`[${options.titleAttr}]`);
428            // var $trContent = $table.find('[groud-content]');
429            $trBtn.on('click', function () {
430
431                var $this = $(this);
432                var openKey = $this.attr(options.titleAttr);
433
434                $this.parents('table').find(`[${options.contentAttr}="${openKey}"]`).toggle();
435                if (options.mode == 1) {
436                    $this.parents('table').find(`[${options.contentAttr}]`).not(`[${options.contentAttr}="${openKey}"]`).hide();
437                }
438
439
440            })
441        })
442    },
443    /**
444     * 固定表格表头
445     *
446     */
447    fixedTableHeader: function () {
448        this.each(function (i, it) {
449            const $table = $(it);
450            const tableHeight = $table.height();
451            const headerHeight = $table.find('thead').height();
452
453            $(window).on('scroll', function () {
454                const scrollTop = $(this).scrollTop();
455                if (scrollTop > $table.offset().top && scrollTop < tableHeight + $table.offset().top - headerHeight - 100) {
456                    $table.addClass('fixed-head').find('thead').css({
457                        position: "sticky",
458                        top: 0,
459                        "z-index": 90
460                    });
461                } else {
462                    $table.removeClass('fixed-head').find('thead').css({
463                        position: 'static'
464                    });
465                }
466            });
467        })
468
469        // return this; // 支持链式调用
470    },
471
472    /**
473     * 表格一些操作方法
474     * 显示/隐藏相同内容、分组行的展开/收起功能
475     * @param {object} options
476     * @param {string} options.sameBtnSelector 触发隐藏/显示相同内容的按钮选择器,默认'[data-same="btn"]'
477     * @param {string} options.sameContentSelector 表示相同内容的行选择器,默认'[data-same="content"]'
478     * @param {string} options.groupTitleAttr 分组标题的属性名,默认 groud-title,同一组分组标题和分组内容就应当写一样的属性值
479     * @param {string} options.groupContentAttr 分组内容的属性名,默认'groud-content',同一组分组标题和分组内容就应当写一样的属性值
480     * @param {number} options.groudSwitchMode 分组切换模式 (1: 仅展开一个组,其他组自动收起; 非1: 每个组单独控制),默认为1
481     * @param {string} options.sameBtnSelector 表示当前活动状态的类名,默认为active
482     * 
483     */
484    tableEvents: function (options) {
485        var settings = $.extend({
486            sameBtnSelector: '[data-same="btn"]',
487            sameContentSelector: '[data-same="content"]',
488            groupTitleAttr: "groud-title",
489            groupContentAttr: "groud-content",
490            groudSwitchMode: 1,
491            activeClass: "active"
492        }, options);
493
494
495        // 是否隐藏相同,只展示不同
496        var viewDif = function () {
497            $(settings.sameBtnSelector).on("click", function (e) {
498
499                var $this = $(this);
500                var $currTable = $this.parents('table');
501                var $sameCnt = $currTable.find(settings.sameContentSelector)
502                if (!$this.hasClass(settings.activeClass)) {
503                    $this.addClass(settings.activeClass);
504                    $sameCnt.hide();
505                } else {
506                    $this.removeClass(settings.activeClass);
507                    // 判断分组是否打开,只对分组打开的项
508                    $sameCnt.each(function (i, sameCntIt) {
509                        var $sameCntIt = $(sameCntIt);
510                        var groudName = $sameCntIt.attr(settings.groupContentAttr);
511                        // isOpen表示是否对当前sameCnt展开
512                        var isOpen = $currTable.find(`[${settings.groupTitleAttr}="${groudName}"]`).hasClass(settings.activeClass); // 判断当前组是否是关闭状态
513                        isOpen && $sameCntIt.show();
514                        // 没有分组的展开
515                        !groudName && $sameCntIt.show();
516
517                    });
518                }
519            });
520        };
521
522        // 分组
523        var slideTr = function () {
524            $(`[${settings.groupTitleAttr}]`).click(function () {
525                var $this = $(this);
526                var $table = $this.parents('table');
527                var name = $this.attr(settings.groupTitleAttr); // 组名
528                var isOpen = $this.hasClass(settings.activeClass);
529                // 非模式1只管自身的展开收起,不管其他组
530                if (settings.groudSwitchMode !== 1) {
531                    this.toggleClass(settings.activeClass);
532                    $table.find(`${settings.groupContentAttr}=""${name}`).toggle();
533                    return
534                }
535
536
537                // 模式1只展示一个组数组
538                if (!isOpen) {
539
540                    // 隐藏同级的其他组
541                    $table.find(`[${settings.groupTitleAttr}]`).removeClass(settings.activeClass);
542                    $table.find(`[${settings.groupContentAttr}]`).hide();
543
544                    // 展开当前组
545                    $this.addClass(settings.activeClass);
546                    // 判断是否选择了隐藏相同
547                    if ($table.find(settings.sameBtnSelector).hasClass(settings.activeClass)) {
548                        $table.find(`[${settings.groupContentAttr}="${name}"]`).each(function (i, currGourdCntIt) {
549                            var $currGourdCntIt = $(currGourdCntIt).not(settings.sameContentSelector);
550                            $currGourdCntIt.show();
551                        })
552                    } else {
553                        $table.find(`[${settings.groupContentAttr}="${name}"]`).show();
554                    }
555                } else {
556                    $this.removeClass(settings.activeClass);
557                    $table.find(`[${settings.groupContentAttr}="${name}"]`).hide();
558                }
559            });
560        };
561
562        // 初始隐藏组内容
563        var hideTr = function () {
564            $(`[${settings.groupTitleAttr}]`).each(function () {
565                var $this = $(this);
566                var name = $this.attr(settings.groupTitleAttr);
567                if (!$this.hasClass(settings.activeClass)) {
568                    $this.parents('table').find(`[${settings.groupContentAttr}="${name}"]`).hide();
569                }
570            });
571        };
572        // 初始化
573        viewDif();
574        slideTr();
575        hideTr();
576        // 返回当前 jQuery 对象,以便继续链式调用
577        return this;
578
579    },
580    /**
581     * 将元素的文本内容复制到剪切板,并支持成功复制后的回调
582     * @param {function=} callback - 可选的回调函数,在复制成功后执行
583     * @returns {jQuery} 支持链式调用
584     */
585    copyToClipboard: function (callback) {
586        // 遍历 jQuery 对象中的每个元素
587        this.each(function () {
588            const $this = $(this);
589            const textToCopy = $this.text(); // 获取元素的文本内容
590
591            // 创建一个临时的文本区域来进行复制
592            const tempInput = $("<textarea>");
593            $("body").append(tempInput);
594            tempInput.val(textToCopy).select();
595
596            // 尝试执行复制操作
597            const success = document.execCommand("copy");
598            tempInput.remove(); // 移除临时元素
599
600            // 如果成功且回调函数存在,则调用回调函数
601            if (success && typeof callback === "function") {
602                callback.call(this, textToCopy);
603            }
604        });
605
606        return this; // 支持链式调用
607    },
608    dropdown: function (selectHead, options) {
609        return this.each(function () {
610            var $select = $(this);
611            var $selectHead = $select.find(selectHead);
612            var $selectedOption = $select.find('.current');
613            //   var $arrow = $select.find('.arrow');
614            var $options = $select.find(options);
615            var $optionItems = $options.children();
616
617            // 隐藏选项列表
618            $options.hide();
619
620            // 点击头部时,显示或隐藏选项列表
621            $selectHead.on('click', function () {
622                $options.toggle();
623                $select.toggleClass('open'); // 可以为箭头添加展开的效果
624            });
625
626            // 点击选项时,更新选中的内容,并隐藏选项列表
627            $optionItems.on('click', function () {
628                var selectedText = $(this).text();
629                $selectedOption.text(selectedText); // 更新头部显示
630                $options.hide(); // 隐藏选项
631                $select.removeClass('open'); // 收起箭头
632
633                // 触发 change 事件,传递选中值
634                $select.trigger('change', selectedText);
635            });
636
637            // 点击页面其他地方时,关闭下拉框
638            $(document).on('click', function (e) {
639                if (!$(e.target).closest($select).length) {
640                    $options.hide();
641                    $select.removeClass('open');
642                }
643            });
644        });
645    }
646})

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.