小程序點睛之三:纔不是你想的那種組件

前言

小程序點睛系列寫到第三篇,我纔在昨夜臨睡前想到這個名字。官方文檔講過的東西我不重複,我只在你會寫的基礎上,幫你畫上點睛一筆。這一篇,是我與小程序鏖戰半年苦心孤詣的成果,滿滿乾貨。javascript

自定義組件

從基礎庫 1.6.3 開始支持,用來抽象功能組件,以便在多個頁面複用。若是你有 ReactVue 等前端類庫的開發經驗,對自定義組件必定不會陌生。css

小程序吸取了 Vue 的模板語法,React 的狀態管理方式,再加上 Web ComponentShadow DOM 殘缺版本,總之就是一邊抄一點,造成了獨具特點的小程序風格組件。這使得你以前在其它類庫上得到的經驗不能徹底適用。html

接下來,咱們就一塊兒聊聊小程序組件的奇技淫巧。前端

JavaScript 部分

小程序將組件數據分爲父組件傳遞來的 properties 和自身持有的 data,這點與主流前端框架相似,咱們重點關注 propertiesjava

組件的 property 接收 typevalueobserver 三個參數git

type: 屬性類型,目前支持 String, Number, Boolean, Object, Array, null

.wxml 傳遞過來的值到 .js 以前會先通過類型轉換。若是想傳遞混合類型值(如既多是 String 也多是 Number 的值),能夠將 type 設置爲 null,能夠避免默認的類型轉換。github

value: 默認值

若是不設置 value 的值,那該 property 的默認值就是其類型的零值。對應以下:小程序

String => ''
Number => 0
Boolean => false
Object => {}
Array => []
null => null
複製代碼

observer: 屬性被改變後執行的函數

因爲小程序自身不支持 watch,故而沒法監聽 data 中某一項的改變。但與 React 不一樣的是,組件的 properties 在組件運行時會被整合入 data 中,經過 this.data 獲取,而且能夠調用 this.setData 改動 properties 的值。 所以能夠將須要監聽的 data 放於 properties 中,利用 observer 監聽。同時,爲表示其爲內部狀態,建議如下劃線(_)開頭,且再也不外部設置其值。瀏覽器

observer 還能夠用來減小 .wxml 模板的重複代碼。例如父組件傳遞了一個 source 對象,要求組件顯示其姓名與年齡bash

// component.js
Component({
    properties: {
        source: Object,
    }
})
複製代碼
<!-- component.wxml -->
<view>{{ source.name }}</view>
<view>{{ source.age }}</view>
複製代碼

利用 observer 能夠寫成

// component.js
Component({
    properties: {
        source: {
            type: Object,
            observer(val) {
                this.setData(val)
            }
        }
    }
})
複製代碼
<!-- component.wxml -->
<view>{{ name }}</view>
<view>{{ age }}</view>
複製代碼

這對體量較大的組件猶爲有效。同時,將 source 封裝爲 behavior,能夠最大限度的減小冗餘代碼

// sourceBehavior.js
export default Behavior({
	properties: {
        source: {
            type: Object,
            observer(val) {
                this.setData(val)
            }
    }
  }
})

// component.js
import sourceBehavior from 'path/to/sourceBehavior.js'

Component({
    behaviors: [sourceBehavior]
})
複製代碼

WXML 部分

.wxml 模塊與 Vue 模板大同小異,惟一值得了解的是因爲小程序不徹底實現了 Shadow DOMVue<template> 標籤只能有一個根節點的限制是不存在的。所以在大多數狀況下,你都不須要給 .wxml 額外添加根節點。

<!-- good.wxml -->
<view>{{ name }}</view>
<view>{{ age }}</view>

<!-- bad.wxml -->
<view>
	<view>{{ name }}</view>
    <view>{{ age }}</view>
</view>
複製代碼

WXSS 部分

inherit 關鍵字

咱們能夠經過將屬性值設置爲 inherit 來有效減小代碼冗餘。若是你想保持節點屬性與父節點一致,就應當使用這個關鍵字。

回想一下小程序點睛之二:小程序使用 Iconfont 的正確姿式,默認 Iconfont 下載的 CSS 文件中定義了 .iconfont 類的字體大小爲 16px,若是你不想每次更新改動這一值,那麼能夠在組件樣式表中添加

.iconfont {
    font-size: inherit;
}
複製代碼

組件樣式表的優先級要高過外部引入的樣式表,因此本來的 font-size: 16px 就會被覆蓋,.iconfont 的字體大小就會跟其父節點一致。

注意:這裏 .iconfont 的父節點並非邏輯上的父節點,而是 shadow-root

:host 選擇器

你能夠在開發者工具中看到每一個自定義組件的 shadow-root,其默認是行內元素,你能夠在組件樣式表中經過 :host 選擇器修改它的樣式

:host {
    display: block;
    background: red;
}
複製代碼

外部樣式表全部的屬性都是直接做用在 shadow-root(而非模板中的根節點)上,例如

<!-- iconfont.wxml -->
<text class="iconfont icon-{{icon}}"></text>

<!-- page.wxml -->
<iconfont class="icon" icon="upload"></iconfont>
複製代碼
/* page.wxss */
.icon {
    color: green;
}

/* iconfont.wxml */
.iconfont {
    color: red;
}
複製代碼

你會發現圖標的顏色是紅色而不是綠色。由於 .icon 是樣式做用於 shadow-root.iconfont 是其子節點,繼承其 color 屬性,但因爲 .iconfont 優先級更高,因此顏色是爲紅色。

優先級關係爲 :host 選擇器 < 外部樣式 < 子節點樣式。利用這個特色,配合 CSS 變量,能夠達到意想不到的效果。

CSS 變量

現階段支持各瀏覽器的支持度並不高,版本稍舊的瀏覽器就會遇到問題。但小程度已經徹底支持了這個特性。

因爲小程序使用了 Shadow DOM,所以在組件內是沒法使用全局定義的樣式類的。可是,CSS 是可繼承而且是全局可用的。所以,咱們能夠將經常使用的樣式定義在 app.wxss 內,並在任意頁面或組件內使用

/* app.wxss */
page {
    --primary-color: #aabbcc;
    --accent-color: #ddeeff;
    --spacing: 32rpx;
}

/* other.wxss */
.component {
    background: var(--primary-color);
    padding: var(--spacing);
}
複製代碼

如此,你只須要對 app.wxss 稍做修改,就能夠改變整個小程序樣式。

除此以外,咱們還能夠利用這個特性,優化組件定義。例如,咱們須要一個圓形組件,常規的作法是定義相等的寬高,再設定 border-radius: 50%。咱們來看看高級的寫法

/* circle.wxss */
:host {
    /* 默認直徑爲 32rpx */
    --diameter: 32rpx;
    
    width: var(--diameter);
    height: var(--diameter);
    border-radius: 50%;
}

/* outer.wxss */
.circle {
    /* 將 circle 組件的直徑設置爲 64rpx */
    --diameter: 64rpx;
}
複製代碼

還記得我剛剛說的優先級規則嗎?外部樣式的優先級高於 :host 選擇器,所以 circle 組件的直徑會被設置爲 64rpx

不僅如此,經過自定義屬性,咱們還能夠修改嵌套較深的組件樣式

<!-- component.wxml -->
<view class="this">
	<view class="is">
    	<view class="a">
        	<view class="embed-component"></view>
        </view>
    </view>
</view>
複製代碼
/* component.wxss */
:host {
    --embed-color: red;
}

.embed-component {
    color: var(--embed-color);
}

/* outer.wxss */
.component {
    --embed-color: blue;
}
複製代碼

Bingo,藉助 CSS 屬性,咱們得到了改動後代節點樣式的能力。你大能夠說一樣的功能使用 externalClasses 或者 addGlobalClass 也能夠作到。可是對於組件來講,外部傳入的樣式可知,處理起來心智負擔更小,更符合高內聚,低耦合的標準。同時,建議將可改動的自定義 CSS 變量以註釋的形式寫在 component.js 中,方便其餘人理解你的組件。

em 而不是 rpx

爲了保持組件可擴展性,應當儘量的使用 em 做爲字體大小單位。我以前用一個小程序解析 markdown 的組件庫,其中將全部字體大小都寫死爲 rpx,例如

/* markdown.wxss */
.h1 {
    font-size: 32rpx;
}

.h2 {
    font-size: 28rpx;
}

.h3 {
    font-size: 24rpx;
}
複製代碼

如此當然能實現需求,但卻失去了外部改變字體大小的能力。做爲一個組件,應該適應更多的可能性,改成 em 做爲字體大小單位就能很好的解決這一問題

.h1 {
    font-size: 2em;
}

.h2 {
    font-size: 1.8em;
}

.h3 {
    font-size: 1.4em;
}
複製代碼

數值僅爲舉例

大膽使用新特性

小程序對 CSS 3 新特性的支持比較完善,vwvhflexcalc,CSS variables 等等只要你想到,你能夠大膽地使用,徹底不須要考慮兼容性問題,這簡直就是前端求之不得的試驗田。因此,好好學習,大膽使用吧!

後記

寫了這麼多,本身都忘了要寫些什麼。原本是準備日更的,可是這兩天一直在忙社保的事。剛剛從公司離職,辦理靈活就業人員耽誤了很多時間。感謝各位耐心閱讀至此,這都是我工做半年以來的經驗之談,但願能夠對大家有一點幫助。

若是你也想發佈小程序的組件,官方模板雖不失爲一個選擇,但我也要強推一下我寫的腳手架工具 tacer,只需一行 npx tarcer wx-component 就能夠開始你的項目了哦!

小程序點睛系列還剩下一篇,最後一篇,咱們單純聊 JavaScript,關注我喲。

相關文章
相關標籤/搜索