需求:
1、點(diǎn)擊左側(cè)分類菜單,右側(cè)界面滑動到對應(yīng)分類的第一個;
2、能嵌套在ng-Zorro的Drawer抽屜里面正常運(yùn)行;
3、某個分類的對應(yīng)內(nèi)容不存在了,分類菜單要有提示;
版本:
angular :7.1.0
ng-zorro-antd : 7.0.3
我這里分了兩個page,test是主體,test2只是Drawer抽屜,沒有做任何改動,直接上代碼吧
test.html
<div nz-row>
<div nz-col nzSpan="6" class="box1">
<ul>
<li
[ngClass]="{'active': active === i}"
(click)="cl(item.value)"
*ngFor="let item of list, let i = index"
class="{{item.disabled?'disabled':''}}"
>
{{item.name}}
</li>
</ul>
</div>
<div
nz-col
nzSpan="18"
class="box2"
#box2
id="aa"
[ngStyle]="{height: height + 'px'}"
>
<ul>
<li class="a" *ngFor="let item of a">{{item}}</li>
<li class="b" *ngFor="let item of b">{{item}}</li>
<li class="c" *ngFor="let item of c">{{item}}</li>
<li class="d" *ngFor="let item of d">{{item}}</li>
</ul>
</div>
</div>
test.scss
ul {
display: block;
border: 1px solid #000;
li {
padding: 10px;
border-bottom: 1px solid #000;
}
}
.box1 {
ul {
li {
&.disabled {
background: #ccc;
cursor: no-drop;
opacity: 0.5;
}
&.active {
background: #ccc;
}
}
}
}
.box2 {
height: 400px;
overflow-y: scroll;
}
test.ts
import {
Component,
OnInit,
ViewChild,
ElementRef,
AfterViewInit,
ChangeDetectorRef
} from '@angular/core';
import { fromEvent } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { reject } from 'q';
@Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit, AfterViewInit {
a = [1, 1, 1, 1, 1, 1, 1, 1, , 1, 1, 1, 1, 1, 1];
b = [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2];
c = [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3];
d = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4];
@ViewChild('box2') box2;
active = 0;
heightArr = [];
// 左側(cè)菜單欄(需要手動配置的參數(shù),上下文關(guān)系name必須class保持一致)
list = [
{
name: 'a',
value: 0,
disabled: false
},
{
name: 'b',
value: 0,
disabled: false
},
{
name: 'c',
value: 0,
disabled: false
},
{
name: 'd',
value: 0,
disabled: false
}
];
// 55 是Drawer抽屜的title的高度,48 是Drawer抽屜的padding高度,根據(jù)實(shí)際情況自己配置
height = window.innerHeight - 55 - 48;
constructor(private el: ElementRef, private cdref: ChangeDetectorRef) {}
ngOnInit() {}
ngAfterViewInit() {
const classNameArr = [];
this.list.map(r => {
classNameArr.push('.' + r.name);
});
classNameArr.map((r, i) => {
if (!this.getFirstNode(r)) {
this.list[i].disabled = true; // 當(dāng)頁面某個class不存在的時候設(shè)置不可操作狀態(tài)(用于某一個類型的數(shù)據(jù)不顯示的時候)
this.cdref.detectChanges(); // 這個必須加,不加會報錯
}
this.list[i].value = this.getFirstNode(r);
this.heightArr.push(this.getFirstNode(r));
});
this.scrollListen();
}
// 左側(cè)菜單點(diǎn)擊事件
cl(n) {
const nowScrollTop = this.box2.nativeElement;
nowScrollTop.scrollTo({
top: n,
behavior: 'smooth'
});
}
// 滾動監(jiān)聽
scrollListen() {
const nowScrollTop = this.box2.nativeElement;
fromEvent(nowScrollTop, 'scroll')
.pipe(debounceTime(30)) // 防抖 (如果你想要更加絲滑的效果直接吧防抖去掉吧)
.subscribe(event => {
const st = event['target'].scrollTop;
this.active = this.scrollFindIndex(st, this.heightArr);
});
}
// 獲取樣式組的第一個的offsetTop
getFirstNode(className) {
const arr = [].slice
.call(document.querySelectorAll(className))
.map(t => t.offsetTop);
return arr[0];
}
// 判斷值在數(shù)組的那個區(qū)域內(nèi)
scrollFindIndex(val, arr) {
let r;
// 當(dāng)某一個class不存在的時候做出跳過處理
arr.map((t, i) => {
if (t === undefined || t === 0) {
arr[i] = this.findNextNode(arr, i);
}
});
console.log(arr);
const n = arr.findIndex(el => el > val) - 1;
switch (n) {
case -1:
r = 0;
break;
case -2:
r = arr.length - 1;
break;
default:
r = n;
break;
}
return r;
}
// 遞歸尋找下個有值的(我的具體情況最后一個是一定有值,其他情況自己改下吧)
findNextNode(arr, i) {
let node;
if (arr[i]) {
node = arr[i];
} else {
node = this.findNextNode(arr, i + 1);
}
return node;
}
}
test2直接按文檔來就好了。

image
效果:

image.png
接下來我們模擬下其中一組數(shù)據(jù)沒有顯示,把其中一行代碼注釋了就好了

image.png

image.png