mirror of
https://github.com/jerryc127/hexo-theme-butterfly.git
synced 2026-08-08 11:38:42 +08:00
improvement
This commit is contained in:
+156
-146
@@ -2,18 +2,25 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
let headerContentWidth, $nav
|
||||
let mobileSidebarOpen = false
|
||||
|
||||
// rightsideScrollPercent
|
||||
let goUpElement = null
|
||||
let scrollPercentElement = null
|
||||
|
||||
const adjustMenu = init => {
|
||||
const getAllWidth = ele => Array.from(ele).reduce((width, i) => width + i.offsetWidth, 0)
|
||||
let hideMenuIndex = false
|
||||
|
||||
if (init) {
|
||||
const blogInfoWidth = getAllWidth(document.querySelector('#blog-info > a').children)
|
||||
const menusWidth = getAllWidth(document.getElementById('menus').children)
|
||||
const blogInfoWidth = Array.from(document.querySelector('#blog-info > a').children).reduce((w, i) => w + i.offsetWidth, 0)
|
||||
const menusWidth = Array.from(document.getElementById('menus').children).reduce((w, i) => w + i.offsetWidth, 0)
|
||||
headerContentWidth = blogInfoWidth + menusWidth
|
||||
$nav = document.getElementById('nav')
|
||||
}
|
||||
|
||||
const hideMenuIndex = window.innerWidth <= 768 || headerContentWidth > $nav.offsetWidth - 120
|
||||
$nav.classList.toggle('hide-menu', hideMenuIndex)
|
||||
hideMenuIndex = window.innerWidth <= 768 || headerContentWidth > $nav.offsetWidth - 120
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
$nav.classList.toggle('hide-menu', hideMenuIndex)
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化header
|
||||
@@ -54,7 +61,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
* 代碼
|
||||
* 只適用於Hexo默認的代碼渲染
|
||||
*/
|
||||
const addHighlightTool = () => {
|
||||
const addHighlightTool = $article => {
|
||||
const highLight = GLOBAL_CONFIG.highlight
|
||||
if (!highLight) return
|
||||
|
||||
@@ -64,8 +71,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const isNotHighlightJs = plugin !== 'highlight.js'
|
||||
const isPrismjs = plugin === 'prismjs'
|
||||
const $figureHighlight = isNotHighlightJs
|
||||
? Array.from(document.querySelectorAll('code[class*="language-"]')).map(code => code.parentElement)
|
||||
: document.querySelectorAll('figure.highlight')
|
||||
? Array.from($article.querySelectorAll('code[class*="language-"]')).map(code => code.parentElement)
|
||||
: $article.querySelectorAll('figure.highlight')
|
||||
|
||||
if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return
|
||||
|
||||
@@ -167,33 +174,23 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
// 獲取隱藏狀態下元素的真實高度
|
||||
const getActualHeight = item => {
|
||||
if (item.offsetHeight > 0) return item.offsetHeight
|
||||
const hiddenElements = new Map()
|
||||
|
||||
const fix = () => {
|
||||
let current = item
|
||||
while (current !== document.body && current != null) {
|
||||
if (window.getComputedStyle(current).display === 'none') {
|
||||
hiddenElements.set(current, current.getAttribute('style') || '')
|
||||
}
|
||||
current = current.parentNode
|
||||
}
|
||||
const clone = item.cloneNode(true)
|
||||
|
||||
const style = 'visibility: hidden !important; display: block !important;'
|
||||
hiddenElements.forEach((originalStyle, elem) => {
|
||||
elem.setAttribute('style', originalStyle ? originalStyle + ';' + style : style)
|
||||
})
|
||||
}
|
||||
clone.style.cssText = `
|
||||
position: absolute !important;
|
||||
visibility: hidden !important;
|
||||
display: block !important;
|
||||
left: 0 !important;
|
||||
top: 0 !important;
|
||||
pointer-events: none !important;
|
||||
z-index: -1 !important;
|
||||
margin: 0 !important;
|
||||
`
|
||||
|
||||
const restore = () => {
|
||||
hiddenElements.forEach((originalStyle, elem) => {
|
||||
if (originalStyle === '') elem.removeAttribute('style')
|
||||
else elem.setAttribute('style', originalStyle)
|
||||
})
|
||||
}
|
||||
|
||||
fix()
|
||||
const height = item.offsetHeight
|
||||
restore()
|
||||
item.parentNode.insertBefore(clone, item)
|
||||
const height = clone.offsetHeight
|
||||
clone.remove()
|
||||
return height
|
||||
}
|
||||
|
||||
@@ -244,9 +241,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
/**
|
||||
* PhotoFigcaption
|
||||
*/
|
||||
const addPhotoFigcaption = () => {
|
||||
const addPhotoFigcaption = $article => {
|
||||
if (!GLOBAL_CONFIG.isPhotoFigcaption) return
|
||||
document.querySelectorAll('#article-container img').forEach(item => {
|
||||
$article.querySelectorAll('img').forEach(item => {
|
||||
const altValue = item.title || item.alt
|
||||
if (!altValue) return
|
||||
const ele = document.createElement('div')
|
||||
@@ -259,8 +256,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
/**
|
||||
* Lightbox
|
||||
*/
|
||||
const runLightbox = () => {
|
||||
btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)'))
|
||||
const runLightbox = $article => {
|
||||
btf.loadLightbox($article.querySelectorAll('img:not(.no-lightbox)'))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,11 +421,11 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
*/
|
||||
const rightsideScrollPercent = currentTop => {
|
||||
const scrollPercent = btf.getScrollPercent(currentTop, document.body)
|
||||
const goUpElement = document.getElementById('go-up')
|
||||
|
||||
if (!goUpElement || !scrollPercentElement) return
|
||||
if (scrollPercent < 95) {
|
||||
goUpElement.classList.add('show-percent')
|
||||
goUpElement.querySelector('.scroll-percent').textContent = scrollPercent
|
||||
scrollPercentElement.textContent = scrollPercent
|
||||
} else {
|
||||
goUpElement.classList.remove('show-percent')
|
||||
}
|
||||
@@ -465,7 +462,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
let flag = ''
|
||||
const scrollTask = btf.throttle(() => {
|
||||
const scrollTask = btf.rafThrottle(() => {
|
||||
const currentTop = window.scrollY || document.documentElement.scrollTop
|
||||
const isDown = scrollDirection(currentTop)
|
||||
if (currentTop > 56) {
|
||||
@@ -497,18 +494,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
isShowPercent && rightsideScrollPercent(currentTop)
|
||||
checkDocumentHeight()
|
||||
}, 300)
|
||||
})
|
||||
|
||||
btf.addEventListenerPjax(window, 'scroll', scrollTask, { passive: true })
|
||||
}
|
||||
|
||||
/**
|
||||
* toc,anchor
|
||||
* toc, anchor
|
||||
*/
|
||||
const scrollFnToDo = () => {
|
||||
const scrollFnToDo = $article => {
|
||||
const isToc = GLOBAL_CONFIG_SITE.isToc
|
||||
const isAnchor = GLOBAL_CONFIG.isAnchor
|
||||
const $article = document.getElementById('article-container')
|
||||
|
||||
if (!($article && (isToc || isAnchor))) return
|
||||
|
||||
@@ -521,7 +517,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
$tocPercentage = $cardTocLayout.querySelector('.toc-percentage')
|
||||
isExpand = $cardToc.classList.contains('is-expand')
|
||||
|
||||
// toc元素點擊
|
||||
const tocItemClickFn = e => {
|
||||
const target = e.target.closest('.toc-link')
|
||||
if (!target) return
|
||||
@@ -548,86 +543,90 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 處理 hexo-blog-encrypt 事件
|
||||
$cardToc.style.display = 'block'
|
||||
}
|
||||
|
||||
// find head position & add active class
|
||||
const $articleList = $article.querySelectorAll('h1,h2,h3,h4,h5,h6')
|
||||
let detectItem = ''
|
||||
if (!$articleList.length) return
|
||||
|
||||
// Optimization: Cache header positions
|
||||
let headerList = []
|
||||
const updateHeaderPositions = () => {
|
||||
headerList = Array.from($articleList).map(ele => ({
|
||||
ele,
|
||||
top: btf.getEleTop(ele),
|
||||
id: ele.id
|
||||
}))
|
||||
}
|
||||
let activeTocItem = null
|
||||
let activeParentItems = []
|
||||
|
||||
updateHeaderPositions()
|
||||
const throttledUpdate = btf.throttle(updateHeaderPositions, 200)
|
||||
btf.addEventListenerPjax(window, 'resize', throttledUpdate)
|
||||
const updateTocUI = currentId => {
|
||||
const encodedAnchor = currentId ? '#' + encodeURI(decodeURI(currentId)) : ''
|
||||
if (isAnchor) btf.updateAnchor(encodedAnchor)
|
||||
|
||||
if ('ResizeObserver' in window) {
|
||||
const observer = new ResizeObserver(throttledUpdate)
|
||||
observer.observe($article)
|
||||
btf.addGlobalFn('pjaxSendOnce', () => { observer.disconnect() })
|
||||
}
|
||||
if (!isToc) return
|
||||
|
||||
const findHeadPosition = top => {
|
||||
if (top === 0) return false
|
||||
if (activeTocItem) activeTocItem.classList.remove('active')
|
||||
activeParentItems.forEach(i => i.classList.remove('active'))
|
||||
activeParentItems = []
|
||||
|
||||
let currentId = ''
|
||||
let currentIndex = ''
|
||||
|
||||
for (let i = 0; i < headerList.length; i++) {
|
||||
const item = headerList[i]
|
||||
if (top > item.top - 80) {
|
||||
currentId = item.id ? '#' + encodeURI(item.id) : ''
|
||||
currentIndex = i
|
||||
} else {
|
||||
break
|
||||
}
|
||||
if (!currentId) {
|
||||
activeTocItem = null
|
||||
return
|
||||
}
|
||||
|
||||
if (detectItem === currentIndex) return
|
||||
const targetLink = Array.from($tocLink).find(link => {
|
||||
const href = link.getAttribute('href')
|
||||
if (!href) return false
|
||||
return decodeURI(href).replace('#', '') === decodeURI(currentId)
|
||||
})
|
||||
|
||||
if (isAnchor) btf.updateAnchor(currentId)
|
||||
if (!targetLink) return
|
||||
|
||||
detectItem = currentIndex
|
||||
targetLink.classList.add('active')
|
||||
activeTocItem = targetLink
|
||||
setTimeout(() => autoScrollToc(targetLink), 0)
|
||||
|
||||
if (isToc) {
|
||||
$cardToc.querySelectorAll('.active').forEach(i => i.classList.remove('active'))
|
||||
|
||||
if (currentId) {
|
||||
const currentActive = $tocLink[currentIndex]
|
||||
currentActive.classList.add('active')
|
||||
|
||||
setTimeout(() => autoScrollToc(currentActive), 0)
|
||||
|
||||
if (!isExpand) {
|
||||
let parent = currentActive.parentNode
|
||||
while (!parent.matches('.toc')) {
|
||||
if (parent.matches('li')) parent.classList.add('active')
|
||||
parent = parent.parentNode
|
||||
}
|
||||
if (!isExpand) {
|
||||
let parent = targetLink.parentNode
|
||||
while (!parent.matches('.toc')) {
|
||||
if (parent.matches('li')) {
|
||||
parent.classList.add('active')
|
||||
activeParentItems.push(parent)
|
||||
}
|
||||
parent = parent.parentNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// main of scroll
|
||||
const tocScrollFn = btf.throttle(() => {
|
||||
const observerOptions = {
|
||||
root: null,
|
||||
rootMargin: '-60px 0px -80% 0px',
|
||||
threshold: 0
|
||||
}
|
||||
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
updateTocUI(entry.target.id)
|
||||
}
|
||||
})
|
||||
}, observerOptions)
|
||||
|
||||
$articleList.forEach(ele => observer.observe(ele))
|
||||
|
||||
const scrollHandler = btf.rafThrottle(() => {
|
||||
const currentTop = window.scrollY || document.documentElement.scrollTop
|
||||
|
||||
if (isToc && GLOBAL_CONFIG.percent.toc) {
|
||||
$tocPercentage.textContent = btf.getScrollPercent(currentTop, $article)
|
||||
}
|
||||
findHeadPosition(currentTop)
|
||||
}, 100)
|
||||
|
||||
btf.addEventListenerPjax(window, 'scroll', tocScrollFn, { passive: true })
|
||||
if (currentTop === 0) {
|
||||
updateTocUI('')
|
||||
} else if (currentTop + window.innerHeight >= document.documentElement.scrollHeight - 10) {
|
||||
const lastHeader = $articleList[$articleList.length - 1]
|
||||
updateTocUI(lastHeader.id)
|
||||
}
|
||||
})
|
||||
|
||||
btf.addEventListenerPjax(window, 'scroll', scrollHandler, { passive: true })
|
||||
|
||||
btf.addGlobalFn('pjaxSendOnce', () => {
|
||||
observer.disconnect()
|
||||
})
|
||||
}
|
||||
|
||||
const handleThemeChange = mode => {
|
||||
@@ -804,8 +803,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
/**
|
||||
* table overflow
|
||||
*/
|
||||
const addTableWrap = () => {
|
||||
const $table = document.querySelectorAll('#article-container table')
|
||||
const addTableWrap = $article => {
|
||||
const $table = $article.querySelectorAll('table')
|
||||
if (!$table.length) return
|
||||
|
||||
$table.forEach(item => {
|
||||
@@ -815,52 +814,54 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* tag-hide
|
||||
*/
|
||||
const clickFnOfTagHide = () => {
|
||||
const hideButtons = document.querySelectorAll('#article-container .hide-button')
|
||||
const clickFnOfTagHide = $article => {
|
||||
const hideButtons = $article.querySelectorAll('.hide-button')
|
||||
if (!hideButtons.length) return
|
||||
hideButtons.forEach(item => item.addEventListener('click', e => {
|
||||
const currentTarget = e.currentTarget
|
||||
currentTarget.classList.add('open')
|
||||
addJustifiedGallery(currentTarget.nextElementSibling.querySelectorAll('.gallery-container'))
|
||||
}, { once: true }))
|
||||
|
||||
const handleClickOfTagHide = e => {
|
||||
const button = e.target.closest('.hide-button')
|
||||
if (!button) return
|
||||
button.classList.add('open')
|
||||
addJustifiedGallery(button.nextElementSibling.querySelectorAll('.gallery-container'))
|
||||
}
|
||||
|
||||
btf.addEventListenerPjax($article, 'click', handleClickOfTagHide)
|
||||
}
|
||||
|
||||
const tabsFn = () => {
|
||||
const navTabsElements = document.querySelectorAll('#article-container .tabs')
|
||||
if (!navTabsElements.length) return
|
||||
const tabsFn = $article => {
|
||||
if (!$article.querySelector('.tabs')) return
|
||||
|
||||
const setActiveClass = (elements, activeIndex) => {
|
||||
elements.forEach((el, index) => {
|
||||
el.classList.toggle('active', index === activeIndex)
|
||||
})
|
||||
elements.forEach((el, index) => el.classList.toggle('active', index === activeIndex))
|
||||
}
|
||||
|
||||
const handleNavClick = e => {
|
||||
const target = e.target.closest('button')
|
||||
if (!target || target.classList.contains('active')) return
|
||||
const handleClick = e => {
|
||||
const tabsRoot = e.target.closest('.tabs')
|
||||
if (!tabsRoot) return
|
||||
|
||||
const navItems = [...e.currentTarget.children]
|
||||
const tabContents = [...e.currentTarget.nextElementSibling.children]
|
||||
const indexOfButton = navItems.indexOf(target)
|
||||
setActiveClass(navItems, indexOfButton)
|
||||
e.currentTarget.classList.remove('no-default')
|
||||
setActiveClass(tabContents, indexOfButton)
|
||||
addJustifiedGallery(tabContents[indexOfButton].querySelectorAll('.gallery-container'), true)
|
||||
}
|
||||
const navContainer = tabsRoot.firstElementChild
|
||||
const toTopContainer = tabsRoot.lastElementChild
|
||||
|
||||
const handleToTopClick = tabElement => e => {
|
||||
if (e.target.closest('button')) {
|
||||
btf.scrollToDest(btf.getEleTop(tabElement), 300)
|
||||
if (navContainer.contains(e.target)) {
|
||||
const target = e.target.closest('button')
|
||||
if (!target || target.classList.contains('active')) return
|
||||
|
||||
const navItems = [...navContainer.children]
|
||||
const tabContents = [...navContainer.nextElementSibling.children]
|
||||
const indexOfButton = navItems.indexOf(target)
|
||||
setActiveClass(navItems, indexOfButton)
|
||||
navContainer.classList.remove('no-default')
|
||||
setActiveClass(tabContents, indexOfButton)
|
||||
addJustifiedGallery(tabContents[indexOfButton].querySelectorAll('.gallery-container'), true)
|
||||
return
|
||||
}
|
||||
|
||||
if (toTopContainer.contains(e.target) && e.target.closest('button')) {
|
||||
btf.scrollToDest(btf.getEleTop(tabsRoot), 300)
|
||||
}
|
||||
}
|
||||
|
||||
navTabsElements.forEach(tabElement => {
|
||||
btf.addEventListenerPjax(tabElement.firstElementChild, 'click', handleNavClick)
|
||||
btf.addEventListenerPjax(tabElement.lastElementChild, 'click', handleToTopClick(tabElement))
|
||||
})
|
||||
btf.addEventListenerPjax($article, 'click', handleClick)
|
||||
}
|
||||
|
||||
const toggleCardCategory = () => {
|
||||
@@ -926,10 +927,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
const unRefreshFn = () => {
|
||||
window.addEventListener('resize', () => {
|
||||
const resizeHandler = btf.rafThrottle(() => {
|
||||
adjustMenu(false)
|
||||
mobileSidebarOpen && btf.isHidden(document.getElementById('toggle-menu')) && sidebarFn.close()
|
||||
if (mobileSidebarOpen && btf.isHidden(document.getElementById('toggle-menu'))) {
|
||||
sidebarFn.close()
|
||||
}
|
||||
})
|
||||
window.addEventListener('resize', resizeHandler, { passive: true })
|
||||
|
||||
const menuMask = document.getElementById('menu-mask')
|
||||
menuMask && menuMask.addEventListener('click', () => { sidebarFn.close() })
|
||||
@@ -947,18 +951,24 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
|
||||
const forPostFn = () => {
|
||||
addHighlightTool()
|
||||
addPhotoFigcaption()
|
||||
addJustifiedGallery(document.querySelectorAll('#article-container .gallery-container'))
|
||||
runLightbox()
|
||||
scrollFnToDo()
|
||||
addTableWrap()
|
||||
clickFnOfTagHide()
|
||||
tabsFn()
|
||||
const $article = document.getElementById('article-container')
|
||||
if (!$article) return
|
||||
|
||||
addHighlightTool($article)
|
||||
addPhotoFigcaption($article)
|
||||
addJustifiedGallery($article.querySelectorAll('.gallery-container'))
|
||||
runLightbox($article)
|
||||
scrollFnToDo($article)
|
||||
addTableWrap($article)
|
||||
clickFnOfTagHide($article)
|
||||
tabsFn($article)
|
||||
}
|
||||
|
||||
const refreshFn = () => {
|
||||
initAdjust()
|
||||
goUpElement = document.getElementById('go-up')
|
||||
scrollPercentElement = goUpElement?.querySelector('.scroll-percent')
|
||||
|
||||
justifiedIndexPostUI()
|
||||
|
||||
if (GLOBAL_CONFIG_SITE.pageType === 'post') {
|
||||
|
||||
+471
-562
File diff suppressed because it is too large
Load Diff
+567
-567
File diff suppressed because it is too large
Load Diff
+24
-11
File diff suppressed because one or more lines are too long
+48
-21
@@ -45,29 +45,55 @@
|
||||
}
|
||||
},
|
||||
|
||||
overflowPaddingR: {
|
||||
add: () => {
|
||||
const paddingRight = window.innerWidth - document.body.clientWidth
|
||||
|
||||
if (paddingRight > 0) {
|
||||
document.body.style.paddingRight = `${paddingRight}px`
|
||||
document.body.style.overflow = 'hidden'
|
||||
const menuElement = document.querySelector('#page-header.nav-fixed #menus')
|
||||
if (menuElement) {
|
||||
menuElement.style.paddingRight = `${paddingRight}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
remove: () => {
|
||||
document.body.style.paddingRight = ''
|
||||
document.body.style.overflow = ''
|
||||
const menuElement = document.querySelector('#page-header.nav-fixed #menus')
|
||||
if (menuElement) {
|
||||
menuElement.style.paddingRight = ''
|
||||
}
|
||||
rafThrottle: fn => {
|
||||
let rafId = null
|
||||
return (...args) => {
|
||||
if (rafId) return
|
||||
rafId = requestAnimationFrame(() => {
|
||||
fn(...args)
|
||||
rafId = null
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
overflowPaddingR: (() => {
|
||||
let headerElement = null
|
||||
let menuElement = null
|
||||
|
||||
const getElements = () => {
|
||||
if (!headerElement) {
|
||||
headerElement = document.getElementById('page-header')
|
||||
}
|
||||
if (!menuElement) {
|
||||
menuElement = document.getElementById('menus')
|
||||
}
|
||||
return { headerElement, menuElement }
|
||||
}
|
||||
|
||||
return {
|
||||
add: () => {
|
||||
const paddingRight = window.innerWidth - document.body.clientWidth
|
||||
|
||||
if (paddingRight > 0) {
|
||||
document.body.style.paddingRight = `${paddingRight}px`
|
||||
document.body.style.overflow = 'hidden'
|
||||
const { headerElement: header, menuElement: menu } = getElements()
|
||||
if (header && menu && header.classList.contains('nav-fixed')) {
|
||||
menu.style.paddingRight = `${paddingRight}px`
|
||||
}
|
||||
}
|
||||
},
|
||||
remove: () => {
|
||||
document.body.style.paddingRight = ''
|
||||
document.body.style.overflow = ''
|
||||
const { headerElement: header, menuElement: menu } = getElements()
|
||||
if (header && menu && header.classList.contains('nav-fixed')) {
|
||||
menu.style.paddingRight = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
})(),
|
||||
|
||||
snackbarShow: (text, showAction = false, duration = 2000) => {
|
||||
const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar
|
||||
const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark
|
||||
@@ -133,7 +159,8 @@
|
||||
const animate = currentTime => {
|
||||
const timeElapsed = currentTime - startTime
|
||||
const progress = Math.min(timeElapsed / time, 1)
|
||||
window.scrollTo(0, currentPos + (pos - currentPos) * progress)
|
||||
const easedProgress = 1 - Math.pow(1 - progress, 4) // easeOutQuart
|
||||
window.scrollTo(0, currentPos + (pos - currentPos) * easedProgress)
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user