企鵝電競weex實踐之UI篇

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

爲何選擇weex

相對H5來講,weex帶來的用戶體驗更好,它結合了H5和Native各自的優點,既能像H5同樣快速迭代,又能和Native同樣流暢。
在這裏插入圖片描述
次嘗試新方案、新技術時都將面臨着許多問題,企鵝電競接入weex也不例外,咱們在使用weex進行設計還原時並非像H5同樣順利,爲了不小夥伴重複踩坑,本文將主要圍繞H5與weex的區別以及weex ui開發時遇到的問題進行說明。html

本文將從如下幾個方面對Weex進行介紹:
H5與Weex的區別vue

  • 項目結構
  • 標籤
  • 引入sass
  • sass變量

weex ui開發踩坑node

  • 通用樣式
  • 佈局
  • 組件
  • 動畫
  • UI性能

H5與Weex的區別

項目結構

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

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

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

標籤

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

引入sass

  1. 安裝sass依賴的npm包:sass-loader、node-sass、sass-loader、stylus-loader。
  2. 在build文件夾下webpack.base.conf.js的rules裏面添加配置。
rules:{
 	{
 	test: /\.(scss|css)$/,
 	loader: 'vue-style-loader!css-loader!sass-loader!stylus-loader?indentedSyntax',
 	}
 	}er-width:$border.width;
 	}
  1. style中修改lang=「stylus」

sass變量

weex中的sass變量相似於對象的寫法:web

//variable.scss
$border={
color: #E9E9E9
width:2px
}
@import "./variable.scss";
.border{
border-color:$border.color;
border-width:$border.width;
}

weex ui踩坑

通用樣式

一、border

weex不支持使用border建立三角形,web能夠正常顯示,而ios和android上顯示的是矩形,建議使用圖片代替。
在這裏插入圖片描述npm

二、transform

一、rotate角度儘可能避免設置負數,某些部分安卓機型會不生效。
二、不支持transform:skew 對於這一類角標須要作傾斜處理能夠採用 圖片加 漸變代碼處理。

三、圖片

一、weex提供了image組件,但只支持遠程圖片連接。
二、避免在image標籤上使用v-for,不然會致使安卓上圖片渲染異常(如slider中的圖片)。

四、透明度

如下是涉及到顏色的相關屬性對透明度的支持度列表。如圖:
在這裏插入圖片描述
注意:box-shadow (自己不支持android),background-image不支持IOS透明。

五、點擊態

項目比較常見的點擊態多半是透明度的變化,如按鈕、列表、連接等,css的作法是添加僞類 (:active),weex中也一樣支持,可是weex須要在原樣式中添加 opacity:1,不然點擊後回不到初始狀態;此外,:active使用時,background-image在ios下會失效。例如:

<template>  
 	    <div class="ui-btn">
 	        <text class="ui-btn-text">下載</text>
 	    </div>
 	</template>
 	<style scoped>
 	    .ui-btn{
 	        opacity: 1; /*必須添加*/
 	    }
 	    .ui-btn:active{
 	        opacity: .5;
 	    }
 	</style>

六、文本截斷

以下圖,要實現下面的效果:
在這裏插入圖片描述
文本從限制1行到不限制能夠用lines:0;

<template>
 	    <text class="info-text" 
 	          @click="textClick" 
 	          :style="textStyle">城市賽戰報,《王者榮耀》城市賽鄭州站歡樂落幕城市賽戰報,《王者榮耀》城市賽鄭州站歡樂落幕城市賽戰報,《王者榮耀》城市賽鄭州站歡樂落幕城市賽戰報,《王者榮耀》城市賽鄭州站歡樂落幕</text>
 	</template>
 	<style scoped>
 	    .info-text{
 	        lines:1;
 	        text-overflow:ellipsis;
 	    }
 	</style>
 	<script>
 	    export default {
 	        data(){
 	            return {
 	                textStyle:{}
 	            };
 	        },
 	        methods:{
 	            textClick(){
 	                this.textStyle = {
 	                    lines:0
 	                }
 	            }
 	        }
 	    }
 	</script>
 	</style>

七、層級問題

例如,有a、b、c、d 四層結構,其中a、b、c均爲absolute定位,z-index由大到小,d爲普通結構,咱們知道在css中a層應該是處於最上方,d在最下方,那麼在weex中表現如何呢?

<div class="wrapper">
 	<div class="box a">a</div>
 	<div class="box b">b</div>
 	<div class="box c">c</div>
 	<div class="d">d</div>
 	</div>

在這裏插入圖片描述
能夠看到web和ios、android的表現不一致,ios、android中是以代碼中dom順序來依次添加的,和z-index無關,後面加載的視圖會覆蓋前面的視圖。因此要保證web、ios、android三端表現一致,改變dom書寫順序便可。

<div class="d"></div>
<div class="box c"></div>
<div class="box b"></div>
<div class="box a"></div>

八、安卓遮擋問題

安卓環境下容器若是設置了寬高,那麼子元素不能超出容器範圍。
在這裏插入圖片描述
建議:fixed定位不會受父容器影響,若是須要超出限制,子元素能夠設置fixed

九、v-if問題

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

佈局

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

目前項目中存在這樣的情形,暱稱與直播標籤並排,暱稱文字短時直播要跟隨,暱稱很長時要作溢出截斷(超出時加…) 。
在這裏插入圖片描述
這種佈局方式在css中要作到很容易,而在weex中利用提供的flex佈局確很難實現,最後的解決方案是經過js動態設置文字與標籤父級的寬度,從而控制文字的溢出。

<template>
 	    <div class="wrapper"  @appear="onappear">
 	        <div class="info-container" ref='info-container'>
 	            <div class="info" ref='info' :class="isFullText?['info-full']:[]">
 	                <text class="nick-text">{
  
  
   
   
            
   

  {isFullText}}企鵝電競企鵝電競企鵝電競企鵝電競</text>
 	                <img src="http://119.29.8.64/vipstyle/egame/app/weex/tab/ERICKCHEN-MC0/dist/static/img/live.b467410.png" class="live-image">
 	            </div>
 	        </div>
 	    </div>
 	</template>
 	 
 	<style scoped lang="stylus">
 	    .info-full{
 	        width:300px;
 	    }
 	</style>
 	 
 	<script>
 	const dom = weex.requireModule('dom')
 	    export default {
 	        data(){
 	            return {
 	                isFullText:false
 	            };
 	        },
 	        methods:{
 	            onappear(){
 	                dom.getComponentRect(this.$refs['info'],option1=>{
 	 
 	                        dom.getComponentRect(this.$refs['info-container'],option2=>{
 	 
 	                            if(option1.size.width>=option2.size.width){
 	                                this.isFullText=true;
 	                            }
 	                        })
 	 
 	                    });
 	 
 	 
 	            }
 	        }
 	    }
 	</script>

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

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

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

那麼運行效果以下圖:
在這裏插入圖片描述

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

<template>
 	    <div class="wrapper">
 	      <scroller class="scroller">
 	        <div @appear="handleAppear"> 
 	            <text>空格寬度:{
  
  
   
   
            
   

  {spaceWidth}}-空格數量:{
  
  
   
   
            
   

  {spaceNum}}</text>
 	            <text class="demo-text" ref="demo-text1">          test</text>
 	            <text class="demo-text" ref="demo-text2">test</text>
 	        </div>
 	 
 	        <div class="rich">
 	          <div class="rich-icon"></div>
 	          <text class="rich-text" :style="textStyle">{
  
  
   
   
            
   

  {content}}</text>
 	        </div>
 	      </scroller>  
 	 
 	    </div>
 	</template>

樣式:

<style scoped>
 	    .demo-text{
 	        position: absolute;
 	        font-size: 32px;/*文字大小與須要加空格文字大小保持一致*/
 	        opacity: 0;
 	    }
 	    .rich{
 	      position: relative;
 	    }
 	    .rich-icon{
 	      position: absolute;
 	      left:0;
 	      top:4px;
 	      width: 120px;
 	      height: 32px;
 	      background-color: red;
 	    }
 	    .rich-text{
 	      font-size: 32px;
 	    }
 	</style>

核心代碼:

<script>
 	    const dom = weex.requireModule('dom');
 	    export default {
 	        data(){
 	            return {
 	                spaceWidth:0,//空格寬度
 	                spaceNum:0,//所需空格數量
 	                opacity:0,//初始透明度爲0,避免文案抖動
 	                content:'王者榮耀遊戲中的鑽石用來作什麼最合算?王者榮耀鑽石用來幹什麼最好?在王者榮耀中鑽石並非惟一通用的貨幣,在遊戲中還有金幣和點券,小編我的以爲鑽石在遊戲中並無其餘兩種貨幣有優點。'
 	            };
 	        },
 	        computed:{
 	                textStyle(){
 	                  return {
 	                    opacity:this.opacity
 	                  }
 	                }
 	        },
 	        methods:{
 	            handleAppear(){
 	                setTimeout(()=>{
 	                    this.setTextContent();
 	                },30)
 	            },
 	            async setTextContent(){
 	                const text1El = this.$refs['demo-text1'];
 	                const text2El = this.$refs['demo-text2'];
 	                let textSize1,textSize2;
 	                await this.getSpaceSize(text1El,(data)=>{
 	                    textSize1 = data;
 	                });
 	                await this.getSpaceSize(text2El,(data)=>{
 	                    textSize2 = data;
 	                });
 	 
 	                this.spaceWidth=Math.abs(textSize1-textSize2)/10;
 	                this.content=this.getSpaceNum();
 	                this.opacity=1;
 	 
 	            },
 	            getSpaceSize(el,callback){
 	              return new Promise(function (resolve) {
 	                  dom.getComponentRect(el, option => {
 	                     if(option.result){
 	                          resolve(callback(option.size.width));
 	                     }
 	                  });
 	 
 	              })
 	            },
 	            getSpaceNum(){
 	              this.spaceNum = Math.ceil(120 / this.spaceWidth);//120爲紅色區塊寬度
 	              return new Array(this.spaceNum).join(' ')+ this.content;
 	            }
 	        }
 	    }
 	</script>

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

組件

一、命名

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

二、自定義slider組件

weex自己提供了slider組件,但輪播圖指示器(indicator)只能修改顏色與位置,大小卻沒法更改,因此須要自定義slider組件。
weex輪播圖指示器效果
在這裏插入圖片描述

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

<div class="indicator-item"  v-for="(item,index) in data" ...>
{
  
  
   
   
            
   

  {index}}/*添加內容,解決H5中class切換樣式不生效問題*/
</div>

<template>
 	    <div class="slider-container" :style="sliderStyle">
 	        <slider class="slider" :interval="interval" @change="change" :auto-play="autoPlay">
 	            <div class="slider-item" v-for="img in data" >
 	                <image class="slider-image" :style="sliderStyle"  resize="cover" :src="img.src"></image>
 	            </div>
 	        </slider>
 	        <div class="slider-indicator">
 	            <div class="indicator-item"  v-for="(item,index) in data" :class="[current == index ? 'indicator-active' : '']">
 	                {
  
  
   
   
            
   

  {index}}
 	            </div>
 	        </div>
 	    </div>
 	</template>

動畫

關鍵幀動畫是很常見的一種動畫,css3中能夠利用@keyframes規則達到動畫效果。
在這裏插入圖片描述
weex中提供了transition,能夠傳入相應的style,經過setInterval控制動畫循環播放,但setInterval比較耗性能,建議終端對weex sdk進行改造,加入相應的循環播放功能。

<template>
 	    <div class="wrapper">
 	        <div class="demo" ref="demo"></div>
 	    </div>
 	</template>
 	 
 	<style scoped>
 	    .demo{
 	        width: 200px;
 	        height: 200px;
 	        background-color: gold;
 	    }
 	</style>
 	<script>
 	import * as animation from './animation.js'
 	    export default {
 	        mounted() {
 	            setTimeout(()=>{
 	                setInterval(() => {
 	                    animation.run(this.$refs.demo);
 	                }, 2100);
 	            },200)
 	        }
 	    }
 	</script>

animation.js

const animation = weex.requireModule('animation');
 	 
 	export function transition(el, opts,dd) {
 	  let duration = dd || 400
 	  if (!el) {
 	    return Promise.resolve();
 	  }
 	  return new Promise(function (resolve) {
 	      animation.transition(el, {
 	          duration: duration, 
 	          timingFunction: 'linear',
 	          delay: 0, 
 	          ...opts
 	      }, resolve);
 	  })
 	}
 	 
 	export async function run(el, obj) {
 	 
 	  await transition(el, {
 	      styles: {
 	          backgroundColor: 'red',
 	      }
 	  },0.0001)
 	 
 	  await transition(el, {
 	      styles: {
 	          backgroundColor: 'purple',
 	      }
 	  },1000)
 	 
 	  await transition(el, {
 	      styles: {
 	          backgroundColor: 'lime',
 	      }  
 	  },1000)
 	 
 	}

性能

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

一、儘可能不要設置背景色;
二、不要過分嵌套,結構儘可能扁平化;

本文同步分享在 博客「xiangzhihong8」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索