schpnc

Vue IntersectionObserver

Sep 17th, 2021 (edited)
711
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <script lang="ts">
  2. import Vue, { CreateElement, VNode, RenderContext } from "vue"
  3. import {DefaultProps} from "vue/types/options";
  4.  
  5. export default Vue.extend({
  6.   name: "Visible",
  7.   props: {
  8.     threshold: {
  9.       type: [Array, Number],
  10.       default: 0
  11.     },
  12.     rootMargin: {
  13.       type: String,
  14.       default: '0px 0px 0px 0px'
  15.     }
  16.   },
  17.   data() {
  18.     return {
  19.       visible: false,
  20.       observer: null as IntersectionObserver|null,
  21.       rootElement: null,
  22.     }
  23.   },
  24.   mounted() {
  25.     this.updateRootElement()
  26.     this.initObserver()
  27.   },
  28.   updated() {
  29.     this.updateRootElement()
  30.   },
  31.   beforeDestroy() {
  32.     this.destroyObserver()
  33.   },
  34.   methods: {
  35.     destroyObserver() {
  36.       if (this.observer) {
  37.         this.observer.disconnect()
  38.         this.observer = null
  39.       }
  40.     },
  41.     initObserver() {
  42.       this.destroyObserver()
  43.  
  44.       if (!this.$isServer) {
  45.         this.observer = new IntersectionObserver(async (entries: IntersectionObserverEntry[], observer: IntersectionObserver) => {
  46.           console.log('hit', arguments);
  47.           this.visible = entries.some(entry => entry.intersectionRatio > 0)
  48.         }, {threshold: this.threshold, rootMargin: this.rootMargin})
  49.  
  50.         this.observe()
  51.       }
  52.     },
  53.     isElement(element) {
  54.       return typeof Element !== 'undefined' && element instanceof Element
  55.     },
  56.     updateRootElement() {
  57.       this.rootElement = this.$el
  58.     },
  59.     observe(element = this.observing) {
  60.       if (this.isElement(element)) this.observer.observe(element)
  61.     },
  62.     unobserve(element) {
  63.       if (this.isElement(element)) this.observer.unobserve(element)
  64.     },
  65.   },
  66.   computed: {
  67.     observing() {
  68.       return this.isElement(this.rootElement) ? this.rootElement : null
  69.     },
  70.   },
  71.   watch: {
  72.     observing(val, oldVal) {
  73.       if (val !== oldVal) {
  74.         this.unobserve(oldVal)
  75.         if (val) {
  76.           this.observe(val)
  77.         }
  78.       }
  79.     },
  80.     threshold(val, oldVal) {
  81.       if (val !== oldVal) this.initObserver()
  82.     },
  83.     margin(val, oldVal) {
  84.       if (val !== oldVal) this.initObserver()
  85.     },
  86.   },
  87.   render(createElement: CreateElement, context: RenderContext<DefaultProps>): VNode {
  88.     const slotContent = this.$scopedSlots.default && this.$scopedSlots.default({visible: this.visible})
  89.     const slotRoot = Array.isArray(slotContent) ? slotContent.pop() : null
  90.  
  91.     return slotRoot || createElement('span', {class: 'test-visibility'})
  92.   }
  93. })
  94. </script>
  95.  
  96. <style scoped>
  97. .test-visibility {
  98.   display: block;
  99.   height: 0;
  100.   width: 0;
  101. }
  102. </style>
  103.  
  104.  
  105. // usage:
  106. <visible v-slot:default="slot">
  107.   <LazyCommonMainSlider :items="mainSlides"  v-if="slot.visible"/>
  108. </visible>
  109.  
RAW Paste Data