視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

目錄

1,主要屬性

1.1,hover-class

1.2,hover-stop-propagation

1.3,hover-start-time、hover-stay-time

1.4,拒絕300毫秒延遲

2,示例代碼與最佳實踐

2.1,使用hover-class定義按鈕狀態

2.2,使用view實現flex佈局

2.2.1,justify-content的值

2.2.2,align-items的值

2.2.3,flex-wrap的值

2.2.4,align-content的值

2.2.5,flex-direction的值

3,相關問題

3.1,如何把view上的內容繪製在畫布上?


文 / 石橋碼農

字符16612,閱讀13分鐘,實踐30分鐘

1,主要屬性

view 是最基礎的,也是微信小程序第一個公佈的容器組件。所謂容器組件,就像 HTML 裡的 div 標籤一樣,是為容納其它組件而存在的。它本身也可以有一些自己的樣式,因為它本身也可以有樣式,但它最重要的功能,是佈局。

這個容器組件的主要屬性有:

1.1,hover-class

指定按下去的樣式類。當 hover-class="none" 時,或者沒有設置這個屬性時,沒有點擊態效果。單擊後,當鬆開手指時,組件恢復變化前的狀態。

代碼:

<code>flex-direction: row/<code>

效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

當按下去時,view容器應用了bc_red樣式,鬆開後,恢復如初。

hover-class這個屬性名稱具有一定迷惑性。在HTML開發中,mouseHover事件指是的鼠標懸停於某頁面元素之上時觸發的事件,mouseDown才是鼠標按下去的事件。這裡hover-class這個屬性名稱,從功能上來看,命名為tap-down-class或press-down-class更為合適。

1.2,hover-stop-propagation

指定是否阻止本節點的父及以上節點出現點擊態。默認為false,不阻止。

阻止節點出現點擊態,什麼意思呢?

代碼:

<code>  flex-direction: row      child view  /<code>

兩個view容器,裡面那個view使用了hover-stop-propagation屬性。由於它是一個布爾屬性,只要寫上屬性,不填寫屬性值也代表真。如果寫屬性值的話,還要使用布爾值綁定:

<code>hover-stop-propagation={{true}}/<code>

直接寫"true",是字符串,是不行的。

效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

從效果看,子容器有點擊態,父容器沒有,雖然父容器也設置了hover-class屬性。

官方文檔中關於這個屬性是這樣描述的:“指定是否阻止本節點的祖先節點出現點擊態”,什麼是“點擊態”?既然是點擊態,把屬性名稱全名為hover-stop-propagation就不妥當嘛,此處應該命名為press-stop-propagation更為合適。

現在我們看另外一個問題,通過事件跟蹤,驗證一下hover-stop-propagation屬性的作用。

wxml代碼:

<code>  flex-direction: row      child view  /<code>

在父子容器同時綁定了tap事件。為方便追蹤,為父子容器分別分配了一個id。父容器id為parentView,子容器id為childView。

js:

<code>onTap(e){  console.log(e.target)}/<code>

單擊一次,輸出:

<code>{id: "childView", offsetLeft: 20, offsetTop: 64, dataset: {…}}{id: "childView", offsetLeft: 20, offsetTop: 64, dataset: {…}}/<code>

為什麼輸出兩次?單擊一次,為什麼觸發兩次tap事件?

這是因為每個事件都有捕捉、目標與冒泡三個階段,在view視圖容器上使用bind綁定的事件,默認會在目標與冒泡兩個階段派發事件,一個是本身派發的,一個是子內容冒泡派發的。

冒泡事件會繼續向上傳遞。hover-stop-propagation屬性就是阻止冒泡事件向上傳遞的。當設置該屬性後,父容器即parentView,便不會觸發onTap的執行,這是我們在輸出中只看到childView的原因。

那麼怎麼樣可以讓view的tap事件只觸發一次呢?

可以使用catch綁定事件函數。catch與bind的作用相同,與 bind 不同的是, catch 會阻止事件向上冒泡。

代碼:

<code>  flex-direction: row      child view  /<code>

與前面代碼只有一處不同,就是將子容器的bindtap改為了catchtap。

讀者朋友們可以自行測試一下,改用catch綁定事件函數後,onTap函數單擊一次執行一次。

1.3,hover-start-time、hover-stay-time

hover-start-time是按住後多久出現點擊態,hover-stay-time是手指鬆開後點擊態保留多長時間,單位均是毫秒。沒有特殊說明,微信小程序中所有屬性中的時間單位都是毫秒。

這兩個屬性的設置說明,在view容器組件內部,有人掐表做了定時。當touchstart事件發生時,開始計時,到達hover-start-time時,應用hover-class樣式;當touchstart結束,即startend事件發生時,開始hover-stay-time倒計時,時間到則移除hover-class樣式。

設置hover-start-time屬性,是為了方便開發者控制hover-class樣式出現的時機。在測試中發現,但凡在view上單擊一下,很正常的速度單擊,不需要懸停,也會出現hover-class樣式的應用。50ms是極短的時間,但是在計算機的微觀世界卻是一個極長的時間,這個時間已經足以包裹一次系統單擊事件。

單擊事件不是一個點事件,也是一個跨一定時間段的物理現象。在mac系統上,設置裡有一個地方可以改變單擊事件的跟蹤速度。

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

改變這個跟蹤速度後,在微信開發者工具模擬器中的tap事情也受其影響。如果你把跟蹤速度調整到快的一側,單擊時只是輕輕慢慢地一按,系統是不會觸發單擊事件的。

1.4,拒絕300毫秒延遲

我們知道,當延遲超過100毫秒時,用戶就會感覺到明顯的卡頓。但是在移動設備上,特別在蘋果的Safari瀏覽器上,我們不得不忍受300毫秒的延時。

這是為什麼呢?

喬本斯在發佈會上演示過這樣一個功能,對於一個Safari瀏覽器打開的網頁:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

在右邊內容區快速雙擊,蘋果會幫助我們準確定位到文章的主體內容,並將其放大:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

這個功能很酷。

但是有一個問題,如果用戶不小心在雙擊時單擊了一個鏈接,這讓軟件怎麼處理呢?是馬上跳轉,還是等待用戶的另一個單擊以判斷是不是雙擊事件?

蘋果採用的是第二種方式,所有Safafi中的鏈接都要延遲300毫秒,如果用戶沒有發出第二個單擊事件,再跳轉鏈接。這導致蘋果手機中的Html5頁面都非常卡頓。

但是微信小程序沒有這個問題,hover-start-time的默認時間是50ms,只需要50ms甚至更短就可以觸發單擊事件,微信小程序已經打破了300毫秒遲延的魔咒。

如果有人問你,使用微信小程序開發相比Html5開發,有什麼優勢?沒有單擊延遲就是在體驗上一個很大的優勢。

有一個問題留給讀者朋友們思考,hover-start-time這個屬性的值,最小可以設置為多少?設置為1毫秒可以嗎,為什麼?這個問題在之前的推文中提到過。

2,示例代碼與最佳實踐

使用hover-class,必使用hover-stop-propagation屬性。

代碼:

<code>/<code>

這是為了避免父容器受子容器影響。

在自定義用於觸發單擊的按鈕時,hover-class特別有用。一般按鈕有兩種狀態:常態與按下的狀態。使用hover-class正好可以定義按下的狀態。

2.1,使用hover-class定義按鈕狀態

wxml代碼:

<code>      /<code> 

三個按鈕均是基於button組件改造的。button是組件,同時實際上也是容器,所以在button上面也可以應用hover-class屬性。

wxss代碼:

<code>.btn{  display: flex;  align-items: middle;  padding: 8px 50px 8px;  border: 1px solid #b2b2b2;  background-color: #f2f2f2;}​.circle-btn__hover_btn {  opacity: 0.8;  transform: scale(0.95, 0.95);}​.rect-btn__hover_btn {  position: relative;  top: 3rpx;  left: 3rpx;  box-shadow: 0px 0px 8px rgba(175, 175, 175, .2) inset;}/<code>

我們看看這三個類樣式都有什麼作用。

.btn是普通的自定義按鈕樣式。flex與align-items是為了實現文本與圖標的橫向對齊。#b2b2b2是符合微信設計規範的按鈕邊框色,#f2f2f2是按鈕背景色。

transform使圓形按鈕在單擊時縮小0.05。按鈕單擊時微微縮小,這是從Flash交互時代傳承下來的體驗技巧。

#b2b2b2做為邊框色,rgba(175, 175, 175, .2)是其做為rgba格式的20%透明形式,將它作為方形按鈕按下狀態的內陰影顏色,這也是符合微信顏色設計規範的。box-shadow這個樣式用於定義組件的內陰影。

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

2.2,使用view實現flex佈局

view容器組件最大的作用,就是實現ui佈局。最常用的是flex佈局,基本所有常見的佈局都可以用它實現。flex佈局指將display樣式設置為flex,再加以其它相關的樣式實現的佈局。

關於flex佈局有三個十分重要的樣式:

  1. justify-content:調整內容,主軸方向的排列方式
  2. align-items:對齊元素,側軸方向的對齊方式
  3. align-content:對齊多行內容,側軸方向多行排列方式

以默認的flex-direction為row來看,即從左到右為主軸,自上而下為側軸。

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

在這種情況下,justify-content管制的是元素在x方向的排列策略;align-items管制的是主軸上排列的元素,在側軸方向,即y方向上的對齊方式;align-content管制的是當出現多行以後,多行內容在側軸方向上,即y軸方向上的排列策略。

這三個屬性很不好記,一時記住了,過一段時間用的時候可能還要查文檔。可以這樣輔助記住:

  1. 在默認的以x軸為主軸的情況下,即flex-direction為row,justify單詞的意思為「調整」,css樣式text-align有一個值是justify,意思是左右橫向對齊,這裡的justify也是橫向調整的意思。至於content,它比items 的字面寬,更能代表行。
  2. 負責元素排列與對齊的樣式,除了justify-content,就是align-items。既然justify-content負責的是橫向調整,那麼align-items負責的就是縱向對齊。
  3. 至於align-content,結合align-items與justify-content記憶。align指的是縱向對齊,content指的是行,那麼align-content指的就是多行的縱向排列方式。
  4. 當flex-direction為row時,橫向就是主軸,縱向就是側軸。

下面分別看一下這三個樣式的作用。

2.2.1,justify-content的值

flex-start:主軸起點對齊,默認值

wxml代碼:

<code>  justify-content:flex-start      1    2    3  /<code>

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

元素向主軸的起點看齊。與flex-start對應的值是flex-end。

flex-end:主軸結束點對齊

wxml代碼:

<code>  justify-content:flex-end      1    2    3  /<code>

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

元素在主軸方向上向尾部看齊。

center:在主軸中居中對齊

wxml代碼:

<code>      1    2    3  /<code>

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

有空隙往首尾放,居中看齊。

space-between:向首尾看齊,相當於align-text的justify效果

wxml代碼:

<code>      1    2    3  /<code>

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

兩端的子元素靠向父容器兩端,其他子元素之間的間隔相等。

space-around:元素之間的間隔,與與父容器之間的間隔相同

wxml代碼:

<code>      1    2    3  /<code>

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

在視圖效果上兩邊間隔較多一點,是因為外容器本身已經有了一個頁邊距。

2.2.2,align-items的值

stretch:填充整個容器,默認值

wxml代碼:

<code>      1    2    3  /<code>

bc_blue樣式本身有一個height設定,為了讓第三個子元素可以自由伸放,所以給它設置了height為auto。style內嵌樣式的優先級高於class類樣式。

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

第一個元素與第三個元素,均填充了整個父容器。在使用stretch這個值時,容器高度取決於最高的那個,其它次高元素必須在高度上可以自由伸縮,才可以發揮作用。不可以有height、min-height等樣式束縛。

flex-start:側軸的起點對齊

wxml代碼:

<code>      1    2    3  /<code>

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

默認x軸為主軸的情況下,效果就是頂部對齊了。

flex-end:側軸的終點對齊

wxml代碼:

<code>      1    2    3  /<code>

效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

center:在側軸中居中對齊

<code>      1    2    3  /<code>

效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

baseline:以子元素的第一行文字對齊

前面的flex-start、flex-end、center均是以元素本身所佔的區域定位的,只有baseline是以內部的文本定位的。

wxml代碼:

<code>  以子元素的第一行文字對齊      1    2    3  /<code> 

為了使baseline的對齊效果明顯,特意給第二、第三個元素設置了不一樣的屬性。

效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

這個特性在設計一些以文本居中顯示的ui效果時很有用,無論文本週圍有什麼樣的裝飾效果,文本始終是在一條線上對齊的。

2.2.3,flex-wrap的值

flex-wrap這個樣式是為了控制主軸一行顯示不了時候的換行策略的。它有三個值:

  1. nowrap:不換行,默認值
  2. wrap:換行
  3. wrap-reverse:換行,第一行在最下面

默認不換行的情況下,便於實現橫向滾動效果。我們重點看一下換行的效果。

wxml代碼:

<code>  多了換行      1    2    3    3    3  /<code>

效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

容器寬度不夠的時候,會自動折到下一行顯示;如果動態增加寬度,又會自動折回到上一行顯示。這種特性方便實現一些瀑布流效果,不限定顯示瀑布是幾列,可以動態調整顯示三列或四列。

2.2.4,align-content的值

通過前面justify-content、align-items兩個樣式可以看出來,具有相同名稱的值定義具有相似的含義。例如flex-start、flex-end、center這三個值,它們表示的含義是近似的。

align-content是為了控制多行在側軸方向的排列方式,這個樣式有這些值:

<code>stretch、center、flex-start、flex-end、space-between、space-around/<code>

這些樣式值在前面都出現過,在這裡代表的含義也與前面類似。我們看一下space-between的效果。

wxml代碼:

<code>  多行側軸的對齊方式      1    2    3    3    3    3    3  /<code>

運行效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

三行之間的間隔是相等的。

2.2.5,flex-direction的值

還有一個樣式在flex佈局中不得不提:flex-direction。它用於決定是x軸,還是y軸是主軸。默認情況下,也就是前面所講的情況,是以x軸為主軸的。

如果將flex-direction的值改為column,效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

值得一提的是,如果將y軸定為主軸的話,決定元素橫向排列的就不是justify-content,而是align-items了。

wxml代碼:

<code>  flex-direction: column,align-items:center      1    2    3  /<code>

將側軸方向上的對齊方式設定為center。

效果:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

x軸為側軸,所以三個元素表現為左右居中。

flex-direction一共有四個值:

  1. row:從左到右的水平方向為主軸,是默認值
  2. row-reverse:從右到左的水平方向為主軸
  3. column:從上到下的垂直方向為主軸
  4. column-reverse:從下到上的垂直方向為主軸

row-reverse與row相反,使元素在橫向從右向左排列;column-reverse與column相反,使元素從向下向上排列。

3,相關問題

3.1,如何把view上的內容繪製在畫布上?

view目前不能直接轉繪到畫布上。如果想生成海報,一種可行的辦法是:

  1. 使用wx.createCanvasContext創建一個畫布
  2. 在畫布上繪製內容,文本或圖片
  3. 通過wx.canvasToTempFilePath保存到本地,並獲取一個臨時圖片路徑
  4. 通過wx.saveImageToPhotosAlbum保存臨時圖片到本地相冊

有一個開源的小程序組件,封閉了通過json數據繪製海報的功能:

//github.com/Kujiale-Mobile/Painter

在階段代碼中集合了這個組件,運行效果為:

視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

單擊「保存」就可以將海報保存到本地了。

階段源碼:

//git.weixin.qq.com/rxyk/weapp-practice/repository/archive.zip?ref=2.2-view

好了,我是石橋碼農,這就是今天分享的內容,有什麼問題歡迎留言討論,也歡迎進群交流。

2020年4月7日

參考文獻

  • 凌徵:"300 毫秒點擊延遲的來龍去脈".[Online]Available://thx.github.io/mobile/300ms-click-delay(2020).
  • "view".[Online]Available://developers.weixin.qq.com/miniprogram/dev/component/view.html(2020).
視圖容器 view 簡介,使用 view 搞定所有常見的 UI 佈局

這是《2020年小程序開發實踐》專欄的一部分:

www.yishulun.com/post/DwHiQLxx2/


分享到:


相關文章: