|
@@ -0,0 +1,147 @@
|
|
|
+<template>
|
|
|
+ <div ref="placeholderNode" :style="{ ...placeholderNodeStyle }">
|
|
|
+ <div ref="fixedNode" :style="{ ...fixedNodeStyle }">
|
|
|
+ <slot />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { TRIGGER_EVENTS, getDefaultTarget } from './utils'
|
|
|
+import addDOMEventListener from 'add-dom-event-listener'
|
|
|
+
|
|
|
+import _ from 'lodash'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'Affix',
|
|
|
+ props: {
|
|
|
+ /**
|
|
|
+ * 距离窗口顶部达到指定偏移量后触发
|
|
|
+ */
|
|
|
+ offsetTop: {
|
|
|
+ type: Number,
|
|
|
+ required: false,
|
|
|
+ default: () => null
|
|
|
+ },
|
|
|
+ offset: {
|
|
|
+ type: Number,
|
|
|
+ required: false,
|
|
|
+ default: () => null
|
|
|
+ },
|
|
|
+ /** 距离窗口底部达到指定偏移量后触发 */
|
|
|
+ offsetBottom: {
|
|
|
+ type: Number,
|
|
|
+ required: false,
|
|
|
+ default: () => null
|
|
|
+ },
|
|
|
+ /** 固定状态改变时触发的回调函数 */
|
|
|
+ // onChange?: (_Affixed?: boolean) => void;
|
|
|
+ /** 设置 _Affix 需要监听其滚动事件的元素,值为一个返回对应 DOM 元素的函数 */
|
|
|
+ target: {
|
|
|
+ type: Function,
|
|
|
+ required: false,
|
|
|
+ default: () => getDefaultTarget()
|
|
|
+ },
|
|
|
+ prefixCls: {
|
|
|
+ type: String,
|
|
|
+ required: false,
|
|
|
+ default: () => null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ this.lazyUpdatePosition = _.throttle(this.lazyUpdatePosition, 300)
|
|
|
+ return {
|
|
|
+ placeholderNodeStyle: '',
|
|
|
+ fixedNodeStyle: '',
|
|
|
+ entity: {
|
|
|
+ target: null,
|
|
|
+ affixList: [],
|
|
|
+ eventHandlers: {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // console.log(this.target().Target)
|
|
|
+ this.init()
|
|
|
+ },
|
|
|
+ // 销毁事件
|
|
|
+ destroyed() {
|
|
|
+ this.unInit()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ init() {
|
|
|
+ const { entity } = this
|
|
|
+ const targetNode = this.target()
|
|
|
+ TRIGGER_EVENTS.forEach((eventName) => {
|
|
|
+ // targetNode.addEventListener(eventName, () => {
|
|
|
+ // this.lazyUpdatePosition()
|
|
|
+ // })
|
|
|
+ entity.eventHandlers[eventName] = addDOMEventListener(
|
|
|
+ targetNode,
|
|
|
+ eventName,
|
|
|
+ () => {
|
|
|
+ this.lazyUpdatePosition()
|
|
|
+ }
|
|
|
+ )
|
|
|
+ })
|
|
|
+ },
|
|
|
+ // @ts-ignore TS6133
|
|
|
+ prepareMeasure() {
|
|
|
+ this.fixedNodeStyle = null
|
|
|
+ this.placeholderNodeStyle = null
|
|
|
+ this.$forceUpdate()
|
|
|
+ },
|
|
|
+ getOffsetTop() {
|
|
|
+ const { offset, offsetBottom } = this
|
|
|
+ let { offsetTop } = this
|
|
|
+ if (typeof offsetTop === 'undefined') {
|
|
|
+ offsetTop = offset
|
|
|
+ }
|
|
|
+
|
|
|
+ if (offsetBottom === undefined && offsetTop === undefined) {
|
|
|
+ offsetTop = 0
|
|
|
+ }
|
|
|
+ return offsetTop
|
|
|
+ },
|
|
|
+ lazyUpdatePosition() {
|
|
|
+ const targetNode = this.target()
|
|
|
+ const offsetTop = this.getOffsetTop()
|
|
|
+ // console.log(102, this.$refs, targetNode.scrollTop)
|
|
|
+ if (targetNode.scrollTop < offsetTop) {
|
|
|
+ this.prepareMeasure()
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const placeholderReact = this.$refs.placeholderNode
|
|
|
+ this.fixedNodeStyle = {
|
|
|
+ position: 'fixed',
|
|
|
+ top: `${offsetTop}px`,
|
|
|
+ zIndex: 999,
|
|
|
+ width: placeholderReact.offsetWidth + 'px',
|
|
|
+ height: placeholderReact.offsetHeight + 'px'
|
|
|
+ }
|
|
|
+ this.placeholderNodeStyle = {
|
|
|
+ width: placeholderReact.offsetWidth + 'px',
|
|
|
+ height: placeholderReact.offsetHeight + 'px'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ unInit() {
|
|
|
+ const { entity } = this
|
|
|
+ // const targetNode = this.target()
|
|
|
+ // console.log(123, targetNode)
|
|
|
+ TRIGGER_EVENTS.forEach((eventName) => {
|
|
|
+ // targetNode.removeEventListener(eventName, () => {
|
|
|
+ // this.lazyUpdatePosition()
|
|
|
+ // })
|
|
|
+ // entity.eventHandlers[eventName]
|
|
|
+ const handler = entity.eventHandlers[eventName]
|
|
|
+ if (handler && handler.remove) {
|
|
|
+ handler.remove()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less"></style>
|