동적 슬라이더를 사용하여 각도 있는 내비게이션 표시줄을 만드는 방법 (이성적 유지)

우리는 모서리가 있는 개발자들이 즐겁다고 상상해야 한다


얼마 전에 나는 Angular와 함께 새로운 프로젝트를 하기 시작했다.
나는 즉시 Angular의 학습 곡선이 React보다 훨씬 가파르다는 것을 알아차렸다.만약 당신이 완전한 초보자라면, FE 경험이 없거나 거의 없다면, 이것은 더욱 정확할 것이다.

일하는 방식


예를 들어 React 구축을 시작하려면 CRA(React 응용 프로그램 만들기) npm 패키지를 사용하여 프로그램을 안내할 수 있다.그리고 프로그램을 열 수 있습니다.js 파일을 만들고 HTML (JSX), 자바스크립트, 심지어 CSS 코드를 작성하기 시작합니다. 예를 들어 StyledComponents와 같은 js의 모든 CSS 도구를 사용합니다.그래서 모든 문제는 하나의 파일에 놓여 있습니다!
당신은 구성 요소, 상태, 도구 등 몇 가지 기본 개념을 이해해야 합니다.여기에 아주 기본적인 FP 재료까지.거의 이렇다.
물론 응용 프로그램의 복잡성이 증가함에 따라 일은 왕왕 더욱 복잡해진다.그리고 더 많은 개념, 디자인 모델, 라이브러리와 도구를 배우고 최종적으로 파악해야 한다(예를 들어 React Router, 전역 상태 관리, Redux, R-Thunk, R-saga, 렌더링 최적화 기술 등).
그러나 이 모든 것은 선택할 수 있는 것이다.대부분의 추가 내용은 제3자 라이브러리 형식으로 제공된다.

- 모서리 있는 작업 방식


Angular는 사물을 새로운 수준으로 끌어올린다.한 페이지 응용 프로그램 세계의 'Hello World' 라는 유명한 업무 목록을 만들고 싶다면, Angular 프로그램 하나만 인도하고, 한 파일에서javascript 코드를 쓰기 시작할 수 없습니다.
우선, 당신은 특정한 각도의 추상과 새로운 디자인 모델, 예를 들어 구성 요소, 지령, 템플릿, OOP의 기초 지식, 의존 주입 등을 배워야 한다.
너는 내가 React에게 같은 말을 한 적이 있다고 말할 수 있다.이 두 가지 상황에서 어떤 것을 구축하기 전에 라이브러리에 특정한 기본 지식을 배워야 한다.이거 진짜야.하지만 내가 보기에 Angular는 React보다'기본 요소'를 더 많이 가지고 있다.
Angular 프로그램을 작성하기 위해 Typescript를 알아야 합니다.이것은 반드시 필요한 것은 아니지만, 그것은 공인된 업계 표준이다.
또한 HTML, CSS 및 TS 코드는 별도의 파일에서 분리됩니다.그것은 웹 응용 프로그램을 구축하는 고전적인 방식과 유사하며 명확한 관심사 분리를 가지고 있다.이것은 좋은 점이 있다. 그러나 나는 리액션이 이 문제를 어떻게 처리하는지 더 좋아한다고 생각한다.
일단 기본 지식을 습득하고 마침내 요령을 터득했다고 생각하기 시작하면 덩닝 크루그 곡선의 첫 번째 산을 통해'어리석은 산'의 정상에서 절망의 골짜기로 떨어진다.

- 일이 곧 복잡해질 거야


결국 Angular의 핵심은 React (공유기, 애니메이션, RxJS) 보다 더 많은 것을 깨달았다. 이것은 완전한 SPA 개발 도구 상자이다.이것이 바로 왜 사람들이 틀이라고 부르는가이다.React와 달리 React는 하나의 라이브러리에 불과합니다.
...
내 각도 학습 프로세스의 현재 점은 D-K 커브 아래쪽에 있을 수 있습니다.나는 내가 막 거대한 바위를 계몽의 산으로 굴리기 시작했다고 생각한다.밝은 면은 내가 천천히 정상에서 점점 가까워지고 있다는 것이다.

좋은 것 - 슬라이더 네비게이션 표시줄을 어떻게 세우는지...


...이 과정에서 이성을 유지하다.
지난주에 저는 현재 (한 회사의 고객을 위해) 일하고 있는 프로젝트에서'네비게이션 표시줄, 아래에 동적 슬라이더'구성 요소/기능을 실현했습니다.
그래서 이 블로그의 목적을 위해 이 구성 요소를 단독으로 다시 만들었습니다.가는 길에 나는 재미있는 문제에 부딪혔다.그 문제를 해결하려면 창조적인 사고가 필요하다.
다음은 전체 어셈블리의 모양입니다.

탐색 모음 구성 요소에는 4개의 탐색 항목이 있습니다.모든 항목을 누르면 사용자는 미리 정의된 노선으로 바뀝니다. ("/홈", "posts", "random", "speed")
그 주요 목적은 사용자에게 현재 활동의 노선을 표시하고 현재 활동의 내비게이션 표시줄 항목을 표시하는 것이다. (따라서 슬라이더이다.)
또 다른 요구 사항은 슬라이더가 한 항목에서 다른 항목으로 안정적으로 이행해야 한다는 것이다.
슬라이더는 추가 목록 요소로 구현되며 다음과 같은 기본 스타일이 있습니다.
  <!-- navbar.component.html -->

  <ul class="header-menu">
    <li #navElements *ngFor="let item of navItemsList">
      <a 
        routerLink="/{{item.route}}" 
        (click)="calcNewIndicatorDOMStyles()"
      >
        {{ item.name }}
      </a>
    </li>
    <li 
      class="slider" 
      [style.width.px]="activeItemWidth" 
      [style.left.px]="activeItemLeftMargin">
    </li>
  </ul>
  // navbar.component.css

  .slider {
    position: absolute;
    bottom: -5px;
    margin-left: 2.2em;
    border-bottom: 2px solid white;
    transition: 0.3s;
    width: 50px;
  }
달리기 앱을 찾을 수 있다here
또 다른 요구는 슬라이더의 넓이가 동적 변화를 필요로 하고 위의 내비게이션 항목의 넓이와 일치해야 한다는 것이다.
탐색 항목의 너비 변화는 두 가지 상황에서 발생할 수 있습니다.

  • 화면 크기를 조정합니다.사용자는 그의 설비를 돌릴 수 있다.

  • 텍스트 번역이 변경되었습니다.어셈블리 아래의 DE/EN 버튼을 사용하여 시뮬레이션합니다.
  • 다음 템플릿 파일 코드를 보면 슬라이더의 왼쪽 여백과 너비를 동적으로 설정하는 인라인 스타일을 사용할 수 있습니다.
      <!-- navbar.component.html -->
    
      <li 
        class="slider" 
        [style.width.px]="activeItemWidth"    <======
        [style.left.px]="activeItemLeftMargin">    <======
      </li>
    
    activeItemWidth 및 activeItemLeftMargin은 다음과 같이 계산됩니다.
      // navbar.component.ts
    
        calcNewIndicatorDOMStyles() {
          this.activeItemWidth = this.router.isActive(routes.name, 
          false)
            ? this.navItemDOMProps?.[0].width
            : this.router.isActive(routes.posts, false)
            ? this.navItemDOMProps?.[1].width
            : this.router.isActive(routes.random, false)
            ? this.navItemDOMProps?.[2].width
            : this.router.isActive(routes.speed, false)
            ? this.navItemDOMProps?.[3].width
            : 0;
    
          this.activeItemLeftMargin = 
          this.router.isActive(routes.name, false)
            ? 0
            : this.router.isActive(routes.posts, false)
            ? this.navItemDOMProps?.[0].width + 30
            : this.router.isActive(routes.random, false)
            ? this.navItemDOMProps?.[0].width + 
              this.navItemDOMProps?.[1].width + 60
            : this.router.isActive(routes.speed, false)
            ? this.navItemDOMProps?.[0].width + 
              this.navItemDOMProps?.[1].width + 
              this.navItemDOMProps?.[2].width + 90
            : 0;
        }
    
    이 메서드는 탐색 항목을 클릭할 때 사용자가 트리거합니다.그런 다음 슬라이더가 새 활성 항목에서 변환될 수 있도록 새 슬라이더의 위치(왼쪽 여백)와 너비를 다시 계산해야 합니다.
    따라서 가장 신선한 DOM 스타일을 가져오는 방법(템플릿에서 새 속성을 다시 렌더링하고 계산한 후)이 까다롭습니다.더 구체적으로 말하면, 캘린더의 너비와 왼쪽 거리를 계산하기 위해 최신 nav 요소인offsetWidth 값 (지난번 렌더링) 이 필요합니다.
    첫 번째 단계는 뷰 DOM에서 대상 목록 요소를 가져오는 것입니다.ViewChildren 장식기를 사용했습니다.
      // navbar.component.ts
    
        @ViewChildren('navElements') navElements: 
         QueryList<ElementRef>;
    
    이 메서드는 새 오프셋 네트워크 너비를 추출하는 데 사용됩니다.
      // navbar.component.ts
    
      private getNewNavItemDOMWidths(navElementsList: any) {
        this.navItemDOMProps = navElementsList.map(item => ({
          width: item.nativeElement.offsetWidth
        }));
      }
    
    마지막으로 나는 제목에서'이성'이라는 단어를 사용하는 이유를 얻었다.
    이것은 가장 이해하기 어려운 부분이다.
    최신 계산된 DOM 스타일 속성을 얻기 위해 사용할 수 있는 라이프 사이클 방법은 무엇입니까?
    가장 유력한 후보는 ngAfterViewInit()와 ngAfterViewChecked()이다.comp의 생명 주기 중, 모든 다른 방법은 너무 일찍 시작된다.
    그러나 놀랍게도 이 두 가지 방법 중 어느 하나에서든 getNew NavItem DOM Widths () 방법을 호출해도 소용이 없었다.이전 렌더링에서 이전 값을 가져오고 있습니다.
    따라서
      ngAfterViewInit() { 
        this.getNewNavItemDOMWidths(this.navElements.toArray());
        this.calcNewIndicatorDOMStyles();
      }
    
    또는 이것:
      ngAfterViewChecked() { 
        this.getNewNavItemDOMWidths(this.navElements.toArray());
        this.calcNewIndicatorDOMStyles();
      }
    
    그것 자체는 작용하지 않는다.
    예.
    현재 선택한 언어가 EN이라고 가정하면 네 개의 내비게이션 항목의 폭은 각각 10, 20, 30, 40이다(나는 여기서 무작위 수로 설명한다).
    그런 다음 언어를 DE로 변경하면 텍스트 길이가 다르기 때문에 실제 DOM 너비가 50, 60, 70, 80으로 변경됩니다.
    만약ngAfterViewInit () 와ngAfterViewChecked () 생명주기 방법에서 그것을 콘솔에 기록하려고 시도한다면, 나는 10, 20, 30, 40 (지난번에 렌더링한 값에서) 을 받을 것이다.
    내가 이 문제를 어떻게 해결했는지
    다음과 같은 질문을 했습니다.
    템플릿 보기를 다시 보여주고 새로운 DOM 스타일 속성을 계산한 후,ngAfterViewChecked 생명주기 방법을 다시 호출하시겠습니까?
    만약 없다면, 원인은 무엇입니까?나는 어떻게 해야만 그것의 운행을 강요할 수 있습니까?
    Angular는 새로운 DOM 스타일 속성을 계산하고 사용할 수 있을 때 기본적으로 이 메서드를 실행하지 않는다는 결론을 내렸습니다.새 스타일을 사용할 수 있을 때, 이 방법을 의식하거나 어쩔 수 없이 다시 실행해야 한다.
    그래서 나는 이렇게 해결한다.
      ngAfterViewChecked() { 
        this.getNewNavItemDOMWidths(this.navElements.toArray());
        this.calcNewIndicatorDOMStyles();
    
        setTimeout(() => {}, 0);
      }
    
    이 방법에서 setTimeout 브라우저 API를 호출하면 Angular가 만일을 대비해서 매번 그것을 다시 실행하도록 합니다.setTimeout의 리셋 fn은 보기에 영향을 미칠 수 있는 코드를 포함할 수 있기 때문입니다. 검사한 후에!
    너는 아마 이미 두 번째 곳을 알아차렸을 것이다.CalCnordis() 방법은 라이프스케일에서 이미 언급되어 있습니다.
    이 해결 방안의 흥미로운 점은 '창' 크기를 조정하는 상황도 포함한다는 데 있다.뷰포트 크기를 조정하면 이 라이프 사이클 방법이 트리거되고 새 DOM 스타일이 추출되어 슬라이더를 업데이트하는 데 사용됩니다.
    거의 이렇다.
    완전한 소스 코드를 찾을 수 있습니다 here

    - 이 여정의 끝


    끝까지 읽어줘서 고마워요.
    나는 네가 약간의 새로운 지식을 배웠으면 한다.또는 제가 제공한 코드는 미래 프로젝트에서 당신을 도울 것입니다.
    여기까지 말하자면, 나는 이 문장을 통독하는 전문가들에게 물어볼 문제가 하나 있다.
    너는 나의 실시가 어떻다고 생각하니?이것은 좋은 것입니까, 아니면 뚜렷한 반모드입니까?내가 더 잘할 수 있는 게 뭐가 있을까?고마워요 고마워요

    좋은 웹페이지 즐겨찾기