网友真实露脸自拍10p,成人国产精品秘?久久久按摩,国产精品久久久久久无码不卡,成人免费区一区二区三区

小程序模板網

Taro實踐 - TOPLIFE小程序 開發體驗

發布時間:2018-07-05 09:47 所屬欄目:小程序開發教程

前陣子,來自我們凹凸實驗室的遵循React 語法規范的 多端開發方案 - Taro 終于對外開源了,歡迎圍觀 star (先打波廣告)。作為第一批使用了 Taro 開發的TOPLIFE小程序的開發人員之一,自然是走了不少彎路,躺了不少坑,也幫忙找過不少bug。現在項目總算是上線了,那么,也是時候給大家總結分享下了。

與WePY比較

當初開發TOPLIFE第一期的時候,用的其實是 WePY (那時Taro還沒有開發完成),然后在第二期才全面轉換為用 Taro 開發。作為兩個小程序開發框架都使用過,并應用在生產環境里的人,自然是要比較一下兩者的異同點。

相同點

  • 組件化開發
  • npm包支持
  • ES6+特性支持,Promise, Async Functions 等
  • CSS預編譯器支持,Sass/Stylus/PostCSS等
  • 支持使用Redux進行狀態管理
  • …..

相同的地方也不用多說什么,都2018年了,這些特性的支持都是為了讓小程序開發變得更現代,更工程化,重點是區別之處。

不同點

  • 開發風格
  • 實現原理
  • WePY支持slot,Taro暫不支持直接渲染children

開發風格

最大的不同之處,自然就是開發風格上的差異, WePY 使用的是類Vue開發風格, Taro 使用的是類React 開發風格,可以說開發體驗上還是會有較大的區別。貼一下官方的demo簡單闡述下。

WePY demo

<style lang="less">
    @color: #4D926F;
    .userinfo {
        color: @color;
    }
</style>
<template lang="pug">
    view(class='container')
        view(class='userinfo' @tap='tap')
            mycom(:prop.sync='myprop' @fn.user='myevent')
            text {{now}}
</template>

<script>
    import wepy from 'wepy';
    import mycom from '../components/mycom';

    export default class Index extends wepy.page {
        
        components = { mycom };
        data = {
            myprop: {}
        };
        computed = {
            now () { return new Date().getTime(); }
        };
        async onLoad() {
            await sleep(3);
            console.log('Hello World');
        }
        sleep(time) {
            return new Promise((resolve, reject) => setTimeout(resolve, time * 1000));
        }
    }
</script>

Taro demo

import Taro, { Component } from '@tarojs/taro'
import { View, Button } from '@tarojs/components'

export default class Index extends Component {
  constructor () {
    super(...arguments)
    this.state = {
      title: '首頁',
      list: [1, 2, 3]
    }
  }

  componentWillMount () {}

  componentDidMount () {}

  componentWillUpdate (nextProps, nextState) {}

  componentDidUpdate (prevProps, prevState) {}

  shouldComponentUpdate (nextProps, nextState) {
    return true
  }

  add = (e) => {
    // dosth
  }

  render () {
    return (
      <View className='index'>
        <View className='title'>{this.state.title}</View>
        <View className='content'>
          {this.state.list.map(item => {
            return (
              <View className='item'>{item}</View>
            )
          })}
          <Button className='add' onClick={this.add}>添加</Button>
        </View>
      </View>
    )
  }
}

可以見到在 WePY 里, css 、 template 、 script 都放在一個wpy文件里, template 還支持多種模板引擎語法,然后支持 computed 、 watcher 等屬性,這些都是典型的Vue風格。

而在 Taro 里,就是徹頭徹尾的 React 風格,包括 constructor , componentWillMount 、 componentDidMount 等各種 React 的生命周期函數,還有 return 里返回的 jsx ,熟悉 React 的人上手起來可以說是非常快了。

除此之外還有一些細微的差異之處:

  • WePY 里的模板,或者說是 wxml ,用的都是小程序里原生的組件,就是小程序文檔里的各種組件;而Taro里使用的每個組件,都需要從 @tarojs/components 里引入,包括 View , Text 等基礎組件(這種做其實是為了轉換多端做準備)
  • 事件處理上
    • Taro 中,是用 click 事件代替 tap 事件
    • WePY使用的是簡寫的寫法@+事件;而Taro則是on+事件名稱
    • 阻止冒泡上WePY用的是@+事件.stop;而Taro則是要顯式地使用 e.stopPropagation()來阻止冒泡
    • 事件傳參WePY可以直接在函數后面傳參,如 @tap="click({{index}})" ;而Taro則是使用 bind 傳參,如 onClick={this.handleClick.bind(null, params)}
  • WePY使用的是小程序原生的生命周期,并且組件有 page 和 component 的區分;Taro 則是自己實現了類似React 的生命周期,而且沒有 page 和 component 的區分,都是 component

總的來說,畢竟是兩種不同的開發風格,自然還是會有許多大大小小的差異。在這里與當前很流行的小程序開發框架之一 WePY 進行簡單對比,主要還是為了方便大家更快速地了解 Taro ,從而選擇更適合自己的開發方式。

實踐體驗

Taro 官方提供的demo 是很簡單的,主要是為了讓大家快速上手,入門。那么,當我們要開發偏大型的項目時,應該如何使用 Taro 使得開發體驗更好,開發效率更高?作為深度參與TOPLIFE小程序開發的人員之一,談一談我的一些實踐體驗及心得

如何組織代碼

使用taro-cli生成模板是這樣的

├── dist                   編譯結果目錄
├── config                 配置目錄
|   ├── dev.js             開發時配置
|   ├── index.js           默認配置
|   └── prod.js            打包時配置
├── src                    源碼目錄
|   ├── pages              頁面文件目錄
|   |   ├── index          index頁面目錄
|   |   |   ├── index.js   index頁面邏輯
|   |   |   └── index.css  index頁面樣式
|   ├── app.css            項目總通用樣式
|   └── app.js             項目入口文件
└── package.json

假如引入了redux,例如我們的項目,目錄是這樣的

├── dist                   編譯結果目錄
├── config                 配置目錄
|   ├── dev.js             開發時配置
|   ├── index.js           默認配置
|   └── prod.js            打包時配置
├── src                    源碼目錄
|   ├── actions            redux里的actions
|   ├── asset              圖片等靜態資源
|   ├── components         組件文件目錄
|   ├── constants          存放常量的地方,例如api、一些配置項
|   ├── reducers           redux里的reducers
|   ├── store              redux里的store
|   ├── utils              存放工具類函數
|   ├── pages              頁面文件目錄
|   |   ├── index          index頁面目錄
|   |   |   ├── index.js   index頁面邏輯
|   |   |   └── index.css  index頁面樣式
|   ├── app.css            項目總通用樣式
|   └── app.js             項目入口文件
└── package.json

TOPLIFE小程序整個項目大概3萬行代碼,數十個頁面,就是按上述目錄的方式組織代碼的。比較重要的文件夾主要是 pages 、 components 和 actions 。

  • pages里面是各個頁面的入口文件,簡單的頁面就直接一個入口文件可以了,倘若頁面比較復雜那么入口文件就會作為組件的聚合文件, redux 的綁定一般也是在這里進行。

  • 組件都放在 components 里面。里面的目錄是這樣的,假如有個 coupon 優惠券頁面,在 pages 自然先有個 coupon ,作為頁面入口,然后它的組件就會存放在 components/coupon 里面,就是 components 里面也會按照頁面分模塊,公共的組件可以建一個 components/public 文件夾,進行復用。

    這樣的好處是頁面之間 互相獨立 , 互不影響 。所以我們幾個開發人員,也是按照頁面的維度來進行分工,互不干擾,大大提高了我們的開發效率。

  • actions這個文件夾也是比較重要,這里處理的是拉取數據,數據再處理的邏輯。可以說,數據處理得好,流動清晰,整個項目就成功了一半,具體可以看下面***更好地使用redux***的部分。如上,假如是 coupon 頁面的 actions ,那么就會放在 actions/coupon 里面,可以再一次見到,所有的模塊都是以頁面的維度來區分的。

除此之外, asset 文件用來存放的靜態資源,如一些icon類的圖片,但建議不要存放太多,畢竟程序包有限制。而 constants 則是一些存放常量的地方,例如 api 域名,配置等等。

只要按照上述或類似的代碼組織方式,遵循規范和約定,開發大型項目時不說能提高多少效率,至少順手了很多。

更好地使用redux

redux大家應該都不陌生,一種狀態管理的庫,通常會搭配一些中間件使用。我們的項目主要是用了 redux-thunk 和 redux-logger 中間件,一個用于處理異步請求,一個用于調試,追蹤 actions 。

數據預處理

相信大家都遇到過這種時候,接口返回的數據和頁面顯示的數據并不是完全對應的,往往需要再做一層預處理。那么這個業務邏輯應該在哪里管理,是組件內部,還是 redux 的流程里?

舉個例子:

例如上圖的購物車模塊,接口返回的數據是

{
	code: 0,
	data: {
        shopMap: {...}, // 存放購物車里商品的店鋪信息的map
        goods: {...}, // 購物車里的商品信息
        ...
	}
	...
}

對的,購車里的商品店鋪和商品是放在兩個對象里面的,但視圖要求它們要顯示在一起。這時候,如果直接將返回的數據存到 store ,然后在組件內部 render 的時候東拼西湊,將兩者信息匹配,再做顯示的話,會顯得組件內部的邏輯十分的混亂,不夠純粹。

所以,我個人比較推薦的做法是,在接口返回數據之后,直接將其處理為與頁面顯示對應的數據,然后再 dispatch 處理后的數據,相當于做了一層攔截,像下面這樣:

const data = result.data // result為接口返回的數據
const cartData = handleCartData(data) // handleCartData為處理數據的函數
dispatch({type: 'RECEIVE_CART', payload: cartData}) // dispatch處理過后的函數

...
// handleCartData處理后的數據
{
    commoditys: [{
        shop: {...}, // 商品店鋪的信息
        goods: {...}, // 對應商品信息
    }, ...]
}

可以見到,處理數據的流程在render前被攔截處理了,將對應的商品店鋪和商品放在了一個對象了.

這樣做有幾個好處

  • 一個是組件的渲染 更純粹 ,在組件內部不用再關心如何將數據修修改改而滿足視圖要求, 只需關心組件本身的邏輯 ,例如點擊事件,用戶交互等

  • 二是數據的流動 更可控 ,假如后續后臺返回的數據有變動,我們要做的只是改變 handleCartData 函數里面的邏輯,不用改動組件內部的邏輯。

    后臺數據——>攔截處理——>期望的數據結構——>組件

實際上,不只是后臺數據返回的時候,其它數據結構需要變動的時候都可以做一層數據攔截,攔截的時機也可以根據業務邏輯調整,重點是要讓組件內部本身不關心 數據與視圖是否對應,只專注于內部交互的邏輯 ,這也很符合 React 本身的初衷,數據驅動視圖。

connect可以做更多的事情

connect 大家都知道是用來連接 store 、 actions 和組件的,很多時候就只是根據樣板代碼復制一下,改改組件各自的 store 、 actions 。實際上,我們還可以做一些別的處理,例如:

export default connect(({
  cart,
}) => ({
  couponData: cart.couponData,
  commoditys: cart.commoditys,
  editSkuData: cart.editSkuData
}), (dispatch) => ({
  // ...actions綁定
}))(Cart)

// 組件里
render () {
	const isShowCoupon = this.props.couponData.length !== 0
    return isShowCoupon && <Coupon />
}

上面是很普通的一種 connect 寫法,然后 render 函數根據 couponData 里是否數據來渲染。這時候,我們可以把 this.props.couponData.length !== 0 這個判斷丟到 connect 里,達成一種 computed 的效果,如下:

export default connect(({
  cart,
}) => {
  const { couponData, commoditys, editSkuData  } = cart
  const isShowCoupon = couponData.length !== 0
  return {
    isShowCoupon,
    couponData,
    commoditys,
    editSkuData
}}, (dispatch) => ({
  // ...actions綁定
}))(Cart)

// 組件里
render () {
    return this.props.isShowCoupon && <Coupon />
}

可以見到,在 connect 里定義了 isShowCoupon 變量,實現了根據 couponData 來進行 computed 的效果。

實際上,這也是一種數據攔截處理。除了 computed ,還可以實現其它的功能,具體就由各位看官自由發揮了。

項目感受

要說最大的感受,就是在開發的過程中, 有時會忘記了自己在寫小程序,還以為是在寫React頁面 。是的,有次我想給頁面綁定一個滾動事件,才醒悟根本就沒有 doucment.body.addEventListener 這種東西。在使用 WePY 過程中,那些奇奇怪怪的語法還是時常提醒著我這是小程序,不是h5頁面,而在用 Taro 的時候,這個差異化已經被消磨得很少了。盡管還是有一定的限制,但我基本上就是用開發React的習慣來使用 Taro ,可以說極大地提高了我的開發體驗。

一些需要注意的地方

那 Taro ,或者是小程序開發,有沒有什么要注意的地方?當然有,走過的彎路可以說是非常多了。

頁面棧只有10層

  • 估計是每個頁面的數據在小程序內部都有緩存,所以做了10層的限制。帶來的問題就是假如頁面存在循環跳轉,即A頁面可以跳到B頁面,B頁面也可以跳到A頁面,然后用戶從A進入了B,想返回A的時候,往往是直接在B頁面里點擊跳轉到A, 而不是點返回 回到A,如此一來,10層很快就突破了。所以我們自己對 navigateTo 函數做了一層封裝,防止溢出。

頁面內容有緩存

  • 上面說到,頁面內容有緩存。所以假如某個頁面是根據不同的數據渲染視圖,新渲染時會有上一次渲染的緩存,導致頁面看起來有個閃爍的變化,用戶體驗非常不好。其實解決的辦法也很簡單,每次在 componentWillUnmount 生命周期中清理一下當前頁面的數據就好了。小程序說到底不是h5,不會說每次進入頁面就會刷新,也不會離開就銷毀,刷新


易優小程序(企業版)+靈活api+前后代碼開源 碼云倉庫:starfork
本文地址:http://www.xiuhaier.com/wxmini/doc/course/24621.html 復制鏈接 如需定制請聯系易優客服咨詢:800182392 點擊咨詢
QQ在線咨詢
AI智能客服 ×