1.bindtab和catchtab,catchtab能夠阻止事件冒泡html
<view bindtap='onClick'></view> <view catchtap='onClick'></view>
2.互斥事件綁定 mut-bindreact
一個 mut-bind 觸發後,若是事件冒泡到其餘節點上,其餘節點上的 mut-bind 綁定函數不會被觸發,但 bind 綁定函數和 catch 綁定函數依舊會被觸發。json
在想要規定冒泡區間時能夠用到。小程序
<view mut-bind:tap='onClick'></view>
<view mark:myMark="last" bindtap="bindViewTap"> <button mark:anotherMark="leaf" bindtap="bindButtonTap">按鈕</button> </view>
在上述 WXML 中,若是按鈕被點擊,將觸發 bindViewTap 和 bindButtonTap 兩個事件,事件攜帶的 event.mark 將包含 myMark 和 anotherMark 兩項。緩存
Page({ bindViewTap: function(e) { e.mark.myMark === "last" // true e.mark.anotherMark === "leaf" // true } })
mark 和 dataset 很類似,主要區別在於:app
1.mark能夠冒泡,若是存在同名的 mark ,父節點的 mark 會被子節點覆蓋。xss
2.在自定義組件中接收事件時, mark 不包含自定義組件外的節點的 mark。函數
3.不一樣於 dataset ,節點的 mark 不會作連字符和大小寫轉換。性能
我的理解 .wxs文件就至關於cocos的prefab。執行起來比js性能要快。可是wxs是一門語言,平行於JavaScript。動畫
有頻繁用戶交互的效果在小程序上表現是比較卡頓的,這時建議使用wxs,爲何?
由於小程序分爲視圖層和邏輯層,好比須要拖動的功能,touchmove事件從視圖層拋到邏輯層,邏輯層通過處理,經過this.setData到視圖層。
1. 一次 touchmove 的響應須要通過 2 次的邏輯層和渲染層的通訊以及一次渲染,通訊的耗時比較大。
2. 此外 setData 渲染也會阻塞其它腳本執行,致使了整個用戶交互的動畫過程會有延遲。
WXS 函數的除了純邏輯的運算,還能夠經過封裝好的ComponentDescriptor 實例來訪問以及設置組件的 class 和樣式,對於交互動畫,設置 style 和 class 很方便。
var wxsFunction = function(event, ownerInstance) { var instance = ownerInstance.selectComponent('.classSelector') // 返回組件的實例 instance.setStyle({ "font-size": "14px" // 支持rpx }) instance.getDataset() instance.setClass(className) // ... return false // 不往上冒泡,至關於調用了同時調用了stopPropagation和preventDefault }
上邊在分析複雜交互時咱們知道,頻繁的調用this.setData會使頁面卡頓,甚至致使小程序僵死。那麼不想寫或者說不會寫wxs的開發者該怎麼辦呢?
此時能夠經過將頁面的 setData 改成 自定義組件 中的 setData 來提高性能。
緣由:自定義組件中的setData不會進行深複製。(深複製會在這個值被組件間傳遞時才發生)
1.在組件wxss中不該使用ID選擇器、屬性選擇器和標籤名選擇器,就只使用class選擇器準沒錯。
2.在自定義組件的 js 文件中,須要使用 Component() 來註冊組件。
3.使用已註冊的自定義組件前,首先要在頁面的 json 文件中進行引用聲明。
4.自定義組件和頁面所在項目根目錄名不能以「wx-」爲前綴,不然會報錯。
5.<slot></slot>
至關於react的this.props.children。
<!-- component-tag-name組件 --> <view class="wrapper"> <view>這裏是組件的內部節點</view> <slot></slot> </view>
<!-- 引用組件的頁面模板 --> <view> <component-tag-name> <!-- 這部份內容將被放置在組件 <slot> 的位置上 --> <view>這裏是插入到組件slot中的內容</view> </component-tag-name> </view>
6.默認狀況下,一個組件的wxml中只能有一個slot。須要使用多slot時,能夠在組件js中聲明啓用。
Component({ options: { multipleSlots: true // 在組件定義時的選項中啓用多slot支持 }, properties: { /\* ... \*/ }, methods: { /\* ... \*/ } })
此時,能夠在這個組件的wxml中使用多個slot,以不一樣的 name 來區分。
<!-- 組件模板 --> <view class="wrapper"> <slot name="before"></slot> <view>這裏是組件的內部細節</view> <slot name="after"></slot> </view>
使用時,用 slot 屬性來將節點插入到不一樣的slot上。
<!-- 引用組件的頁面模板 --> <view> <component-tag-name> <!-- 這部份內容將被放置在組件 <slot name="before"> 的位置上 --> <view slot="before">這裏是插入到組件slot name="before"中的內容</view> <!-- 這部份內容將被放置在組件 <slot name="after"> 的位置上 --> <view slot="after">這裏是插入到組件slot name="after"中的內容</view> </component-tag-name> </view>
7.設置自定義組件的捕獲和冒泡機制須要使用 triggerEvent 方法。
// 組件 my-component.js Component({ methods: { onTap: function(){ this.triggerEvent('customevent', {}, { bubbles: true, composed: true }) } } })
我的理解:多個頁面可能會共用一個功能,這個功能抽象後稱爲組件。
多個組件共用一個方法或者多個方法,這類方法的集合稱爲behaviors。就tm理解成高階組件就完了。
官方說:有時須要實現這樣的組件:
<custom-ul> <custom-li> item 1 </custom-li> <custom-li> item 2 </custom-li> </custom-ul>
說custom-ul 和 custom-li 都是自定義組件,它們有相互間的關係,相互間的通訊每每比較複雜。具體怎麼個複雜須要單獨拎出來一個ralations屬性來處理,咱也不知道。
使用方法:
// path/to/custom-ul.js Component({ relations: { './custom-li': { type: 'child', // 關聯的目標節點應爲子節點 linked: function(target) { // 每次有custom-li被插入時執行,target是該節點實例對象,觸發在該節點attached生命週期以後 }, linkChanged: function(target) { // 每次有custom-li被移動後執行,target是該節點實例對象,觸發在該節點moved生命週期以後 }, unlinked: function(target) { // 每次有custom-li被移除時執行,target是該節點實例對象,觸發在該節點detached生命週期以後 } } },
// path/to/custom-li.js Component({ relations: { './custom-ul': { type: 'parent', // 關聯的目標節點應爲父節點 linked: function(target) { // 每次被插入到custom-ul時執行,target是custom-ul節點實例對象,觸發在attached生命週期以後 }, linkChanged: function(target) { // 每次被移動後執行,target是custom-ul節點實例對象,觸發在moved生命週期以後 }, unlinked: function(target) { // 每次被移除時執行,target是custom-ul節點實例對象,觸發在detached生命週期以後 } } } })
注意:必須在兩個組件定義中都加入relations定義,不然不會生效。
還有一種狀況,若是你兩個自定義組件都用了相同的behaviors,你可使用這個behavior來代替組件路徑做爲關聯的目標節點。
// path/to/custom-form.js var customFormControls = require('./custom-form-controls') Component({ relations: { 'customFormControls': { type: 'descendant', // 關聯的目標節點應爲子孫節點 target: customFormControls } } })
官方定義他叫數據監聽器,呵呵。
使用方法:
Component({ attached: function() { this.setData({ numberA: 1, numberB: 2, }) }, observers: { 'numberA, numberB': function(numberA, numberB) { // 在 numberA 或者 numberB 被設置時,執行這個函數 this.setData({ sum: numberA + numberB }) } } })
若是須要監聽全部子數據字段的變化,可使用通配符 。
Component({ observers: { 'some.field.**': function(field) { // 使用 setData 設置 this.data.some.field 自己或其下任何子數據字段時觸發 // (除此之外,使用 setData 設置 this.data.some 也會觸發) field === this.data.some.field }, }, attached: function() { // 這樣會觸發上面的 observer this.setData({ 'some.field': { /* ... */ } }) // 這樣也會觸發上面的 observer this.setData({ 'some.field.xxx': { /* ... */ } }) // 這樣仍是會觸發上面的 observer this.setData({ 'some': { /* ... */ } }) } })
特別地,僅使用通配符 能夠監聽所有 setData 。**
就是局部變量,不參與渲染,也不會傳遞。
官方說這樣聲明後再用能提升性能,要不我纔不用。
使用方式:
Component({ options: { pureDataPattern: /^_/ // 指定全部 _ 開頭的數據字段爲純數據字段 }, data: { a: true, // 普通數據字段 _b: true, // 純數據字段 }, methods: { myMethod() { this.data._b // 純數據字段能夠在 this.data 中獲取 this.setData({ c: true, // 普通數據字段 _d: true, // 純數據字段 }) } } })
又一個新名詞,呵呵呵。
說白了就是有一個父容器組件A,由於條件不一樣有可能A中會渲染組件B,也可能渲染組件C。舉個例子,當頁面須要單選和多選組件的時候,方法1是按條件引用兩個封裝好的組件(<單選/>,</多選>),方法2是你也能夠只引用一個組件<啦啦啦/>,只不過這個<啦啦啦/>組件去幫你按需渲染<單選/>或者<多選/>。
須要在父容器組件A的.json文件聲明:
{ "componentGenerics": { "selectable": true } }
在使用組件時,必須指定父組件具體是渲染哪一個子組件:
<啦啦啦 generic:selectable="單選" />
<啦啦啦 generic:selectable="多選" />
在頁面的.json文件<啦啦啦/>,<單選/>,<多選/>都要引用。代碼
//page下頁面的.json文件中 { "usingComponents": { "啦啦啦": "path/*/*", "多選": "*/checkbox", "單選": "*/radio" } }
固然,你也能夠在容器組件.json中指定默認用哪一個組件:
{ "componentGenerics": { "selectable": { "default": "*/checkbox"// 多選 } } }
今天真是開眼了,學到了這麼多新詞彙。。
( 計算屬性的做用):是爲了解決HTML代碼中複雜的js代碼(HTML代碼中能夠嵌套js代碼),把複雜的js代碼經過計算屬性來解決
這是計算屬性的應用??? 聽着詞這麼厲害幹這事真是大才小用了。
計算屬性會使用緩存機制,若是這個數據的值沒有改變,則計算屬性將不會調用方法
這點應該是它實際有價值的地方。
實現原理很簡單,就是對已有的 setData 進行二次封裝,在每次 setData 的時候計算出 computed 裏各字段的值,這期間能夠增長緩存機制,屬性值沒有變化的複用。
在react中想拓展一個組件怎麼辦,會用高階組件。
小程序中,天然是使用behaviors。
// behavior.js module.exports = Behavior({ definitionFilter(defFields) { defFields.data.from = 'behavior' }, }) // component.js Component({ data: { from: 'component' }, behaviors: [require('behavior.js')], ready() { console.log(this.data.from) // 此處會發現輸出 behavior 而不是 component } })
Behavior() 構造器提供了新的定義段 definitionFilter ,用於支持自定義組件擴展。