From 78d715c2a6066ef2c902dc88357db2021d496101 Mon Sep 17 00:00:00 2001 From: chenxi-20 <2465950588@qq.com> Date: Mon, 13 Mar 2023 10:07:50 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(anchor):=20=E9=94=9A=E7=82=B9=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E5=A2=9E=E5=8A=A0=E5=9B=BA=E5=AE=9A=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=E7=A4=BA=E4=BE=8B=E6=96=87=E6=A1=A3?= =?UTF-8?q?bug=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/anchor/index.js | 69 +++++++++++++++++++++++++++------------------ src/anchor/vue.js | 8 +++--- 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/src/anchor/index.js b/src/anchor/index.js index 4cc453f..d2b50c3 100644 --- a/src/anchor/index.js +++ b/src/anchor/index.js @@ -13,11 +13,12 @@ import { addClass, removeClass } from '@opentiny/vue-renderless/common/deps/dom' -const setFixAnchor = ({ vm }) => { - const { anchorRef } = vm.$refs - if (anchorRef) { - anchorRef.style.position = 'fixed' - anchorRef.style.top = anchorRef.offsetTop +const setFixAnchor = () => { + const fixElList = document.querySelectorAll('.tiny-anchor__affix') + if (fixElList.length >= 1) { + fixElList.forEach(fixRef => { + !fixRef.style.top && (fixRef.style.top = fixRef.offsetTop) + }) } } @@ -44,25 +45,20 @@ const setScrollContainer = ({ state, api, cb = null }) => { } } -const updateSkidPosition = ({ vm, state, emit }) => { - const { currentLink } = state - const activeEl = document.querySelector(`a[href='${currentLink}']`) - const { skidRef, maskRef, anchorRef } = vm.$refs - - if (!activeEl || !anchorRef) { - return - } - emit('onChange', currentLink) - +const forEachUpdateNode = ({ skidRef, currentLink }) => { + const anchorRef = skidRef.parentNode.parentNode + const { top: anchorClientTop, left: anchorClientLeft } = anchorRef.getBoundingClientRect() + const activeEl = anchorRef.querySelector(`a[href='${currentLink}']`) + const maskRef = anchorRef.querySelector('.tiny-anchor-link-mask') const { offsetHeight, offsetWidth } = activeEl const { top: linkTitleClientTop, left: linkTitleClientLeft } = activeEl.getBoundingClientRect() - const { top: anchorClientTop, left: anchorClientLeft } = anchorRef.getBoundingClientRect() - const offsetTop = linkTitleClientTop - anchorClientTop const offsetLeft = linkTitleClientLeft - anchorClientLeft - addClass(skidRef, 'tiny-anchor-orbit-skid--active') - skidRef.style.top = `${offsetTop}px` - skidRef.style.height = `${offsetHeight}px` + if (skidRef) { + addClass(skidRef, 'tiny-anchor-orbit-skid--active') + skidRef.style.top = `${offsetTop}px` + skidRef.style.height = `${offsetHeight}px` + } if (maskRef) { maskRef.style.top = `${offsetTop}px` maskRef.style.height = `${offsetHeight}px` @@ -70,10 +66,27 @@ const updateSkidPosition = ({ vm, state, emit }) => { } } -const getCurrentAnchor = ({ vm, state, link, emit }) => { +const updateSkidPosition = ({ state, emit }) => { + const { currentLink } = state + const activeEl = document.querySelector(`a[href='${currentLink}']`) + const skidElList = document.querySelectorAll('.tiny-anchor-orbit-skid') + + if (!activeEl) { + return + } + emit('onChange', currentLink) + + if (skidElList && skidElList.length >= 1) { + skidElList.forEach(skidRef => { + forEachUpdateNode({ skidRef, currentLink }) + }) + } +} + +const getCurrentAnchor = ({ state, link, emit }) => { if (state.currentLink === link) { return } state.currentLink = link - updateSkidPosition({ vm, state, emit }) + updateSkidPosition({ state, emit }) } const addObserver = ({ props, state }) => { @@ -105,9 +118,9 @@ const setCurrentHash = (state) => { export const getContainer = ({ props }) => () => props.containerId ? document.querySelector(props.containerId) : document.body -export const mounted = ({ vm, state, api }) => () => { +export const mounted = ({ state, api }) => () => { setScrollContainer({ state, api }) - setFixAnchor({ vm }) + setFixAnchor() api.onItersectionObserver() setCurrentHash(state) } @@ -122,7 +135,7 @@ export const unmounted = ({ state }) => () => { intersectionObserver.disconnect() } -export const onItersectionObserver = ({ vm, state, props, emit }) => () => { +export const onItersectionObserver = ({ state, props, emit }) => () => { state.intersectionObserver = new IntersectionObserver((entries) => { entries.forEach(item => { @@ -133,7 +146,7 @@ export const onItersectionObserver = ({ vm, state, props, emit }) => () => { for (let item of Object.values(state.observerLinks)) { if (item.isIntersecting && item.intersectionRatio > 0) { const link = `#${item.target.id}` - getCurrentAnchor({ vm, state, link, emit }) + getCurrentAnchor({ state, link, emit }) break } } @@ -143,7 +156,7 @@ export const onItersectionObserver = ({ vm, state, props, emit }) => () => { } -export const linkClick = ({ state, vm, emit, props }) => (e, item) => { +export const linkClick = ({ state, emit, props }) => (e, item) => { const { link, title } = item const emitLink = { link, title } emit('linkClick', e, emitLink) @@ -151,7 +164,7 @@ export const linkClick = ({ state, vm, emit, props }) => (e, item) => { const isChangeHash = setCurrentHash(state) const { scrollContainer } = state state.currentLink = link - updateSkidPosition({ vm, state, emit }) + updateSkidPosition({ state, emit }) setMarkClass({ state, props }) if (scrollContainer !== document.body && !isChangeHash) { diff --git a/src/anchor/vue.js b/src/anchor/vue.js index 60a473f..f81c40f 100644 --- a/src/anchor/vue.js +++ b/src/anchor/vue.js @@ -14,7 +14,7 @@ import { mounted, updated, unmounted, getContainer, linkClick, onItersectionObse export const api = ['state', 'getContainer', 'linkClick', 'onItersectionObserver'] -export const renderless = (props, { onMounted, onUnmounted, onUpdated, reactive }, { vm, emit }) => { +export const renderless = (props, { onMounted, onUnmounted, onUpdated, reactive }, { emit }) => { const api = {} const state = reactive({ currentLink: '', @@ -26,12 +26,12 @@ export const renderless = (props, { onMounted, onUnmounted, onUpdated, reactive Object.assign(api, { state, - mounted: mounted({ vm, state, api }), + mounted: mounted({ state, api }), updated: updated({ state, api }), unmounted: unmounted({ state }), getContainer: getContainer({ props }), - linkClick: linkClick({ state, vm, emit, props }), - onItersectionObserver: onItersectionObserver({ vm, state, props, emit }) + linkClick: linkClick({ state, emit, props }), + onItersectionObserver: onItersectionObserver({ state, props, emit }) }) onMounted(api.mounted) From a14725675ab0f5350b1c0558e8d212f0e83a0eec Mon Sep 17 00:00:00 2001 From: chenxi-20 <2465950588@qq.com> Date: Mon, 13 Mar 2023 10:33:54 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat(anchor):=20=E4=BF=AE=E5=A4=8Daffix?= =?UTF-8?q?=E6=A3=80=E8=A7=86=E6=84=8F=E8=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/anchor/index.js | 69 ++++++++++++++++++--------------------------- src/anchor/vue.js | 8 +++--- 2 files changed, 32 insertions(+), 45 deletions(-) diff --git a/src/anchor/index.js b/src/anchor/index.js index d2b50c3..b1c711f 100644 --- a/src/anchor/index.js +++ b/src/anchor/index.js @@ -13,12 +13,11 @@ import { addClass, removeClass } from '@opentiny/vue-renderless/common/deps/dom' -const setFixAnchor = () => { - const fixElList = document.querySelectorAll('.tiny-anchor__affix') - if (fixElList.length >= 1) { - fixElList.forEach(fixRef => { - !fixRef.style.top && (fixRef.style.top = fixRef.offsetTop) - }) +const setFixAnchor = ({ vm }) => { + const { fixRef } = vm.$refs + if (fixRef) { + fixRef.style.position = 'fixed' + fixRef.style.top = fixRef.offsetTop } } @@ -45,20 +44,25 @@ const setScrollContainer = ({ state, api, cb = null }) => { } } -const forEachUpdateNode = ({ skidRef, currentLink }) => { - const anchorRef = skidRef.parentNode.parentNode - const { top: anchorClientTop, left: anchorClientLeft } = anchorRef.getBoundingClientRect() - const activeEl = anchorRef.querySelector(`a[href='${currentLink}']`) - const maskRef = anchorRef.querySelector('.tiny-anchor-link-mask') +const updateSkidPosition = ({ vm, state, emit }) => { + const { currentLink } = state + const activeEl = vm.$refs[currentLink] + const { skidRef, maskRef, anchorRef } = vm.$refs + + if (!activeEl || !anchorRef) { + return + } + emit('onChange', currentLink) + const { offsetHeight, offsetWidth } = activeEl const { top: linkTitleClientTop, left: linkTitleClientLeft } = activeEl.getBoundingClientRect() + const { top: anchorClientTop, left: anchorClientLeft } = anchorRef.getBoundingClientRect() + const offsetTop = linkTitleClientTop - anchorClientTop const offsetLeft = linkTitleClientLeft - anchorClientLeft - if (skidRef) { - addClass(skidRef, 'tiny-anchor-orbit-skid--active') - skidRef.style.top = `${offsetTop}px` - skidRef.style.height = `${offsetHeight}px` - } + addClass(skidRef, 'tiny-anchor-orbit-skid--active') + skidRef.style.top = `${offsetTop}px` + skidRef.style.height = `${offsetHeight}px` if (maskRef) { maskRef.style.top = `${offsetTop}px` maskRef.style.height = `${offsetHeight}px` @@ -66,27 +70,10 @@ const forEachUpdateNode = ({ skidRef, currentLink }) => { } } -const updateSkidPosition = ({ state, emit }) => { - const { currentLink } = state - const activeEl = document.querySelector(`a[href='${currentLink}']`) - const skidElList = document.querySelectorAll('.tiny-anchor-orbit-skid') - - if (!activeEl) { - return - } - emit('onChange', currentLink) - - if (skidElList && skidElList.length >= 1) { - skidElList.forEach(skidRef => { - forEachUpdateNode({ skidRef, currentLink }) - }) - } -} - -const getCurrentAnchor = ({ state, link, emit }) => { +const getCurrentAnchor = ({ vm, state, link, emit }) => { if (state.currentLink === link) { return } state.currentLink = link - updateSkidPosition({ state, emit }) + updateSkidPosition({ vm, state, emit }) } const addObserver = ({ props, state }) => { @@ -118,9 +105,9 @@ const setCurrentHash = (state) => { export const getContainer = ({ props }) => () => props.containerId ? document.querySelector(props.containerId) : document.body -export const mounted = ({ state, api }) => () => { +export const mounted = ({ vm, state, api }) => () => { setScrollContainer({ state, api }) - setFixAnchor() + setFixAnchor({ vm }) api.onItersectionObserver() setCurrentHash(state) } @@ -135,7 +122,7 @@ export const unmounted = ({ state }) => () => { intersectionObserver.disconnect() } -export const onItersectionObserver = ({ state, props, emit }) => () => { +export const onItersectionObserver = ({ vm, state, props, emit }) => () => { state.intersectionObserver = new IntersectionObserver((entries) => { entries.forEach(item => { @@ -146,7 +133,7 @@ export const onItersectionObserver = ({ state, props, emit }) => () => { for (let item of Object.values(state.observerLinks)) { if (item.isIntersecting && item.intersectionRatio > 0) { const link = `#${item.target.id}` - getCurrentAnchor({ state, link, emit }) + getCurrentAnchor({ vm, state, link, emit }) break } } @@ -156,7 +143,7 @@ export const onItersectionObserver = ({ state, props, emit }) => () => { } -export const linkClick = ({ state, emit, props }) => (e, item) => { +export const linkClick = ({ state, vm, emit, props }) => (e, item) => { const { link, title } = item const emitLink = { link, title } emit('linkClick', e, emitLink) @@ -164,7 +151,7 @@ export const linkClick = ({ state, emit, props }) => (e, item) => { const isChangeHash = setCurrentHash(state) const { scrollContainer } = state state.currentLink = link - updateSkidPosition({ state, emit }) + updateSkidPosition({ vm, state, emit }) setMarkClass({ state, props }) if (scrollContainer !== document.body && !isChangeHash) { diff --git a/src/anchor/vue.js b/src/anchor/vue.js index f81c40f..60a473f 100644 --- a/src/anchor/vue.js +++ b/src/anchor/vue.js @@ -14,7 +14,7 @@ import { mounted, updated, unmounted, getContainer, linkClick, onItersectionObse export const api = ['state', 'getContainer', 'linkClick', 'onItersectionObserver'] -export const renderless = (props, { onMounted, onUnmounted, onUpdated, reactive }, { emit }) => { +export const renderless = (props, { onMounted, onUnmounted, onUpdated, reactive }, { vm, emit }) => { const api = {} const state = reactive({ currentLink: '', @@ -26,12 +26,12 @@ export const renderless = (props, { onMounted, onUnmounted, onUpdated, reactive Object.assign(api, { state, - mounted: mounted({ state, api }), + mounted: mounted({ vm, state, api }), updated: updated({ state, api }), unmounted: unmounted({ state }), getContainer: getContainer({ props }), - linkClick: linkClick({ state, emit, props }), - onItersectionObserver: onItersectionObserver({ state, props, emit }) + linkClick: linkClick({ state, vm, emit, props }), + onItersectionObserver: onItersectionObserver({ vm, state, props, emit }) }) onMounted(api.mounted)