首頁 >web前端 >js教程 >Angular實作雙向折疊列表元件

Angular實作雙向折疊列表元件

小云云
小云云原創
2018-01-16 09:39:081807瀏覽

本文主要介紹了Angular實現雙向折疊列表組件的範例程式碼,分為左右兩組,具有一定的參考價值,有興趣的小伙伴們可以參考一下,希望能幫助到大家。

最近在做一個雙向折疊元件,如下圖所示,頁面是分為兩組,左邊頁面是Summary Panel,主要是一組列表,右邊頁面是Detail Panel,展示左邊列表中某一項的具體訊息,我們把它記作「Middle State」。

我們也看到有「8809681ace18ec83dd5b775f04c3322e」兩組按鈕,這就是我們要做的「雙向折疊組件」。點擊左邊的“5fe999eed3b112b4bb4cb2b2361e77a7”,再回到“Middle State”。點擊“>”,Detail Panel折疊起來,Summary Panel鋪滿整個頁面,我們把它記作“Right State”,如下圖:

我們通過以上的需求分析可知,

1.頁面的整體佈局是一個Summary的p,兩個箭頭buttons,一個Detail的p。

2.頁面總共有三種state:“Middle”、“Left”、“Right”,有兩個button:“e84aacd5f768f485facc4bd6b8750f46”,也就是兩個button去控制三個state。

因此我們需要定義一個枚舉來記錄頁面的三種狀態(注意,定義枚舉要用export導出,否則後面會出錯)


export enum CollapseExpandState {
  Middle = 1,
  Left,
  Right
}

頁面的結構如下,並且透過一個變數_collapseExpandState去控制「left」和「right」兩個button,具體為「680831cebac6617a53de2455a94fd6ac」會在頁面狀態為「Middle」和「Left」狀態下出現,從需求圖中即可得知:


<p id="container">
  <p id="summary"></p>
  <p id="buttons">
    <p id="left" *ngIf="_collapseExpandState === CollapseExpandState.Middle || CollapseExpandState.Right" (click)="_onHandleLeft($event)">《</p>
    <p id="right"> *ngIf="_collapseExpandState === CollapseExpandState.Middle || CollapseExpandState.Left" (click)="_onHandleLeft($event)">》</p>
  </p>
  <p id="detail"></p>
</p>

這裡在angular的template中用到了枚舉,遭遇了一些麻煩,如果我們按上述定義了枚舉,並且在Angular Component的template中用了枚舉,我們會得到以下的錯誤提示:

TypeError: Cannot read property 'Middle' of undefined

也就是說,在Angular2的template中無法識別定義的枚舉類型CollapseExpandState,這是因為你寫的Angular Component的template模板的執行環境是你定義的component class,但是在class中並沒有關於CollapseExpandState枚舉的任何引用,所以Angular在為你的component產生模板的時候認為CollapseExpandState是undefined的。知道了原因,解決方案就很容易了,只需要在component class中加入這個枚舉的引用即可:


@component(...)
export class ContainerWidget {
  public CollpaseExpandState: any = CollapseExpandState;
}

我們透過枚舉狀態來控制了兩個buttons是否在適當的頁面狀態顯示與否,但是即使是同一個buttons,在不同的頁面狀態下所用到的樣式也會不同,這裡的樣式其實最主要的就是位置了。我們先來考慮如何控制button的樣式,再來考慮如何正確定位不同頁面狀態下button的位置。

對於控制button的樣式,我們需要控制三個樣式:"left button"、"right button"還有「buttons」。能夠想到有三種方案:

I、用ng-class

ng-class一般的用法如下:


#
<some-element [ngClass]="{&#39;first&#39;: true, &#39;second&#39;: true, &#39;third&#39;: false}">...</some-element>

因此它需要用boolean去控制,每一種樣式需要一個boolean去控制,left和right各有兩種樣式,buttons有三種樣式,這樣就需要用5個boolean去控制,略顯麻煩。

II、 用ElementRef.nativeElement.className

分別在buttons、left和right上用模板變量,然後在class中定義:


@ViewChild("buttons") buttons: ElementRef;
@ViewChild("left") left: ElementRef;
@ViewChild("right") right: ElementRef;

在處理函數中這樣去給class賦值從而改變樣式:


this.left.nativeElement.className = "XXXXX";

這樣的話,我們需要從元素的角度出發,只需要3個元素變量,從而改變元素上的className即可。但這樣做有個隱患,注意到我們是用的ngIf來控制left和right在不同狀態下是否存在,因為每一次事件處理都需要對三個元素的樣式進行賦值,但是如果某個頁面狀態下ngIf為false從而元素不存在,那麼就會報“Null Pointer”的錯誤,所以如果所引用的元素受到了ngIf的控制,不確定是否一定存在的情況下,要慎用該方法為元素賦予樣式。

III、用 class="{{}}"

为了II中的尴尬,我们采用在HTML元素上对class进行直接赋值的方式,但是需要借用插值表达式{{}}。我们在css中用class的形式定义好样式,并且在compoennt class中定义三个字符串变量记录className,然后在事件处理函数中把相应的className赋予变量即可。这样我们就不用担心元素是否存在而导致的空指针了。

考虑完如何控制样式,下面我们进入CSS样式的讨论,这里其实主要考虑的就是位置。

我们采用flex布局,从左到右依次排列Summary Panel, buttons和Detail Panel。我们希望Buttons向左移,但是空出的位置被Detail Panel来填充。首先来看一下不设样式的效果图:

显然buttons是占据了文档流的位置的,如果这时候我们用relative定位buttpms,并且设置left的值为-74px(注意到left为负数就会把元素往左推):


.buttons{
  display: flex;
  position: relative;
  margin-top: 23px;
  left: -74px;
}

效果图为:

发现如果用left的话,buttons原来的文档流位置依然存在,只是buttons相对于原来的位置移动了一定的位移。

如果我们用margin-left来设置呢:


.buttons{
  display: flex;
  position: relative;
  margin-top: 23px;
  margin-left: -74px;
}

效果图为:

它和left不同之处在于,left会留住原来的文档流位置,但是用margin-left原来的文档流位置会消失,而由后面的元素补充过来,而我们想要的效果,正好是用margin-left来实现的。

所以用CSS定位的时候,要明白left和margin-left的区别,从而选择正确的方式来定位。

总结一下,从这个案例中我们学习到了:

  1. 双向折叠可以用“3种页面状态去控制2个按钮”来实现

  2. enum在Angular Component的template中用到时,需要在compnent class中添加它的引用

  3. 控制元素样式有很多方法,要选择合适的方法

  4. CSS定位中left和margin-left虽然都能把元素推向左边,但是left保留原来文档流位置,margin-left不保留原来文档流位置。

相关推荐:

简单实现Angular文字折叠展开效果

有关折叠式的文章推荐

使用纯CSS打造可折叠树状菜单方法介绍

以上是Angular實作雙向折疊列表元件的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn