Vaadin學習筆記——自定義vaadin組件的樣式

在開始閱讀本文之前,你需要先了解以下內容:
  • CSS相關知識(如選擇器、如何編寫CSS rule等)

  • HTML相關知識(元素、class屬性、DOM層級結構等)

  • Vaadin相關知識(如怎樣創建、運行Vaadin項目,怎樣創建一個vaadin頁面)

前言

習慣了SSH的小夥伴們遇到vaadin這樣的技術時,肯定會一臉懵逼。我當初看到這個東西時眼前飄過的絕對不是6666666666,而是一大堆????????????。

有人說Vaadin就像swing,果真如此嗎?No!形似而已。真要上手去用去寫,你就會發現——這TM就是一坨屎。

好啦,不抱怨了。由於公司大部分產品都是基於Vaadin創建的,爲了提高代碼質量,再屎的東西也要硬着頭皮去學。

在學習Vaadin的時候,有一個坎,那就是theming。Vaadin真不像Swing,再怎麼說swing的LAF還沒有跳脫Java的範疇,可以說他們還是在同一個體系中的。而Vaadin的style(或者說theming)則與你寫的Java代碼沒有關係,哦,這樣說並不確切。確切的說,絕大多數靈活的theming工作都要用到CSS(SCSS)。在Java代碼中僅能對一些組件做最基礎的尺寸等樣式調整,至於什麼margin、space、padding啥的,不能做(space僅有一個開關,代表“有space”和“沒有space”)。如果你想對vaadin的組件進行更大尺度的樣式化,請使用SCSS。

調整樣式的大致步驟

1、用java語言編寫頁面,添加頁面元素。

2、給頁面元素指定一個特定的class name。

3、在SCSS中針對特定的class name編寫樣式規則。

4、編譯,試運行,看結果。


實例:樣式化一個Label組件

接下來我就以Label組件爲例,詳細講述如何爲vaadin組件修改樣式。在例子中,我將創建一個Label用來顯示某人的姓名和年齡。然後針對姓名和年齡兩個部分分別樣式化。如果創建Label部分不熟悉,你可以參考我的另一篇文章《Vaadin組件筆記——Label》。另:如何創建Vaadin項目,怎樣編譯運行,不在本文範疇之內,你可以參考其他相關資料。

第一步:用java語言編寫頁面,添加一個Label組件。

組件的Caption中填寫“Mr. Wangbagaozi”,value中填寫“1000 year-old”。

List-1

Label label = new Label();
label.setCaption("Mr. Wangbagaozi");
label.setValue("1000 year-old");

先讓我們運行一下,看看界面上的效果。

wKioL1h022CTZS41AAAL3rNpZRQ373.png

這是Vaadin根據我們的Java代碼自動生成的前端代碼:

List-2

<div class="v-widget v-has-caption v-caption-on-top v-has-width" style="width: 100%;">
    <div class="v-caption" id="gwt-uid-2" for="gwt-uid-3">
        <span class="v-captiontext">Mr. Wangbagaozi</span>
    </div>
    <div class="v-label v-widget v-has-width" id="gwt-uid-3" aria-labelledby="gwt-uid-2" style="width: 100%;">1000 year-old</div>
</div>

第二步:給頁面元素指定一個特定的class name。

現在,我希望caption中的內容字號24px並且加粗,value中的內容字號16px,灰色,斜體。之前說過,vaadin的組件樣式是通過CSS來調整的,那麼,作爲CSS編寫規則的最重要的選擇器就那麼幾種,class、id、element name等。vaadin推薦使用class name。Okay,我們看一下生成的前端HTML代碼,就清楚該怎樣編寫我們的CSS規則了。注:在CSS和SCSS中,有些需求可以使用多種方式來實現,本文介紹其中一種方式。方式無好壞,你覺得好用就好。

通過分析,我們看到,帶有Caption的label被解析成了一個div包裹着兩個同級div。提煉一下:

List-3

<div class="v-widget v-has-caption v-caption-on-top v-has-width">
    <div class="v-caption">
        <span class="v-captiontext">Mr. Wangbagaozi</span> <!--這裏是caption-->
    </div>
    <div class="v-label v-widget v-has-width">1000 year-old</div> <!--這裏是value-->
</div>

我們嘗試寫一下SCSS(vaadin中使用SCSS,你需要先編寫SCSS,編譯時vaadin會自動將SCSS編譯爲CSS)。

List-4

.v-captiontext {
    font-size: 24px;
    font-weight: bold;
}
.v-label {
    font-size: 16px;
    color: gray;
    font-style: italic;
}

運行一下看看結果:

wKioL1h0466z112HAAARCWLZrO0705.png

第三步:在SCSS中針對特定的class name編寫樣式規則。

樣式改變了,貌似這樣就可以了?等等!這樣寫有問題,讓我再增加一個label組件到頁面上,你們就知道問題在哪兒了。下面我增加一個label,用來顯示這位Wangbagaozi先生的地址還有電話號碼。

List-5

Label label2 = new Label();
label2.setCaption("South China sea.");
label2.setValue("13399988888.");

運行一下看看結果:

wKiom1h05PGBIQO2AAAe1YdoQZY392.png

Whaaat!! 這是什麼鬼東西?沒錯,被放入label2的caption的內容也隨之改變,而這並不是我們想要的結果。我們希望label2的caption和value都按照普通方式顯示,不要加樣式。

我們來看一下vaadin幫我們自動生成的前端代碼,找一下有什麼辦法將兩個Label進行區分。

List-6

<div class="v-slot">
    <!--下面是label生成的代碼-->
    <div class="v-widget v-has-caption v-caption-on-top v-has-width" style="width: 100%;">
        <div class="v-caption" id="gwt-uid-2" for="gwt-uid-3">
            <span class="v-captiontext">Mr. Wangbagaozi</span>
        </div>
        <div class="v-label v-widget v-has-width" id="gwt-uid-3" aria-labelledby="gwt-uid-2" style="width: 100%;">1000 year-old</div>
    </div>
</div>
<div class="v-slot">
    <!--下面是label2生成的代碼-->
    <div class="v-widget v-has-caption v-caption-on-top v-has-width" style="width: 100%;">
        <div class="v-caption" id="gwt-uid-4" for="gwt-uid-5">
            <span class="v-captiontext">South China sea.</span>
        </div>
        <div class="v-label v-widget v-has-width" id="gwt-uid-5" aria-labelledby="gwt-uid-4" style="width: 100%;">13399988888.</div>
    </div>
</div>

呃……label和label2生成的前端代碼中用於區別的class name一模一樣,除了進行噁心的相對定位選擇就沒有別的辦法了嗎?當然不是,Vaadin不會這麼蠢!既然無法利用自動生成的class name,我們還可以利用我們自定義的class name來對這兩個label進行區別。我們只需要針對第一個label進行樣式化,其他的不用加載樣式。Okay,稍加修改List-1的代碼:

List-7

Label label = new Label();
label.setCaption("Mr. Wangbagaozi");
label.setValue("1000 year-old");
label.addStyleName("special-label");  <--- Look here!

方法addStyleName其實就是給指定的組件添加一個class name。現在讓我們再看一下vaadin生成的前端代碼有什麼變化。

List-8

<div class="v-slot v-slot-special-label">
    <!--下面是爲label生成的代碼-->
    <div class="v-widget v-has-caption v-caption-on-top v-has-width" style="width: 100%;">
        <div class="v-caption v-caption-special-label" id="gwt-uid-2" for="gwt-uid-3">
            <span class="v-captiontext">Mr. Wangbagaozi</span>
        </div>
        <div class="v-label v-widget special-label v-label-special-label v-has-width" id="gwt-uid-3" aria-labelledby="gwt-uid-2" style="width: 100%;">1000 year-old</div>
    </div>
</div>
<div class="v-slot">
    <!--下面是爲label2生成的代碼-->
    <div class="v-widget v-has-caption v-caption-on-top v-has-width" style="width: 100%;">
        <div class="v-caption" id="gwt-uid-4" for="gwt-uid-5">
            <span class="v-captiontext">South China sea.</span>
        </div>
        <div class="v-label v-widget v-has-width" id="gwt-uid-5" aria-labelledby="gwt-uid-4" style="width: 100%;">13399988888.</div>
    </div>
</div>

注意看List-8中的代碼,相比較沒有用addStyleName方法添加額外class name的label2生成的代碼List-6,第4行的div元素class屬性中多了“v-caption-special-label”,還有第7行的div元素中多了“special-label”和"v-label-special-label"。

有了這些不同,我們就好區別對待了。修改SCSS如下:

List-9

.v-caption-special-label .v-captiontext {
    font-size: 24px;
    font-weight: bold;
}
.v-label-special-label {
    font-size: 16px;
    color: gray;
    font-style: italic;
}

運行看看效果:

wKioL1h08s2iSFCTAAAbk96AwQE039.png

Bingo!就是我想要的效果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章