企鵝電競weex實踐——UI開發篇

騰訊DeepOcean原創文章:dopro.io/egame-weex-…css

隨着電競業務的不斷髮展,頁面功能愈來愈多,交互邏輯更加複雜,相似無限滾動、上拉刷新、橫豎切換滾動等形式在業務中已經是標配,通過重重優化後在H5中的體驗一直達不到理想狀態,沒錯,種種卡,H5的性能太差! 是持續優化仍是破然後立選擇新的技術方向呢?咱們選擇了更有效的後者。

爲何選擇weex

相對H5來講,weex帶來的用戶體驗更好,它結合了H5和Native各自的優點,既能像H5同樣快速迭代,又能和Native同樣流暢。
H5 Weex Native
開發成本
維護更新 簡單 簡單 複雜
用戶體驗
發版審覈 不須要 不須要 須要
跨平臺性
項目中每一次嘗試新方案、新技術時都將面臨着許多問題,企鵝電競接入weex也不例外,咱們在使用weex進行設計還原時並非像H5同樣順利,爲了不小夥伴重複踩坑,本文將主要圍繞H5與weex的區別以及weex ui開發時遇到的問題進行說明。

H5與Weex的區別html

  • 項目結構
  • 標籤
  • 引入sass
  • sass變量
weex ui開發踩坑
  • 通用樣式
  • 佈局
  • 組件
  • 動畫
  • UI性能
 

H5與Weex的區別

項目結構

因爲weex和H5是兩套不一樣的技術方案,代碼組織方式、構建工具、和開發側對接方式都會不一樣。

下圖是電競重構稿H5與weex目錄結構對比,以前H5開發是基於jinja模版,採用grunt構建,在release中生成相應的html文件,而weex則主要在src中開發組件,採用webpack編譯,最終會在dist中生成相對應地web和weex版jsbundle文件,再由weex.html生成的二維碼查看weex版頁面效果。前端

此外weex下的src目錄內容是與開發側保持一致的,這樣的好處在於開發人員只須要關注組件的結構變化,其它資源直接更新替換便可。vue

標籤

weex只提供了17個組件,如div、text、image等,其中text和H5中p標籤等同,文字只能放到text下,text中不能嵌套其餘標籤。

引入sass

一、安裝sass依賴的npm包:sass-loader、node-sass、sass-loader、stylus-loader

二、在build文件夾下webpack.base.conf.js的rules裏面添加配置node

  1. rules:{
  2. {
  3. test: /\.(scss|css)$/,
  4. loader: 'vue-style-loader!css-loader!sass-loader!stylus-loader?indentedSyntax',
  5. }
  6. }er-width:$border.width;
  7. }
三、style中修改lang="stylus"

sass變量

weex中的sass變量相似於對象的寫法
  1. //variable.scss
  2. $border={
  3. color: #E9E9E9
  4. width:2px
  5. }
  1. @import "./variable.scss";
  2. .border{
  3. border-color:$border.color;
  4. border-width:$border.width;
  5. }
  6.  

weex ui開發踩坑

通用樣式

一、border

weex不支持使用border建立三角形,web能夠正常顯示,而ios和android上顯示的是矩形,建議使用圖片代替

web: ios、android: android

二、transform

一、rotate角度儘可能避免設置負數,某些部分安卓機型會不生效

二、不支持transform:skew 對於這一類角標須要作傾斜處理能夠採用 圖片加  漸變代碼處理webpack

三、圖片

一、weex提供了image組件,但只支持遠程圖片連接

二、避免在image標籤上使用v-for,不然會致使安卓上圖片渲染異常(如slider中的圖片)ios

四、透明度

如下是涉及到顏色的相關屬性對透明度的支持度列表,

注意:box-shadow (自己不支持android),background-image不支持IOS透明css3

屬性 IOS Android H5
color 支持 支持 支持
opacity 支持 支持 支持
border-color 支持 支持 支持
box-shadow 支持 不支持 支持
background-color 支持 支持 支持
background-image 不支持 支持 支持

五、點擊態

項目比較常見的點擊態多半是透明度的變化,如按鈕、列表、連接等,css的作法是添加僞類 (:active),weex中也一樣支持,可是weex須要在原樣式中添加 opacity:1,不然點擊後回不到初始狀態;此外,:active使用時,background-image在ios下會失效。
  1. <template>  
  2.    <div class="ui-btn">
  3.        <text class="ui-btn-text">下載</text>
  4.    </div>
  5. </template>
  6. <style scoped>
  7.    .ui-btn{
  8.        opacity: 1; /*必須添加*/
  9.    }
  10.    .ui-btn:active{
  11.        opacity: .5;
  12.    }
  13. </style>
  14.  

六、文本截斷

文本從限制1行到不限制能夠用lines:0;
  1. <template>
  2.    <text class="info-text"
  3.          @click="textClick"
  4.          :style="textStyle">城市賽戰報,《王者榮耀》城市賽鄭州站歡樂落幕城市賽戰報,《王者榮耀》城市賽鄭州站歡樂落幕城市賽戰報,《王者榮耀》城市賽鄭州站歡樂落幕城市賽戰報,《王者榮耀》城市賽鄭州站歡樂落幕</text>
  5. </template>
  6. <style scoped>
  7.    .info-text{
  8.        lines:1;
  9.        text-overflow:ellipsis;
  10.    }
  11. </style>
  12. <script>
  13.    export default {
  14.        data(){
  15.            return {
  16.                textStyle:{}
  17.            };
  18.        },
  19.        methods:{
  20.            textClick(){
  21.                this.textStyle = {
  22.                    lines:0
  23.                }
  24.            }
  25.        }
  26.    }
  27. </script>
  28. </style>
  29.  

七、層級問題

例若有a、b、c、d 四層結構,其中a、b、c均爲absolute定位,z-index由大到小,d爲普通結構,咱們知道在css中a層應該是處於最上方,d在最下方,那麼在weex中表現如何呢?
  1. <div class="wrapper">
  2. <div class="box a">a</div>
  3. <div class="box b">b</div>
  4. <div class="box c">c</div>
  5. <div class="d">d</div>
  6. </div>
  7. &nbsp;
  8.  
web   native

能夠看到web和ios、android的表現不一致,ios、android中是以代碼中dom順序來依次添加的,和z-index無關,後面加載的視圖會覆蓋前面的視圖。web

因此要保證web、ios、android三端表現一致,改變dom書寫順序便可。

  1. <div class="d"></div>
  2. <div class="box c"></div>
  3. <div class="box b"></div>
  4. <div class="box a"></div>
  5.  

八、安卓下遮擋問題

安卓下容器若是設置了寬高,那麼子元素不能超出容器範圍

[cc lang="html"]

 

[/cc]

web、ios android 

建議:fixed定位不會受父容器影響,若是須要超出限制,子元素能夠設置fixed

九、v-if問題

在作一些操做切換狀態時(如按鈕點擊置灰),應儘可能避免使用v-if,使用v-if會閃,且部分安卓機子會發生不可描述的事情(如部分三星機型會出現按鈕文字居頂),可採用添加class的方式

佈局

一、單行文本與圖片並排方案

目前項目中存在這樣的情形,暱稱與直播標籤並排,暱稱文字短時直播要跟隨,暱稱很長時要作溢出截斷(超出時加...)

這種佈局方式在css中要作到很容易,而在weex中利用提供的flex佈局確很難實現,最後的解決方案是經過js動態設置文字與標籤父級的寬度,從而控制文字的溢出

  1. <template>
  2.    <div class="wrapper"  @appear="onappear">
  3.        <div class="info-container" ref='info-container'>
  4.            <div class="info" ref='info' :class="isFullText?['info-full']:[]">
  5.                <text class="nick-text">{{isFullText}}企鵝電競企鵝電競企鵝電競企鵝電競</text>
  6.                <img src="http://119.29.8.64/vipstyle/egame/app/weex/tab/ERICKCHEN-MC0/dist/static/img/live.b467410.png" class="live-image">
  7.            </div>
  8.        </div>
  9.    </div>
  10. </template>
  11.  
  12. <style scoped lang="stylus">
  13.    .info-full{
  14.        width:300px;
  15.    }
  16. </style>
  17.  
  18. <script>
  19. const dom = weex.requireModule('dom')
  20.    export default {
  21.        data(){
  22.            return {
  23.                isFullText:false
  24.            };
  25.        },
  26.        methods:{
  27.            onappear(){
  28.                dom.getComponentRect(this.$refs['info'],option1=>{
  29.  
  30.                        dom.getComponentRect(this.$refs['info-container'],option2=>{
  31.  
  32.                            if(option1.size.width>=option2.size.width){
  33.                                this.isFullText=true;
  34.                            }
  35.                        })
  36.  
  37.                    });
  38.  
  39.  
  40.            }
  41.        }
  42.    }
  43. </script>
  44.  

二、多行文本與圖片並排方案

場景一:圖片位於段落左側

css的float能夠作到圖文混排,而weex只提供了flex佈局,而且text組件之間也不能進行嵌套,沒法作到這種圖文混排效果,不過weex的text組件比較奇特,那就是text組件中的空格是照代碼原樣輸出的,如

  1. <text>              戰國鬼才傳,這個名字想必不少人聽都沒有聽過吧,這個名字說實話真的不是很吸引人…</text>
  2.  
文案效果:

因此解決的方案能夠利用填充空格給圖片預留位置,先計算一個空格的寬度,再計算這張圖片所須要的空格數量,最後空格鏈接字符串輸出。

ios、android效果以下(紅色色塊爲圖片區域):

結構

  1. <template>
  2.    <div class="wrapper">
  3.      <scroller class="scroller">
  4.        <div @appear="handleAppear">
  5.            <text>空格寬度:{{spaceWidth}}-空格數量:{{spaceNum}}</text>
  6.            <text class="demo-text" ref="demo-text1">          test</text>
  7.            <text class="demo-text" ref="demo-text2">test</text>
  8.        </div>
  9.  
  10.        <div class="rich">
  11.          <div class="rich-icon"></div>
  12.          <text class="rich-text" :style="textStyle">{{content}}</text>
  13.        </div>
  14.      </scroller>  
  15.  
  16.    </div>
  17. </template>
  18.  
樣式
  1. <style scoped>
  2.    .demo-text{
  3.        position: absolute;
  4.        font-size: 32px;/*文字大小與須要加空格文字大小保持一致*/
  5.        opacity: 0;
  6.    }
  7.    .rich{
  8.      position: relative;
  9.    }
  10.    .rich-icon{
  11.      position: absolute;
  12.      left:0;
  13.      top:4px;
  14.      width: 120px;
  15.      height: 32px;
  16.      background-color: red;
  17.    }
  18.    .rich-text{
  19.      font-size: 32px;
  20.    }
  21. </style>
  22.  
核心代碼
  1. <script>
  2.    const dom = weex.requireModule('dom');
  3.    export default {
  4.        data(){
  5.            return {
  6.                spaceWidth:0,//空格寬度
  7.                spaceNum:0,//所需空格數量
  8.                opacity:0,//初始透明度爲0,避免文案抖動
  9.                content:'王者榮耀遊戲中的鑽石用來作什麼最合算?王者榮耀鑽石用來幹什麼最好?在王者榮耀中鑽石並非惟一通用的貨幣,在遊戲中還有金幣和點券,小編我的以爲鑽石在遊戲中並無其餘兩種貨幣有優點。'
  10.            };
  11.        },
  12.        computed:{
  13.                textStyle(){
  14.                  return {
  15.                    opacity:this.opacity
  16.                  }
  17.                }
  18.        },
  19.        methods:{
  20.            handleAppear(){
  21.                setTimeout(()=>{
  22.                    this.setTextContent();
  23.                },30)
  24.            },
  25.            async setTextContent(){
  26.                const text1El = this.$refs['demo-text1'];
  27.                const text2El = this.$refs['demo-text2'];
  28.                let textSize1,textSize2;
  29.                await this.getSpaceSize(text1El,(data)=>{
  30.                    textSize1 = data;
  31.                });
  32.                await this.getSpaceSize(text2El,(data)=>{
  33.                    textSize2 = data;
  34.                });
  35.  
  36.                this.spaceWidth=Math.abs(textSize1-textSize2)/10;
  37.                this.content=this.getSpaceNum();
  38.                this.opacity=1;
  39.  
  40.            },
  41.            getSpaceSize(el,callback){
  42.              return new Promise(function (resolve) {
  43.                  dom.getComponentRect(el, option => {
  44.                     if(option.result){
  45.                          resolve(callback(option.size.width));
  46.                     }
  47.                  });
  48.  
  49.              })
  50.            },
  51.            getSpaceNum(){
  52.              this.spaceNum = Math.ceil(120 / this.spaceWidth);//120爲紅色區塊寬度
  53.              return new Array(this.spaceNum).join(' ')+ this.content;
  54.            }
  55.        }
  56.    }
  57. </script>
  58.  
場景二:圖片位於段落末尾

很遺憾,目前這種特殊文本以及圖片置於段落末尾並無找到相應的解決方案,只能依賴終端添加相應的富文本功能。

組件

一、命名

組件命名應避免使用JS關鍵字和保留字,以及weex提供的組件名稱,如用loading做爲組件名稱,在ios與android中將呈現空白。

錯誤示例:

  1. <template>
  2.    <div class="wrapper">
  3.        <Loading></Loading>/*改用其它名稱*/
  4.    </div>
  5. </template>
  6. <script>
  7. import Loading from './demo'
  8.    export default {
  9.        components:{
  10.            Loading
  11.        }
  12.    }
  13. </script>    
  14.  

二、自定義slider組件

weex自己提供了slider組件,但輪播圖指示器(indicator)只能修改顏色與位置,大小卻沒法更改,因此須要自定義slider組件

weex輪播圖指示器效果:

電競項目輪播圖指示器效果

weex slider提供了change事件,能夠獲取到當前播放的序號,從而作到自定義輪播指示器。 可是當中遇到一個詭異問題:若是「div.indicator-item」的內容爲空的話,H5中的指示器並不會隨着圖片切換而變化(樣式不生效),div中須要添加內容才行

  1. <div class="indicator-item"  v-for="(item,index) in data" ...>
  2. {{index}}/*添加內容,解決H5中class切換樣式不生效問題*/
  3. </div>
  4.  
完整結構以下:
  1. <template>
  2.    <div class="slider-container" :style="sliderStyle">
  3.        <slider class="slider" :interval="interval" @change="change" :auto-play="autoPlay">
  4.            <div class="slider-item" v-for="img in data" >
  5.                <image class="slider-image" :style="sliderStyle"  resize="cover" :src="img.src"></image>
  6.            </div>
  7.        </slider>
  8.        <div class="slider-indicator">
  9.            <div class="indicator-item"  v-for="(item,index) in data" :class="[current == index ? 'indicator-active' : '']">
  10.                {{index}}
  11.            </div>
  12.        </div>
  13.    </div>
  14. </template>
  15.  

動畫

關鍵幀動畫是很常見的一種動畫,css3中能夠利用@keyframes規則達到動畫效果

css3: [cc lang="css"]

[/cc] 效果如圖:

weex中提供了transition,能夠傳入相應的style,經過setInterval控制動畫循環播放,但setInterval比較耗性能,建議終端對weex sdk進行改造,加入相應的循環播放功能

  1. <template>
  2.    <div class="wrapper">
  3.        <div class="demo" ref="demo"></div>
  4.    </div>
  5. </template>
  6.  
  7. <style scoped>
  8.    .demo{
  9.        width: 200px;
  10.        height: 200px;
  11.        background-color: gold;
  12.    }
  13. </style>
  14. <script>
  15. import * as animation from './animation.js'
  16.    export default {
  17.        mounted() {
  18.            setTimeout(()=>{
  19.                setInterval(() => {
  20.                    animation.run(this.$refs.demo);
  21.                }, 2100);
  22.            },200)
  23.        }
  24.    }
  25. </script>
  26.  
animation.js
  1. const animation = weex.requireModule('animation');
  2.  
  3. export function transition(el, opts,dd) {
  4.  let duration = dd || 400
  5.  if (!el) {
  6.    return Promise.resolve();
  7.  }
  8.  return new Promise(function (resolve) {
  9.      animation.transition(el, {
  10.          duration: duration,
  11.          timingFunction: 'linear',
  12.          delay: 0,
  13.          ...opts
  14.      }, resolve);
  15.  })
  16. }
  17.  
  18. export async function run(el, obj) {
  19.  
  20.  await transition(el, {
  21.      styles: {
  22.          backgroundColor: 'red',
  23.      }
  24.  },0.0001)
  25.  
  26.  await transition(el, {
  27.      styles: {
  28.          backgroundColor: 'purple',
  29.      }
  30.  },1000)
  31.  
  32.  await transition(el, {
  33.      styles: {
  34.          backgroundColor: 'lime',
  35.      }  
  36.  },1000)
  37.  
  38. }
  39.  

UI性能

安卓下打開「調試GPU過分繪製」選項,打開以後選擇「顯示過分區域繪製」後,會發現手機界面基本被藍色,淡綠,淡紅,深紅所填充,這幾種顏色表明了不一樣程度的繪製狀況,其中藍色繪製最少,而深紅色繪製最多,可能會形成頁面卡頓,應避免出現大面積紅色區域。

優化建議:

一、儘可能不要設置背景色

二、不要過分嵌套,結構儘可能扁平化

最後

weex目前仍在不斷的完善中,過程當中遇到的問題將不斷被修復,後續將持續更新。

歡迎關注"騰訊DeepOcean"微信公衆號,每週爲你推送前端、人工智能、SEO/ASO等領域相關的原創優質技術文章:

看小編搬運這麼辛苦,關注一個唄:)

相關文章
相關標籤/搜索