• 中文
  • ENGLISH
Rax深入淺出 – 樣式編寫
2017/02/09

前面開篇里提到過,使用Rax/Weex構建的是:一個移動端·跨平臺應用

那么,從樣式編寫的角度,該如何看待移動端跨平臺這兩個Rax/Weex特性?

  • 移動端:寬高/邊距,甚至是字體大小等樣式,需要能夠適配不同屏幕尺寸的手機
  • 跨平臺:同一份樣式代碼需要能夠同時在Web/IOS/Android平臺上運行

面對上述的問題,其實在以往的Web App實踐中,已經有了一些類似的經驗沉淀:

  • 通過「rem」「flexbox」可以做到手機屏幕適配
  • 通過「css in js」的方式,讓JS擁有描述樣式的能力,從而做到將同一份代碼運行在不同的JS Engine里(拋棄了原來Web固有的CSS樣式表)

Rax/Weex也正是基于類似上述的思路實現了對應樣式API,接下來主要以Rax為例介紹如何編寫樣式。

基礎

Rax提供的大多數元件都支持style屬性,用來初始化或修改元素樣式,就像原生html標簽的style屬性一樣(<img style="width:40px" />),對比下Rax的樣式編寫方式:

// 定義樣式集合
const styles = {
  container: {
    padding: '20rem',
    height: '300rem',
    fontSize: '28rem',
    backgroundColor: 'red'
  },
  container_title: {
    color: '#fff',
    fontSize: '32rem' // font-size不會繼承父或祖先元素,需重新定義
  }
};

// 應用樣式
const App = (props) => {
  return (
    <View style={styles.container}>
      <Text style={styles.container_title}>Hello World</Text>
    </View>
  );
};

與原生的html標簽style屬性不同,Rax元件接收的style屬性類型是一個對象

受限于Native元素渲染方式,元件之間的嵌套關系并不會帶來樣式繼承的效果,因此上述例子中定義了一個樣式集合,各自描述對應元素的樣式(比如:fontSize)。

關于適配

在傳統的Web中,根據手機屏幕寬度的值,動態改變html font-size,再結合rem單位對不同尺寸的手機屏幕進行適配(對于樣式數值的轉換,往往會通過sass/less來進行預編譯)。

而在Weex/Rax中,同樣是根據手機屏幕寬度,由于樣式已經通過「css in js」的方式引入,所以動態轉換用戶傳遞參數(樣式數值)就可以達到適配的目的(這里的數值轉換,與之前的不同,因為發生在javascript運行時)。

如何方便的還原視覺稿?

一般設計師給到前端同學的,都是以iPhone6為樣板的雙倍高清設計稿,所以適配方案的對應的基準寬度就是375 * 2 = 750,對應的樣式數值轉換公式類似如下(以Web為例):

outpuValue = inputValue * (document.documentElement.clientWidth / 750);

對于一個設計稿上,寬高400×200的div,它對應的樣式代碼以Rax書寫方式為例:

const style = {
    width: '400rem',
    height: '200rem'
};

通過Rax內部執行,最終呈現在不同的手機屏幕上的真實寬高,如下:

機型 屏幕寬度 div真實寬高
iPhone5 320px 170.7×85.3
iPhone6(設計稿) 375px 200×100
iPhone6+ 414px 220.8×110.4

也就是說:我們在 750 的設計稿上量到的數值是多少,代碼編寫就寫多少(方便了很多,省去了心算)。

關于布局

在Weex/Rax中,不再支持float布局,取而代之的是flexbox布局(對于移動端而言,理應如此)。

更多關于「Weex Flexbox」,詳見這里。

關于單位

Weex只支持px長度單位,不支持相對單位(em、rem),并且它將在JavaScript運行時和本機渲染器中解析為數字類型,所以省略px 單位后綴,直接寫數字也是可以的。

/* 以下兩種寫法,效果是一樣的,更推薦帶單位的寫法 */
.classA { font-size: 48; line-height: 64; }
.classB { font-size: 48px; line-height: 64px; }

而Rax支持兩種單位:pxrem,或者不帶單位后綴。

const styles = {
    borderWidth: '1px',
    height: '100rem',
    width: 750
};

如何理解?

Rax在Web端,重寫了H5-RenderEngine;在Native端,底層調用的仍是Weex-RenderEngine(IOS/Android)。

在將具體的元素樣式,傳遞給Weex之前,Rax針對單位做了一層處理,轉換規則(這里假設手機屏幕寬度/deviceWidth為375px),如下:

類型 Rax-Web Weex-Native
無單位 750 ‘375px’ ‘750px’
rem為單位 ‘100rem’ ’50px’ ‘100px’
px為單位 ‘1px’ ‘1px’ ‘1px’

Rax中依然推薦使用帶單位的方式,如:{ width: '750rem', borderWidth: '1px' },比較直觀。

結論:

  • Rax依靠Weex的Native渲染能力,所以這里的Weex-Native指的是Rax調用Weex SDK API渲染UI時,傳的樣式值,關于Native的具體的適配處理由Weex-renderEngine完成。
  • 在Rax中,如果數值單位是px,那么數值是不會根據手機屏幕做數值轉換的,如:{ borderWidth: '1px' } 在deviceWidth為375px的手機上,不會變成{ borderWidth: '0.5px' },這其實很好的解決了很多Android手機在Web端因為不支持0.5px而導致線條無法呈現的問題,但同時也會使得一些原本支持0.5px的IOS手機得不到細線條的美感,倘若你真的追求極致的web端優雅降級,可以在html頁面中引入「lib-flexible.js」通過頁面scale的方式,支持IOS border 0.5px。

關于顏色

Weex/Rax支持多種格式的顏色值書寫方式,基本對準了W3C標準,以Weex書寫方式為例:

.my-class { color: red; }                  /* 色值關鍵字 */
.my-class { color: #f00; }                 /* 精簡十六進制*/
.my-class { color: #ff0000; }              /* 十六進制 */
.my-class { color: rgb(255, 0, 0); }       /* RGB */
.my-class { color: rgba(255, 0, 0, 0.5); } /* RGBA */

一般情況下,不推薦使用「色值關鍵字」

高階

事實上,在項目開發過程中,如果將所有的樣式代碼都寫在JS文件里,會發現代碼看起來很臃腫,或許我們更習慣于:分離樣式代碼

Webpack的誕生,推動了前端自動化工具的發展的同時,也加速了我們對前端的認知,不用再去一直等待標準規范的完全實現,有很多這樣的例子:

  • babel-loader:jsx/es6/es7轉換成es5
  • sass/less-loader:sass/less轉換成css
  • vue-loader:實現了SFC(Single File Components)
  • weex-loader:實現了SFC的同時,還注入了__weex_require__(可以引用Native Module)

所以,代碼的寫法已經不受太多約束,因為可以有很多插件去支撐一個靠譜的想法。

同樣的,Rax也提供了這么一個Webpack插件 – 「stylesheet-loader」,讓我們能夠在Rax應用中通過CSS寫樣式。

就像下面這樣:

/* hello-world.css */

.container {
  padding: 20rem;
  height: 300rem;
  background-color: red;
}

.container_title {
  color: #fff;
  font-size: 32rem;
  border-width: 1px;
}

如何引入?

/* hello-world.js */
import styles from './hello-world.css';

webpack配置

{
    test: /\.css$/,
    loader: 'stylesheet'
}

除了樣式代碼的分離,少寫幾個引號之外,stylesheet-loader的好處還在于:

  • 對于Weex不支持的樣式,能快速給予友好的warning提示
  • 可以跟sass/less-loader結合,使用變量、mixin、嵌套等預編譯功能

warning提示

比如:Weex不支持floatz-index樣式,那么stylesheet-loader會提示:

warning.png

用sass寫樣式

/* hello-world.scss */

/* 變量 */
$fontSize: 32rem;

/* 嵌套 */
.container {
  padding: 20rem;
  height: 300rem;
  background-color: red;
  .title {
    color: #fff;
    font-size: $fontSize;
    border-width: 1px;
  }
}

NOTE:默認情況下,stylesheet-loader不支持嵌套,即不支持.container .title { ... }的轉換,需要開啟一個配置項:transformDescendantCombinator,嵌套變量名將以_連接,如下:

.container .title { ... }

/* 轉換成 -> */

.container_title { ... }

所以,一個完整的配置如下:

{
  test: /\.scss$/,
  loaders: [
    'stylesheet?transformDescendantCombinator',
    'sass'
  ]
}

參考資料

訂閱我們
体彩20选5开奖结果查询 有手机就能赚钱的软件是什么软件 在福鼎开出租车赚钱吗 神武2手游如何快速赚钱之道 美人捕鱼漏洞刷分 商业策划赚钱 恩施民宿赚钱吗 捕捕鱼来了官网 自带面包车送货做什么最赚钱 最新手机赚钱app 万家彩票安卓 网上答题赚钱么 卖二手车员工赚钱吗 真人打麻将赢钱版平台 可以赚钱又好玩的pk手游 用微信赚钱的手游 激战2锻造赚钱