MutationObserver 및 ResizeObserver를 사용하여 Vue에서 변경되는 DOM 요소 측정

25781 단어 vuecsshtmljavascript
DOM 요소에 대한 창의 onresize 이벤트 리스너와 같은 것이 있습니다. ResizeObserver이라고 하며 동적 요소를 매우 쉽게 측정할 수 있습니다. 유일한 문제는 표준이 아니라는 것입니다. 😑 몇 년 동안 편집자의 초안 목록에 있었습니다. 거의 모든 브라우저가 지원합니다. Safari는 13.1부터 지원하기 시작했지만 Internet Explorer 및 Firefox Android는 여전히 지원하지 않습니다. 그래서 ... setInterval 이외의 변화하는 요소를 측정하는 다른 방법이 있습니까? MutationObserver 을 입력합니다.

다음은 아래에서 설명할 코드의 데모입니다.


<템플릿> 또는 HTML 부분



<template>
  <div class="resize-observer">
    <div class="box" ref="box">
      <h4>Resize Me</h4>
      <p>
        width: <span class="size">{{ width }}</span>
      </p>
      <p>
        height: <span class="size">{{ height }}</span>
      </p>
    </div>
  </div>
</template>


css 속성div을 부여하여 "box"클래스로 resize: both 요소의 크기를 조정할 것입니다. 그러면 렌더링된 상자의 오른쪽 하단 모서리에 크기를 조정할 수 있는 작은 삼각형이 생깁니다.

실제 HTML 요소와 변경되는 치수에 액세스해야 하므로 ref 를 사용할 것입니다. refs here 에 대해 자세히 알아볼 수 있습니다.

MutationObserver로 크기 조정을 위한 <script> 코드



<script>
  export default {
    data() {
      return {
        width: null,
        height: null,
        observer: null,
      }
    },

    mounted() {
      const box = this.$refs.box,
        boxSize = box.getBoundingClientRect()

      this.width = boxSize.width + 'px'
      this.height = boxSize.height + 'px'
      // initialize the observer on mount
      this.initObserver()
    },

우리는 width , heightobserver 를 우리 상태에 추가할 것입니다. 그런 다음 구성 요소가 마운트되면 너비와 높이를 설정합니다. 또한 this.initObserver 를 호출하여 관찰자를 초기화합니다.

    beforeDestroy() {
      if (this.observer) this.observer.disconnect()
    },

또한 파괴하기 전에 관찰자의 연결을 끊었는지 확인해야 합니다.

이제 이 튜토리얼의 주요 부분에 도달했습니다. initObserver 메서드에서 MutationObserver 의 인스턴스인 관찰자를 만들고 초기화합니다. 이 관찰자는 상자 요소의 돌연변이를 추적하고 돌연변이 유형이 속성일 때 다른 메소드onResize를 호출합니다(박스의 너비 및 높이 속성이 여기에 해당함). onResize는 크기 조정 핸들러입니다.

    methods: {
     initObserver() {
        const config = {
            attributes: true,
          },
          vm = this

        // create the observer
        const observer = new MutationObserver(function (mutations) {
          mutations.forEach(function (mutation) {
            // check if the mutation is attributes and
            // update the width and height data if it is.
            if (mutation.type === 'attributes') {
              // call resize handler on mutation
              vm.onResize()
            }
          })
        })

        // observe element's specified mutations
        observer.observe(this.$refs.box, config)
        // add the observer to data so we can disconnect it later
        this.observer = observer
      },

크기 조정 핸들러는 치수가 변경될 때 상태를 업데이트합니다. 선택적으로 다른 구성 요소가 수신할 수 있는 이벤트를 내보낼 수 있습니다. More info on emitting events with vue.

      // Resize handler
      onResize() {
        const box = this.$refs.box,
          vm = this
        let { width, height } = box.style

        this.width = width
        this.height = height
        // Optionally, emit event with dimensions
        this.$emit('resize', { width, height })
      },
    },
  }
</script>

ResizeObserver로 크기 조정을 위한 <script> 코드



다음은 ResizeObserver 로 수행하는 방법입니다. ResizeObserver 로 구현할 때 코드가 훨씬 적다는 것을 알 수 있습니다. <template><style> 부분은 동일하게 유지됩니다.

<script>
  export default {
    data() {
      return {
        width: null,
        height: null,
        observer: null,
      }
    },

    mounted() {
      // initialize the observer on mount
      this.initObserver()
    },

    // unobserve before destroy
    beforeDestroy() {
      if (this.observer) this.observer.unobserve(this.$refs.box)
    },

    methods: {
      onResize() {
        const box = this.$refs.box,
          width = this.$refs.box.offsetWidth + 'px',
          height = this.$refs.box.offsetHeight + 'px'

        this.width = width
        this.height = height

        this.$emit('resize', { width, height })
      },
      initObserver() {
        const observer = new ResizeObserver(this.onResize)
        observer.observe(this.$refs.box)
        this.observer = observer
      },
    },
  }
</script>

다음은 <template> , <script><style> 로 크기를 조정하기 위한 전체 코드입니다.

<template>
  <div class="resize-observer">
    <div class="box" ref="box">
      <h4>Resize Me</h4>
      <p>
        width: <span class="size">{{ width }}</span>
      </p>
      <p>
        height: <span class="size">{{ height }}</span>
      </p>
    </div>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        width: null,
        height: null,
        observer: null,
      }
    },

    mounted() {
      const box = this.$refs.box,
        boxSize = box.getBoundingClientRect()

      this.width = boxSize.width + 'px'
      this.height = boxSize.height + 'px'
      // initialize the observer on mount
      this.initObserver()
    },

    //disconnect the observer before destroy
    beforeDestroy() {
      if (this.observer) this.observer.disconnect()
    },

    methods: {
      // Resize handler
      onResize() {
        const box = this.$refs.box,
          vm = this
        let { width, height } = box.style

        this.width = width
        this.height = height
        // Optionally, emit event with dimensions
        this.$emit('resize', { width, height })
      },

      initObserver() {
        const config = {
            attributes: true,
          },
          vm = this

        // create the observer
        const observer = new MutationObserver(function (mutations) {
          mutations.forEach(function (mutation) {
            // check if the mutation is attributes and
            // update the width and height data if it is.
            if (mutation.type === 'attributes') {
              // call resize handler on mutation
              vm.onResize()
            }
          })
        })

        // observe element's specified mutations
        observer.observe(this.$refs.box, config)
        // add the observer to data so we can disconnect it later
        this.observer = observer
      },
    },
  }
</script>

<style lang="scss" scoped>
  .resize-observer {
    text-align: center;

    h4 {
      margin-top: 30px;
      text-align: center;
    }

    .box {
      box-sizing: border-box;
      width: 210px;
      height: 210px;
      border: 2px solid red;
      padding: 10px;
      margin: 0 auto;
      resize: both;
      overflow: auto;
    }
    .size {
      color: #2a9966;
      font-weight: 600;
    }
  }
</style>

좋은 웹페이지 즐겨찾기