많은 수의 DOM 요소를 변환/이동하는 가장 성능적인 방법
얼마 전 AngularJS(Angular Material)를 위한 트리 테이블 구조를 만들었습니다.
제 목표는 대화면(1280 이상)에서만 작동하도록 만드는 것이었지만 지금은 데이터 제한 없이 업데이트하여 더 작은 장치(대부분 태블릿)에서도 작동하도록 만들고 싶습니다.성능 때문에 HTML을 최대한 단순하게 유지하고 싶습니다(트리 테이블은 1000개 이상의 행을 가질 수 있으므로 단일 행에 대해 더 복잡한 HTML을 생성하면 테이블 행을 추가하고 렌더링하는 데 필요한 시간이 길어집니다(행은 동적이므로 초기 렌더링에만 해당하는 것이 아님).
이름이 포함된 첫 번째 셀로 "고정"된 부분을 유지하고 모든 메트릭이 포함된 두 번째 부분을 스크롤하여 동기적으로 스크롤하겠다는 아이디어를 생각해 냈습니다.
단일 행의 현재 HTML:
<div class="tb-header layout-row">
<div class="tb-title"><span>Name</span></div>
<div class="tb-metrics">
<div class="layout-row">
<div class="tb-cell flex-10">812</div>
<div class="tb-cell flex-7">621</div>
<div class="tb-cell flex-4">76.5</div>
<div class="tb-cell flex-7">289</div>
<div class="tb-cell flex-4">46.5</div>
<div class="tb-cell flex-7">308</div>
<div class="tb-cell flex-4">49.6</div>
<div class="tb-cell flex-7">390</div>
<div class="tb-cell flex-4">48.0</div>
<div class="tb-cell flex-7">190</div>
<div class="tb-cell flex-4">23.4</div>
<div class="tb-cell flex-7">0</div>
<div class="tb-cell flex-4">0.0</div>
<div class="tb-cell flex-8">6.4</div>
<div class="tb-cell flex-8">0.0</div>
<div class="tb-cell flex-8"></div>
</div>
</div>
내 생각은 사용하는 것이었습니다.touchmove
으로 바인딩)및트를 래핑딩)k 확인touchmove
메트릭 섹션에서 시작하여 메트릭을 이동할 값을 계산합니다.그리고 그 부분은 잘 작동합니다. 때 됩니다..tb-metrics >
.
저의 첫 번째 시도는 jQuery:
function moveMetrics( offset ) {
var ofx = offset < 0 ? (offset < -getMetricsScrollWidth() ? -getMetricsScrollWidth() : offset) : 0;
$('.tb-metrics').children().css('transform', 'translateX(' + ofx + 'px)');
/*...*/
}
불행히도 테이블에 행이 더 포함되어 있는 경우 이 솔루션은 매우 느립니다(행이 동적이기 때문에 캐시할 수 없음).
두 번째 시도에서, A는 내가 할 수 있는 한 많은 DOM 조작을 피하려고 했습니다.그것을 이루기 위해 나는 추가하기로 결정했습니다.<script>
dome하는 CSS되는 태그 to dome에 하는 tag to .metrics > .layout-row
.
해결책:
function moveMetrics( offset ) {
var ofx = offset < 0 ? (offset < -getMetricsScrollWidth() ? -getMetricsScrollWidth() : offset) : 0
, style = $( '#tbMetricsVirtualScroll' )
;
if ( !style.length ) {
body.append( '<style id="tbMetricsVirtualScroll">.tb-metrics > * {transform: translateX(' + ofx + 'px)}</style>' );
style = $( '#tbMetricsVirtualScroll' );
} else {
style.text( '.tb-metrics > * {transform: translateX(' + ofx + 'px)}' );
}
/*...*/
}
그러나 테이블에 행이 많이 포함되어 있을 때는 그다지 빠르지 않은 것 같습니다.따라서 DOM 조작이 아니라 렌더링/도장 뷰가 병목 현상인 것 같습니다.
" 수준 수 새 가 "" 에()의될 수 )ng-repeat
정말 정말 어려운 일입니다.
그 상황에서 가상 스크롤을 사용하지 않고 어떻게 하면 성능을 향상시킬 수 있을지에 대한 아이디어를 주시면 감사하겠습니다.
편집:
Chrome 타임라인 스크린샷을 보면 스크롤 시간은 대부분 렌더링에 의해 소모됨을 알 수 있습니다(DOM 구조가 복잡하기 때문인 것 같습니다).
편집 2:
절대적으로 매끄러운 스크롤을 달성했다고 말하지는 않겠지만, 몇 가지 성능 향상을 위한 몇 가지 사항을 발견했습니다(그 중 일부는 명확하지 않았고 작은 변화에도 불구하고 예상했던 것보다 결과가 좋습니다).
- :
.tb-header > .tb-metrics > .tb-cell
다보다 ..tb-specific-cell
(더 복잡한 셀렉터를 파싱하는 데 시간이 더 걸리는 것 같습니까?) - 변환된 요소에서 불투명도 및 상자 그림자 제거
- (CSS 합니다)).
will-change
및/translateZ(0)
)
저도 예전에 테이블이 너무 커서 비슷한 문제를 겪은 적이 있습니다.따라서 UX 측면을 방정식 밖에 두는 것은 목표를 달성하기 위해 다음과 같은 것이 될 수 있습니다.첫 번째 테이블을 고정하고 나머지 테이블을 모두 옮기는 대신 반대로 시도할 수도 있습니다.하여 가로 하도록 한 후 아카,합니다를 하여 이동합니다.translateY
세로로 스크롤할 때 첫 번째 열 테이블 셀.
제가 설명하는 방식으로 첫 번째 테이블 셀의 최대 너비를 검색하고(또는 더 나은 고정 너비 설정), 각 셀을 왼쪽에 절대적으로 배치할 수 있습니다. 그러나 상대 컨테이너는 오버플로된 테이블 외부에 있어야 하며, 각 행의 두 번째 테이블 셀에 패딩-왼쪽을 설정하고, 첫 번째 테이블 셀과 동일하게 설정한 다음 스크롤할 때 주의해야 합니다.수직으로, 음을 더합니다.translateY
'.값에 수 그러면 선택기가 'layout-row.table-cell:first-child'에 쉽게 액세스할 수 있어야 합니다.
.css()
을 써 보다.attr('style', value)
대신. 이 있어서 수 한 것을 해야 할 것 .또한 동적 컨텐츠가 있어 캐시할 수 없다고 읽었지만, DOM을 조작할 때마다 한 번씩 캐싱을 고려해야 할 것 같습니다.캐시된 선택된 요소는 모든 스크롤/터치 이동 이벤트에서 셀렉터를 계산하는 것보다 여전히 더 좋습니다.
마지막으로 스크롤 프레임마다 스크롤이 발생하는 것이 아니라 10프레임마다 한 번씩 발생하도록 일종의 디바운싱 기술을 추가할 수도 있습니다. 이 기술은 여전히 눈에 보이지 않거나, 어떤 경우에도 이 모든 재도장 이벤트로 브라우저를 병으로 묶는 것보다 더 나을 수 있습니다.
저는 당신이 게으른 로딩을 사용하는 것을 제안합니다.레이지 로딩에는 4가지 옵션이 있습니다.레이지 로드 설계 패턴을 구현하는 일반적인 방법은 레이지 초기화, 가상 프록시, 고스트 및 값 보유자의 네 가지입니다.각각의 장점과 단점(링크)이 있습니다.
행운을 빌어요
그래서 저도 전문가는 아니지만 제가 언급할 가치가 있다고 생각하는 아이디어가 있습니다.제가 제대로 이해하고 있다면 문제는 이 프로젝트가 점점 더 많은 HTML 요소를 필요로 하기 때문에 성능이 지속적으로 저하된다는 것입니다.
여기에 당신에게 도움이 될 것 같은 3가지 js 개념이 있습니다.
*html 요소를 동적으로 만듭니다.
let div = document.createElement('div');
*요소에 사용할 속성을 동적으로 생성하고 해당 속성을 동적으로 할당할 수 있음
function attributeSetter(atr){
div.setAttribute('class', atr)
}
이렇게 하면 필요한 곳에서 함수를 호출하고 원하는 클래스 이름을 동적으로 지정할 수 있습니다.또한 디브 요소를 원하는 횟수만큼 사용할 수 있습니다.
최종 개념이와 같이 CSS에 이미 사전 정의된 클래스를 가정하여 동적으로 미리 만들어진 클래스를 추가할 수도 있습니다.
div.classList.add("my-class-name")
유용하게 사용될 수 있는 또 하나의 개념은 구조화입니다.
let myClasses = ['flex-10', 'flex-7', 'flex-4', 'flex-9'] //etc
let [flex10, flex7, flex4, flex9] = myClasses;
이렇게 하면 모든 문자열을 쉽게 반복할 수 있는 변수로 변환하여 다음과 같이 속성 Setter 함수에 동적으로 추가할 수 있습니다.
attributeSetter(flex10)
필요한 곳이면 어디든.그게 도움이 되는지, 아니면 당신의 질문에 대답이 되었는지는 모르겠지만 적어도 몇 가지 아이디어는 있습니다.행운을 빌어요 :)
언급URL : https://stackoverflow.com/questions/36129133/most-performant-way-to-transform-move-large-number-of-dom-elements
'sourcecode' 카테고리의 다른 글
Angularjs에서 $compile을 지시 외에 사용하려면 어떻게 해야 합니까? (0) | 2023.10.10 |
---|---|
파이썬 패키지에 포함된 모든 모듈을 나열하시겠습니까? (0) | 2023.10.10 |
이 두 구조 선언의 차이점은 무엇입니까? (0) | 2023.10.05 |
SQL 개발자 사용자 지정 연결 문자열 (0) | 2023.10.05 |
mysql java 프로그램에서 works를 선택, 삽입 및 삭제하지만 업데이트가 작동하지 않습니다. (0) | 2023.10.05 |