小程序點睛系列寫到第三篇,我纔在昨夜臨睡前想到這個名字。官方文檔講過的東西我不重複,我只在你會寫的基礎上,幫你畫上點睛一筆。這一篇,是我與小程序鏖戰半年苦心孤詣的成果,滿滿乾貨。javascript
從基礎庫 1.6.3 開始支持,用來抽象功能組件,以便在多個頁面複用。若是你有 React
或 Vue
等前端類庫的開發經驗,對自定義組件必定不會陌生。css
小程序吸取了 Vue
的模板語法,React
的狀態管理方式,再加上 Web Component
的 Shadow DOM
殘缺版本,總之就是一邊抄一點,造成了獨具特點的小程序風格組件。這使得你以前在其它類庫上得到的經驗不能徹底適用。html
接下來,咱們就一塊兒聊聊小程序組件的奇技淫巧。前端
小程序將組件數據分爲父組件傳遞來的 properties
和自身持有的 data
,這點與主流前端框架相似,咱們重點關注 properties
。java
組件的 property 接收 type
、value
、observer
三個參數git
String
, Number
, Boolean
, Object
, Array
, null
從 .wxml
傳遞過來的值到 .js
以前會先通過類型轉換。若是想傳遞混合類型值(如既多是 String
也多是 Number
的值),能夠將 type
設置爲 null
,能夠避免默認的類型轉換。github
若是不設置 value
的值,那該 property
的默認值就是其類型的零值。對應以下:小程序
String => ''
Number => 0
Boolean => false
Object => {}
Array => []
null => null
複製代碼
因爲小程序自身不支持 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
模塊與 Vue
模板大同小異,惟一值得了解的是因爲小程序不徹底實現了 Shadow DOM
, Vue
中 <template>
標籤只能有一個根節點的限制是不存在的。所以在大多數狀況下,你都不須要給 .wxml
額外添加根節點。
<!-- good.wxml -->
<view>{{ name }}</view>
<view>{{ age }}</view>
<!-- bad.wxml -->
<view>
<view>{{ name }}</view>
<view>{{ age }}</view>
</view>
複製代碼
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 變量,能夠達到意想不到的效果。
現階段支持各瀏覽器的支持度並不高,版本稍舊的瀏覽器就會遇到問題。但小程度已經徹底支持了這個特性。
因爲小程序使用了 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 新特性的支持比較完善,vw
,vh
,flex
,calc
,CSS variables 等等只要你想到,你能夠大膽地使用,徹底不須要考慮兼容性問題,這簡直就是前端求之不得的試驗田。因此,好好學習,大膽使用吧!
寫了這麼多,本身都忘了要寫些什麼。原本是準備日更的,可是這兩天一直在忙社保的事。剛剛從公司離職,辦理靈活就業人員耽誤了很多時間。感謝各位耐心閱讀至此,這都是我工做半年以來的經驗之談,但願能夠對大家有一點幫助。
若是你也想發佈小程序的組件,官方模板雖不失爲一個選擇,但我也要強推一下我寫的腳手架工具 tacer,只需一行 npx tarcer wx-component
就能夠開始你的項目了哦!
小程序點睛系列還剩下一篇,最後一篇,咱們單純聊 JavaScript
,關注我喲。