import Swiper from './swiper-bundle.esm.browser.min.js';
import { CountUp } from './countUp.min.js';
/** 屏幕宽度 */
export const WINDTH = innerWidth;
/** 屏幕高度 */
export const HEIGHT = innerHeight;
export function onEnter(inputEl, callback) {
$(inputEl).focus((e) => {
$(document).keyup((e) => {
if (e.keyCode == 13) {
const value = $(inputEl).val();
callback(value);
}
});
});
$(inputEl).focusout(() => {
$(document).off('keyup');
});
}
export function gsapAni() {
if (!window.gsap) return;
gsap.registerPlugin(ScrollTrigger);
let bottom = 100;
if (WINDTH < 980) {
bottom = 20;
}
ScrollTrigger.batch('[data-scroll]', {
toggleClass: 'inview',
start: `top bottom-=${bottom}px`,
end: `bottom top+=${bottom}px`,
});
ScrollTrigger.batch('[data-inview]', {
toggleClass: 'inview',
});
const ro = new ResizeObserver((entries) => {
ScrollTrigger.refresh();
});
// 观察一个或多个元素
ro.observe(document.querySelector('body'));
}
/**
* 吸顶
* @param {String} boxEl 容器css选择器
* @param {String} El 吸顶元素css选择器
*/
export function sticky(boxEl, El, TOP = 0) {
const box = $(boxEl);
const el = $(El);
if (box.length === 0) return;
const boxH = box.outerHeight(true);
const elH = el.outerHeight(true);
const start = box.offset().top - TOP;
const end = boxH - elH + start;
box.css('position', 'relative');
handleScroll({
scroll(st) {
if (st >= start) {
el.css({
position: 'fixed',
top: `${TOP}px`,
});
} else {
el.css('position', 'static');
}
if (st >= end) {
el.css({
position: 'absolute',
top: `${end - start}px`,
});
}
},
});
}
export function inBox() {
const box = document.querySelectorAll('.inbox');
box.forEach((el) => {
const text = el.textContent.split('\n');
const dom = text.map((e) => {
return `
`.trim();
});
el.innerHTML = dom.join('');
});
}
export function fadeOut(el) {
el.style.opacity = 1;
(function fade() {
if ((el.style.opacity -= 0.03) < 0) {
el.style.display = 'none';
} else {
requestAnimationFrame(fade);
}
})();
}
export function fadeIn(el, display) {
el.style.opacity = 0;
el.style.display = display || 'block';
(function fade() {
var val = parseFloat(el.style.opacity);
if (!((val += 0.04) > 1)) {
el.style.opacity = val;
requestAnimationFrame(fade);
}
})();
}
/**
* 点击目标非指定元素及其子元素时触发回调
* @param {JqueryEl} node 指定元素
* @param {Function} callback 回调
*/
export function awayClick(node, callback) {
$(document).on('click', (e) => {
const lg = node.parent().find(e.target).length;
if (lg === 0) {
callback &&
(typeof callback == 'function'
? callback()
: console.error('callback 必须是 function'));
}
});
}
/**
* countUp
* @param {string} className 需要countUp的元素类名 默认 .count
*/
export function countUp(className = '.count') {
const els = document.querySelectorAll(className);
els.forEach((el) => {
const number = Number(el.textContent);
new CountUp(el, number, {
enableScrollSpy: true,
separator: '',
});
});
}
/**
* 文件下载
* 查找a[download],重写下载逻辑,避免图片在新标签页打开
*/
export function resetDownload() {
const body = document.querySelector('body');
window.resetDownloadMethod = function (e) {
e.preventDefault();
const url = this.href;
const split = url.split('/');
const name = split[split.length - 1];
const x = new XMLHttpRequest();
x.open('GET', url, true);
x.responseType = 'blob';
x.onload = function (e) {
const url = window.URL.createObjectURL(x.response);
const a = document.createElement('a');
a.href = url;
a.download = decodeURI(name);
a.click();
};
x.send();
};
const reset = () => {
const files = document.querySelectorAll('a[download]');
files.forEach((el) => {
el.removeEventListener('click', window.resetDownloadMethod);
el.addEventListener('click', window.resetDownloadMethod);
});
};
reset();
const observer = new MutationObserver(reset);
observer.observe(body, {
childList: true,
subtree: true,
});
}
/**
* 控制元素显示隐藏
* @param {String} el 被控元素 class
*/
export function changeDisplay(el) {
if ($(el).css('display') == 'none') {
$(el).fadeIn();
} else {
$(el).hide();
}
}
/**
* 复制链接
*/
export function copyLink() {
const el = $('.copylink');
el.click(() => {
const link = window.location.href;
const res = copyToClipboard(link);
res
.then(() => {
alert('已成功将链接复制到剪切板');
})
.catch(() => {
alert('链接复制失败, 请手动复制链接: ', link);
});
});
}
/**
* 移动端横向菜单选中项定位
*/
export function scrollX() {
const box = $('.nav, [sx], .crumbs');
const active = box.find('.active,.on');
const w = document.body.offsetWidth;
if (w < 980) {
if (box.length === 0) return;
box.scrollLeft(active.position().left - box.position().left - w * 0.1);
}
}
/**
* @typedef swiperOptions
* @prop {swiperOptions} mobile 移动端设置
* @prop {{
* [key: number]: swiperOptions
* }} breakpoints 断点
* @prop {number | 'auto'} slidesPerView 展示个数
* @prop {number} spaceBetween 间距
* @prop {'horizontal'|'vertical'} 水平或垂直
* @prop {'slide'|'fade'} effect
* @prop {number} speed
* @prop {boolean} loop
* @prop {boolean | {
* disableOnInteraction: boolean
* }} autoplay
* @prop {number} delay
* @prop {boolean} autovideoplay
* @prop {boolean} observer
* @prop {{
* nextEl: string
* prevEl: string
* }} navigation
* @prop {{
* init: (swiper) => void
* }} on
*/
/**
* 设置swiper
* @param {String} boxEl swiper容器
* @param {swiperOptions} opts 选项
*/
export function setSwiper(boxEl, opts = {}) {
const box = document.querySelector(boxEl);
if (box === null) return null;
const { length } = [...box.children].filter((e) => {
if (e.classList.contains('swiper-wrapper')) {
return true;
}
});
if (length == 0) return null;
let options = {
direction: 'horizontal',
speed: 1500,
loop: false,
autoplay: false,
delay: 4000,
noSwiping: true,
noSwipingClass: 'no-swiping',
slideActiveClass: 'active',
normalizeSlideIndex: false,
};
if (WINDTH < 980) {
options = Object.assign(options, opts.mobile);
}
if (opts.effect === 'fade') {
options = {
...options,
fadeEffect: {
crossFade: true,
},
};
}
if (opts.autoplay) {
opts.autoplay = Object.assign(
{
delay: opts.delay || options.delay,
},
opts.autoplay
);
}
if (opts.observer) {
opts = {
...opts,
observer: true,
observeParents: true,
observeSlideChildren: true,
};
}
let final = Object.assign(options, opts);
if (WINDTH < 980) {
final = Object.assign(options, { ...opts, ...opts.mobile });
}
const swiper = new Swiper(boxEl, final);
if (opts.autovideoplay) {
let timer = null;
function next() {
swiperNext(swiper);
}
function videoslidechange() {
const videos = swiper.el.querySelectorAll('video');
const video = () =>
swiper.slides[swiper.realIndex]?.querySelector('video');
clearTimeout(timer);
if (video()) {
video().play();
video().removeEventListener('ended', next);
video().addEventListener('ended', next);
} else {
videos.forEach((e) => {
e.pause();
e.currentTime = 0;
});
timer = setTimeout(() => {
swiperNext(swiper);
}, options.delay || 4000);
}
}
videoslidechange();
swiper.on('slideChange', videoslidechange);
}
return swiper;
}
export function swiperNext(swiper) {
const index = swiper.realIndex;
if (index === swiper.slides.length - 1) {
swiper.slideTo(0);
} else {
swiper.slideNext();
}
}
export function swiperPrev(swiper) {
const index = swiper.realIndex;
if (index === 0) {
swiper.slideTo(swiper.slides.length - 1);
} else {
swiper.slideTo(index - 1);
}
}
/**
* 禁止图片拖拽
*/
export function imgDraggable() {
const imgs = $('img');
imgs.attr('draggable', false).css('user-select', 'none');
}
/**
* 监听大小变化
* @param {css} el 需要监听的元素 css 选择器
* @param {function} callback mutation =>
*/
export function onResizeObserver(el, callback) {
const ro = new ResizeObserver((mutation) => {
mutation.forEach((e) => callback(e));
});
ro.observe(document.querySelector(el));
}
/**
* 监听dom的类名和样式变化
* @param {Node} node 需要监听的节点
* @param {function} callback mutation =>
*/
export function onAttrObserver(node, callback) {
const AttrObserver = new MutationObserver((mutationsList) => {
mutationsList.forEach(callback);
});
AttrObserver.observe(node, {
attributes: true,
attributeOldValue: true,
attributeFilter: ['class', 'style'],
});
}
/**
* 处理弹窗
* @param {ClassName} cls 元素类名
* @returns {open, close}
*/
export function handlePop(cls) {
const pop = $(cls);
const close = () => pop.fadeOut();
const open = () => pop.fadeIn();
pop.click((e) => {
const target = $(e.target);
if (target.closest('.con').length === 0) {
close();
}
});
return { open, close };
}
/**
* 处理滚动
* @param {Object} funcs {scroll: func, up: func, down: func}
*/
export function handleScroll(funcs) {
let position = $(window).scrollTop();
$(window).on(
'scroll',
throttle(
() => {
const st = $(window).scrollTop();
typeof funcs.scroll === 'function' && funcs.scroll(st);
if (st > position) {
typeof funcs.down === 'function' && funcs.down(st);
} else {
typeof funcs.up === 'function' && funcs.up(st);
}
position = st;
},
50,
1
)
);
}
/**
* 返回顶部
* @param {cssSelect} $el 能通过css选择器查找到的点击元素 [to-top]
*/
export function toTop($el) {
$el = $el || '[to-top]';
const el = $($el);
el.on('click', () => {
$('html,body').stop().animate({ scrollTop: 0 }, 600);
});
const hide = () => el.fadeOut();
let timer = null;
const show = (flex = false) => {
clearTimeout(timer);
if (el.css('display') === 'none') {
if (flex) {
el.css('display', 'flex').hide().fadeIn();
} else {
el.fadeIn();
}
}
timer = setTimeout(() => {
hide();
}, 2000);
};
return {
show,
hide,
el,
};
}
/**
* 防抖
* @param func 函数
* @param wait 延迟执行毫秒数
* @param immediate true 表立即执行,false 表非立即执行
*/
export function debounce(func, wait, immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout);
if (immediate) {
let callNow = !timeout;
timeout = setTimeout(() => {
timeout = null;
}, wait);
if (callNow) func.apply(context, args);
} else {
timeout = setTimeout(() => {
func.apply(context, args);
}, wait);
}
};
}
/**
* 节流
* @param func 函数
* @param wait 延迟执行毫秒数
* @param type 1 表时间戳版,2 表定时器版
*/
export function throttle(func, wait, type) {
let previous;
if (type === 1) {
previous = 0;
} else if (type === 2) {
let timeout;
}
return function () {
let context = this;
let args = arguments;
if (type === 1) {
let now = Date.now();
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
func.apply(context, args);
}, wait);
}
}
};
}