wepy一些問題和解決方案


wepy一些問題和解決方案

小程序開發和傳統的web開發有相識的地方,但是也有不同的地方,要區分。

computed屬性名和props屬性名重復

  • 如果那個組件的渲染值是重名的computed屬性,每次點擊都是之前的計算加上最新計算的值
  • 定義computed屬性名的時候避免和props屬性名重復

父子組件傳值和Vue中的區別

  • Vue中的prop傳值默認是只要父組件的數據改變,子組件同時改變,但是這種模式在wepy中是靜態的 也即 :name="name"是靜態的,父組件改變name子組件還是不會變,子組件還是父組件第一次傳進來的值
  • wepy要做到父組件數據變的同時,子組件也跟着變,要加個修飾符.sync,也即:name.sync="name"
  • 還有一個是雙向綁定的問題,Vue中可以通過$emit事件的方式實現,這里wepy可以在子組件中的props配置類型、默認值、以及是否雙向中的twoWaytrue,就實現了雙向數據流
  • 默認twoWay的值是false,如果不是特別需要,請按單向數據的方式傳遞數據最好,再配合$emit、$broadcast、$invoke,盡量少用,除非是表單這種

如何給當前自定義組件或者頁面類添加靜態屬性

  • 可以在constructor構造函數中添加靜態屬性,但是要添加super(),才可以使用this來添加靜態屬性
  • 由於constructor執行時間比較早,所有在這里面的變量,可以直接用於wepy組件,也就是可以和data的數據一樣用於數據綁定,但是原生組件只能放在data
  • 如果有些數據是一次性的,不會改變的(靜態),最好在constructor中定義,不要都放到data中,data中的數據都會被轉換成Observable數據的

組件與組件通信$broadcast、$emit、$invoke

  • 這些方法不可以在constructor調用,可以在onLoad中調用
  • events用於定義事件,用於接收用的
  • 如果想傳數據給子組件,可以使用$broadcast('eventName', ...args),但是所有的后代組件都會觸發該事件,如果后代組件的events.eventName有定義到,會調用其函數,並將args傳給其函數
  • 如果想傳數據給父組件可以使用$emit,同理,父組件(到根組件)的events要事先定義好事件
  • $broadcast和$emit都會一次觸發多個事件,定義events的時候要注意
  • $invoke('./componentName', 'methodName', args)可以直接調用指定組件的方法methods中定義的方法,如果是調用父組件可以用../往上層走,如果要調用下層的./oneLevelComponentName/twoLevelComponentName
  • 如果有很多組件都公用一個方法methods或者events,還可以使用mixins

區分Page、App、Component、Mixin這些實例

  • 有些生命周期鈎子是那個實例特有的,有些生命周期是所有都共享的

components不同於Vue或React的組件

  • 小程序的組件和Vue和React組件是有區別的
  • 在wepy中引入組件在components中,和Vue的一樣,但是使用的時候是不同的,一個組件對應一個id,如果在同一個模板中使用同一組件超過2次,它們會共享數據
  • 共享數據指的是props等,可以測試一下,同一個組件傳入的props名一樣,值不一樣,最終所有組件那的那個props值是最后一個值
  • 因為它們共享同一個props,多個組件一起使用,類似定義多個同名的函數一樣,最后使用的是最后一個函數
  • 為了避免這種情況下可以用同一個組件去定義多個組件名{ coma: Button, comb: Button },實際上就是new多一個Button
  • 也就是說小程序中的組件在使用的時候,不會自動地new一個新的組件,而是同一個組件,而像Vue和React這樣的組件,它們會new一個新的Button實例
  • 還有一種情況是,在循環體<repeat>中,在小程序中就會去new一個新的組件實例,如果你的內容重復,又不想定義多個組件名(new 多個組件),可以使用循環體<repeat>
  • 還有一種情況是slot,如果那個組件和數據無關,只是單純的用於slot模板,它們最終生成的標簽是不同的,因為這些生成的模板和數據無關,如果生成的模板中包含數據,那生成那部分關聯數據的元素都是一樣的
  • 這里說的數據是<view class='{{ className }}' >{{ data }}</view>這些花括號中的數據classNamedata,它們是共享的,所以它們最終生成的視圖是一模一樣的
  • 小程序的組件和目前流行的web組件有很大的區別,不能老用web組件傳值得思維思考(很多莫名的bug),多從廣播(訂閱)的角度思考

repeat注意點

  • 分兩種情況
//repeat包着元素view text等
<repeat for="{{mylist}}">
  <view>{{item.name}}</view>
</repeat>

//repeat包着自定義組件
<repeat for='{{myList}}'>
  <List :mylist.sync="mylist"></List>
  <Item :item='item'></Item>
</repeat>
  • 不支持在repeat的組件中使用propscomputedwatch等特性
  • 在使用repeat的時候,盡量使用純文本渲染的組件,純組件
  • 原生組件的情況下,可以使用.或者[]的方式選擇想傳的數據,但是自定義組件不可以,要整個數據傳入,或者傳入item([{}, {}]這種格式的數據),item就是wx:item
  • 數據源要在data中,才有效果,靜態屬性不行
  • 盡量只包含一個組件,出現多個組件,會出現莫名的bug,其它的功能再在這一個組件內部處理,然后組件間的通信通過$broadcast、$emit、$invoke
  • 使用組件多使用$broadcast、$emit、$invoke的方式傳值,別老想着使用props,會有很多莫名的bug
  • 關於$broadcast、$emit、$invoke,可以通過mixins拯救一下,唯一沒什么莫名bug的

Object.create(null)

  • 上面返回的對象不帶原型鏈,也即不包含Object原生對象的信息
  • 小程序中一些數據,像data需要的對象要帶原型鏈,不能用這個,否則在綁定數據到模板的時候會報錯

字符串雙引號""和單引號''

  • 在模板中務必使用"",別用''
  • :age='2':age="2",前面的''是傳不了2age的,除非使用"2"
  • 在模板中最外層字符串最好用""不要使用'',比如定義事件函數的時候'handlerTap("123")',這里是不成功的給handlerTap傳遞參數"123",但是"handlerTap('123')"就可以
  • 正確用法:@tap="handlerTap('love')",最外層用"",最內層''

mixins的computed順序問題

  • mixins中的computed執行順序和vue的相反,也即先執行component或者頁面的定義的,然后再執行mixins中的
  • 還有就是延遲的問題,mixins的慢於組件或者當前頁面定義的,如果想在當前頁面獲取mixins的一些值,會獲取不到

組件傳值和模板綁定問題

  • 一個是上面提到的字符串要用雙引號
  • 然后就是要區分原生組件和自定義組件

原生組件:就是小程序自帶的組件<view>、<text>、<image>等等,這些原生組件綁定數據,要求數據必須在data中,如果綁定的數據不在data中將不會渲染

<template>
  <view class="{{className}}">{{text}}</view>
</template>

<script>
import wepy from 'wepy'

// 注意:這個是組件實例
export default class Test extends wepy.component {
  data = {
    text: 123,
    className: 'hahah'
  }
  
  // 由於computed最后返回值會成為data中一部分,computed也可以用於原生組件數據綁定
  // 但是在repeat的時候,不可以使用這個,repeat的時候不可以使用computed和watch
  computed = {
    text () {
      return this.text + 1
    }
  }
}
</script>

自定義組件:綁定數據可以是data中,也可以用自定義函數,或者靜態變量來綁定數據,且綁定數據的方式要和原生小程序的一樣,不能用vue的方式

<template>
  <UserComponent :fn="fn()" :staticV="staticVar" :text="text"/>
</template>

<script>
import wepy from 'wepy'

// 注意:這個是頁面實例
export default class Index extends wepy.page {
  constructor () {
    super()
    this.staticVar = 123
  }

  data = {
    text: 123
  }
  
  // 自定義函數
  fn () {
    return '123'
  }
  
  // 由於computed最后返回值會成為data中一部分,computed也可以用於原生組件數據綁定,如果和data中的屬性重名,優先使用computed的
  computed = {
    text () {
      return this.text + 1
    }
  }
}
</script>

原生組件的綁定只能是data中的數據,不可以像vue中的那樣綁定數據,但是如果是自定義的組件就可以像vue那樣綁定數據。還有methods自能用於定義事件處理程序,不能把自定義函數定義在里面

也就是碰到原生組件的時候,請用原生小程序的方式處理,碰到自定義組件的時候才考慮用你vue的方式處理,也就是區分原生組件和自定義組件非常重要

圖片和導航的路徑問題

  • 不要在組件中使用相對定位,如../這種,因為當組件被引入到某個頁面時,會相對哪個頁面,導致路徑無法復用
  • 使用絕對定位,/,在小程序中,/是指的當前項目的文件夾,例如:/pages/index,這里的首個字符/就相當於@/都是指向/src目錄
  • 如果是圖片,如@/assets/icons/logo.png可以用/assets/icons/logo.png,因為第一個字符是/就相當於@/,表示/src目錄之下
  • 如果是導航wx.navigateTo,如果導航到/pages/user,不要使用/或者../,直接user,最終會自動拼成/pages/user,也就是說微信默認/pages/+user

canvas中的canvas-id不能動態賦值

  • 可以通過slot來實現一個組件,不同canvas-id
  <component-name sid="canvas">
    <canvas canvas-id="canvas"></canvas>
  </component-name>
  • component-name是一個組件,接收sid只要是為了可以wx.createCanvasContext(this.sid)
  • 其實我們在組件的內部只需要知道canvas的id,並且調用wx.createCanvasContext(this.sid),所以我們可以把canvas獨立成slot

在一個組件中引入另一個組件作為子組件,子組件的樣式<style>不起作用

  • 是因為父組件沒有<style>標簽,導致子組件不編譯<style>標簽的內容
  • 最好還是每個組件都添加<style>標簽,即使里面沒有內容


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM