refactor(anchor): target => listen-to, fix scroll listener is not unregistered

This commit is contained in:
07akioni 2020-10-23 15:42:11 +08:00
parent f0ac1d30c1
commit 52f58d9dac
6 changed files with 82 additions and 40 deletions

View File

@ -15,7 +15,7 @@ scrollto
|affix|`boolean`|`false`|If it works like a affix. If set to `true`, it will recieve props from [affix](n-affix#Props)|
|bound|`number`|`12`||
|ignore-gap|`boolean`|`false`| If set to `true`, it will be displayed on the exact href |
|target|`() => HTMLElement`|A function that returns the nearest scrollable ascendant element|The element that anchor listens to scroll event. (If you want affix & anchor to listen to different target, manually warp anchor in affix instead.)|
|listen-to|`string \| HTMLElement`|`undefined`|The scrolling element to listen scrolling. If not set it will listen to the nearest scrollable ascendant element.|
|theme|`'light' \| 'dark' \| string`|`undefined`||
## Methods

View File

@ -14,7 +14,7 @@ scrollto
|affix|`boolean`|`false`|Anchor 是否像 Affix 一样展示,如果设定为 `true`,它还会接受 [Affix](n-affix#Props) 的 Props|
|bound|`number`|`12`||
|ignore-gap|`boolean`|`false`| 如果设定为 `true`, 导航将显示在准确的href区域 |
|target|`() => HTMLElement`|一个返回最邻近可滚动祖先元素的函数|需要监听滚动的元素(如果你希望 Anchor 和 Affix 分别监听不同的元素,可以手动的组合 Anchor 和 Affix|
|listen-to|`string \| HTMLElement`|`undefined`|需要监听滚动的元素,如果未设定则会监听最近的可滚动祖先元素|
|theme|`'light' \| 'dark' \| string`|`undefined`||
## Methods

View File

@ -116,11 +116,11 @@ export default {
},
x: {
type: Number,
default: null
default: undefined
},
y: {
type: Number,
default: null
default: undefined
}
},
watch: {

View File

@ -2,6 +2,8 @@
<n-base-anchor
v-if="!affix"
ref="anchor"
:theme="theme"
:listen-to="listenTo"
:bound="bound"
:target="target"
:ignore-gap="ignoreGap"
@ -10,18 +12,21 @@
</n-base-anchor>
<n-affix
v-else
:target="target"
:listen-to="listenTo"
:top="top"
:bottom="bottom"
:offset-top="offsetTop"
:offset-bottom="offsetBottom"
:position="position"
:target="target"
>
<n-base-anchor
ref="anchor"
:theme="theme"
:bound="bound"
:target="target"
:listen-to="listenTo"
:ignore-gap="ignoreGap"
:target="target"
>
<slot />
</n-base-anchor>
@ -31,10 +36,7 @@
<script>
import NBaseAnchor from './BaseAnchor.vue'
import NAffix from '../../affix'
import usecssr from '../../_mixins/usecssr'
import themeable from '../../_mixins/themeable'
import withapp from '../../_mixins/withapp'
import styles from './styles'
import { themeable } from '../../_mixins'
export default {
name: 'Anchor',
@ -43,18 +45,12 @@ export default {
NAffix
},
mixins: [
withapp,
themeable,
usecssr(styles)
themeable
],
props: {
top: {
type: Number,
default: null
},
target: {
type: Function,
default: null
default: undefined
},
affix: {
type: Boolean,
@ -83,6 +79,17 @@ export default {
ignoreGap: {
type: Boolean,
default: false
},
listenTo: {
type: [String, Object],
default: undefined
},
// deprecated
target: {
validator () {
return true
},
default: undefined
}
},
methods: {

View File

@ -26,10 +26,15 @@
<script>
import { nextTick, ref, markRaw } from 'vue'
import getScrollParent from '../../_utils/dom/getScrollParent'
import withapp from '../../_mixins/withapp'
import themeable from '../../_mixins/themeable'
import {
configurable,
themeable,
usecssr
} from '../../_mixins'
import { onFontReady } from '../../_utils/composition/index'
import { warn } from '../../_utils/naive/warn'
import getTarget from '../../_utils/dom/get-target'
import styles from './styles'
function getOffset (el, container) {
const {
@ -46,10 +51,12 @@ function getOffset (el, container) {
}
export default {
name: 'NBaseAnchor',
name: 'BaseAnchor',
cssrName: 'Anchor',
mixins: [
withapp,
themeable
configurable,
themeable,
usecssr(styles)
],
provide () {
return {
@ -57,9 +64,9 @@ export default {
}
},
props: {
target: {
type: Function,
default: null
listenTo: {
type: [String, Object],
default: undefined
},
bound: {
type: Number,
@ -68,6 +75,14 @@ export default {
ignoreGap: {
type: Boolean,
default: false
},
// deprecated
target: {
validator () {
if (__DEV__) warn('anchor', '`target` is deprecated, please use`listen-to` instead.')
return true
},
default: undefined
}
},
setup () {
@ -80,7 +95,13 @@ export default {
collectedLinkHrefs: markRaw([]),
titleEls: markRaw([]),
activeHref: ref(null),
container: ref(null)
scrollElement: ref(null)
}
},
beforeUnmount () {
const { scrollElement } = this
if (scrollElement) {
scrollElement.removeEventListener('scroll', this.handleScroll)
}
},
watch: {
@ -162,8 +183,11 @@ export default {
const linkEl = document.getElementById(idMatchResult[1])
if (linkEl) {
this.activeHref = href
const top = getOffset(linkEl, this.container).top + (this.container.scrollTop || 0)
this.container.scrollTo({
const {
scrollElement
} = this
const top = getOffset(linkEl, scrollElement).top + (scrollElement.scrollTop || 0)
scrollElement.scrollTo({
top: top
})
if (!transition) {
@ -183,7 +207,7 @@ export default {
const {
top,
height
} = getOffset(linkEl, this.container)
} = getOffset(linkEl, this.scrollElement)
links.push({
top,
height,
@ -229,17 +253,26 @@ export default {
}
},
init () {
this.container = getScrollParent(this.$el)
if (this.target) {
const target = this.target()
if (target instanceof Element) {
this.container = target
const {
target: getScrollTarget,
listenTo
} = this
let scrollElement
if (getScrollTarget) {
// deprecated
scrollElement = getScrollTarget()
} else if (listenTo) {
scrollElement = getTarget(listenTo)
} else {
scrollElement = getScrollParent(this.$el)
}
if (scrollElement) {
this.scrollElement = scrollElement
} else if (__DEV__) {
warn('anchor', 'target is not a element')
warn('anchor', 'Target to be listened to is not valid.')
}
}
if (this.container) {
this.container.addEventListener('scroll', this.handleScroll)
if (scrollElement) {
scrollElement.addEventListener('scroll', this.handleScroll)
}
}
}

View File

@ -14,6 +14,8 @@ placeable 进行了大调整
- `target` => `listen-to`
- [x] alert
- [x] anchor
- deprecate
- `target` => `listen-to`
- [x] auto-complete
- break
- `v-model` => `v-model:value`