Sticker.vue 1.4 KB
Newer Older
D
DCloud_LXH 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
<template>
	<component
		:is="tag || 'div'"
		class="sticker"
		:class="needFloat ? ['stick-float'] : undefined"
		:style="needFloat ? { bottom: `${stickBottom}px` } : undefined"
	>
		<slot></slot>
	</component>
</template>

<script>
	import { findContainerInVm } from '../util';
	export default {
		props: ['stick', 'tag'],
		data() {
			return {
				needFloat: false,
				stickBottom: 0,
			};
		},
		watch: {
			stick() {
				this.unStick();
				this.stickHandle();
			},
		},
		mounted() {
			this.stickHandle();
		},
		beforeDestroy() {
			this.unStick();
		},
		methods: {
			stickHandle() {
				if (!this.stick) return;
				const stickElement = findContainerInVm(this.stick, this);
				if (!stickElement) return;
				this._stickerScroll = () => {
					const rect = this.$el.getBoundingClientRect();
					const scrollTop = document.body.scrollTop + document.documentElement.scrollTop;
					this.needFloat =
						document.body.offsetHeight - scrollTop - rect.height < stickElement.offsetHeight;
					this.stickBottom = stickElement.offsetHeight;
				};
				this._stickerScroll();
				window.addEventListener('scroll', this._stickerScroll);
			},
			unStick() {
				this.needFloat = false;
				this.stickBottom = 0;
				window.removeEventListener('scroll', this._stickerScroll);
			},
		},
	};
</script>

<style lang="stylus">
	.sticker
	  position fixed
	  &.stick-float
	    top auto
	    position absolute
</style>