随着电竞业务的不断发展,页面功能愈来愈多,交互逻辑更加复杂,相似无限滚动、上拉刷新、横竖切换滚动等形式在业务中已经是标配,通过重重优化后在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
- 安装sass依赖的npm包:sass-loader、node-sass、sass-loader、stylus-loader。
- 在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; }
- 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源创计划”,欢迎正在阅读的你也加入,一块儿分享。