Vue 패러다임에서 벗어나도 괜찮아 (가끔)

11906 단어 vuejavascriptwebdev
일을 하는 Vue way™는 훌륭합니다.

파이프라인Data->Template->DOM은 매우 잘 작동합니다.
데이터와 템플릿을 지정하고 Vue가 실제 DOM에 함께 연결하는 힘든 작업을 하도록 합니다.

그러나 이 깔끔한 패러다임을 따르면 특정 기능을 구현하는 것이 힘든 싸움처럼 느껴지거나 심지어 불가능할 수도 있습니다.

Vue 루프에서 벗어나 일반 JavaScript의 문제를 회피하는 것이 적절한 때를 아는 것이 중요합니다.

"전역" DOM ​​동작



일반적으로 Vue 방식으로 해결할 수 없는 가장 큰 문제는 Vue의 구성 요소 기반 부모/자식 패러다임에 맞지 않는 일부 유형의 DOM 기능에 액세스해야 할 때입니다.

다음 시나리오를 상상해 보십시오. 핸들을 끌어 너비를 조정할 수 있는 패널을 구현하고 있습니다.

"순진한"방법은 Vuev-on 지시문을 사용하여 마우스/터치 이벤트를 수신하는 것입니다.

<div class="relative inline-block">
  <div :style="{ width: `${width}px` }" ref="panel"></div>
  <button
    class="handle"
    @mousedown="startDrag"
    @mousemove="drag"
    @mouseup="stopDrag"
    @touchstart.prevent="startDrag"
    @touchmove.prevent="drag"
    @touchend.prevent="stopDrag"
  />
</div>



export default {
  data() {
    return {
      width: 300,
      offset: 0,
      dragging: false,
    };
  },
  methods: {
    startDrag() {
      const { left, height } = this.$refs.panel.getBoundingClientRect();
      this.offset = left;
      this.height = height;
      this.dragging = true;
    },
    drag(e) {
      if (this.dragging) {
        if (e.touches) this.width = e.touches[0].clientX - this.offset;
        else this.width = e.clientX - this.offset;
      }
    },
    stopDrag() {
      this.dragging = false;
    },
  },
};


이 접근 방식을 사용하면 마우스를 너무 빨리 끌면 포인터가 핸들을 떠나고 핸들에 연결된 수신기가 트리거를 중지하기 때문에 순진하다고 말합니다.

original post으로 이동하여 대화형 구성 요소를 사용해 보십시오.

이 문제를 해결하려면 문서 자체에 mousemovemouseup 이벤트를 등록하여 포인터가 핸들을 벗어나더라도 리스너가 계속 트리거되도록 해야 합니다. 그리고 임의의 구성 요소에서 무작위로 문서 객체에 액세스하는 것은 Vue의 관심사가 아니므로 일반 JS에서 수행하기만 하면 됩니다.

<div class="relative inline-block">
  <div :style="{ width: `${width}px` }" ref="panel"></div>
  <button
    class="handle"
    @mousedown="startDrag(true)"
    @touchstart.prevent="startDrag(false)"
    @touchmove.prevent="drag"
  />
</div>



export default {
  data() {
    return {
      width: 300,
      offset: 0,
      dragging: false,
    };
  },
  methods: {
    startDrag(mouse) {
      const { left, height } = this.$refs.panel.getBoundingClientRect();
      this.offset = left;
      this.height = height;
      if (mouse) {
        document.addEventListener("mouseup", this.drag);
        document.addEventListener("mousemove", this.stopDrag);
      }
    },
    drag(e) {
      if (e.touches) this.width = e.touches[0].clientX - this.offset;
      else this.width = e.clientX - this.offset;
    },
    stopDrag() {
      document.removeEventListener("mouseup", this.drag);
      document.removeEventListener("mousemove", this.stopDrag);
    },
  },
};


위의 예는 사소해 보일 수 있습니다. 우리는 일부 이벤트 리스너를 직접 추가할 뿐입니다. 그러나 요점은 이처럼 명확하지 않은 상황에서도 DOM API를 직접 호출할 수 있을 때 Vue와 불필요하게 싸우고 있는지 자문해야 한다는 것입니다.

이벤트 리스너 뿐만 아니라



이 예제는 이벤트 리스너에 중점을 두었지만 Vue를 건너뛰어야 하는 다른(덜 일반적) 유형의 전역 DOM 기능이 있습니다.

알림 구성 요소를 만들어야 하는 경우 HTML이 항상 다른 콘텐츠 위에 유지되도록 body 태그 끝에 HTML을 추가해야 할 것입니다. 모달도 마찬가지입니다(Vue 3에서는 이 경우가 teleport을 사용하여 완화됨).

Canvas 또는 WebGL로 작업하려면 데이터와 렌더링을 직접 연결해야 합니다.

마지막으로 타사 라이브러리를 래핑하려면 많은 패키지가 렌더링을 제어해야 하기 때문에 수동으로 반응 데이터를 라이브러리의 관련 속성 및 함수 호출에 연결해야 합니다.

좋은 웹페이지 즐겨찾기