weex常見問題解析

什麼是 Weex?

Weex 是使用流行的 Web 開發體驗來開發高性能原生應用的框架。css

Weex 致力於使開發者能基於通用跨平臺的 Web 開發語言和開發經驗,來構建 Android、ios 和 Web 應用。簡單來講,在集成了 WeexSDK 以後,你可使用 JavaScript 語言和前端開發經驗來開發移動應用。html

Weex 渲染引擎與 DSL 語法層是分開的,Weex 並不強依賴任何特定的前端框架。目前 Vue.js 和 Rax 這兩個前端框架被普遍應用於 Weex 頁面開發,同時 Weex 也對這兩個前端框架提供了最完善的支持。Weex 的另外一個主要目標是跟進流行的 Web 開發技術並將其和原生開發的技術結合,實現開發效率和運行性能的高度統一。在開發階段,一個 Weex 頁面就像開發普通網頁同樣;在運行時,Weex 頁面又充分利用了各類操做系統的原生組件和能力。前端

爲何選擇 Weex?

Weex帶給咱們的收益

  • 迭代速度快,快速上線
  • Weex環境下徹底Native體驗
  • Bundle資源大小對比H5小不少
  • 富交互體驗,長列表性能好
  • 上手快且簡單、一次編寫三段兼容
H5 WEEX Native
開發成本
維護更新 簡單 簡單 複雜
用戶體驗
發版審覈 不須要 不須要 須要
跨平臺性

Weex開發踩坑

通用樣式

一、圖片

一、Weex提供了image組件,但只支持遠程圖片連接(在新weex sdk 已經解決)。圖片必須添加寬、高屬性不然會不顯示出來。 二、避免在image標籤上使用v-for,不然會致使安卓上圖片渲染異常(如slider中的圖片)vue

<slider class="activity" :autoPlay="true" interval="4000" @change="sliderChange">
    <div class="activity-cell"
      v-for="(item, index) in bannerList" :key="index"
      @click="clickInBanner(item)">
      <image class="activity-wrap-bg" resize="cover" :src="imageRes.bannerBgImg"></image>
      <image class="activity-wrap-image" :src="item.pictureUrl"></image>
    </div>
  </slider>
複製代碼

二、border

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

web
ios、android

三、scale設置爲0問題

transform: scale(0)會致使文檔流內全部事件擴散到整個html結構,致使文檔流事件所有無效。只有脫離文檔流的元素(absolute等)能夠點擊;經常使用能夠設置transform: scale(0,1),並使元素隱藏起來。ios

四、input標籤高度問題

安卓環境中,當input高度設置小於60px時,會致使輸入框光標不會顯示出來。(ios、web正常)web

五、v-if問題

在作一些操做切換狀態時(如按鈕點擊置灰),應儘可能避免使用v-if,可採用添加class的方式segmentfault

六、透明度

目前僅ios支持box-shadow屬性,android暫不支持,可使用圖片代替。每一個元素只支持設置一個陰影效果,不支持多個陰影同時做用於一個元素。and在平常開發中陰影最好使用圖片來代替,避免出現未知的問題。如下是涉及到顏色的相關屬性對透明度的支持度列表bash

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

七、Weex不支持樣式簡寫

.border {
    margin: 0 10px; // 錯誤
    margin-right: 10px;
    margin-left: 10px; // 正確
    border: 1px solid #000; // 錯誤
    border-width: 1px;
    border-style: solid;
    border-color: #000; // 正確
  }
複製代碼

八、 點擊態

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

<template>
  <div class="btn">
    <text>下載</text>
  </div>
</template>
<style scoped>
  .btn {
    opacity: 1; // 必須添加
  }
  .btn:active {
    opacity: 0.5;
  }
</style>
複製代碼

九、 文本截斷

文本從限制一行到不限制可使用lines:0來控制;

<template>
  <text class="text" @click="onClickText" :style="textStyle">
    這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,這是一段測試文本,
  </text>
</template>
<style scoped>
.text {
  text-overflow: ellipsis;
  lines: 1;
}
</style>
<script>
 export default {
   data () {
     return {
       textStyle: {},
     };
   },
   methods: {
     onClickText() {
       this.textStyle = {
         lines: 0,
       };
     },
   },
 }
</script>
複製代碼

十、html順序在不一樣設備上的顯示

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

<template>
  <div>
    <div>A(綠)</div> 
    <div>B(藍)</div>
    <div>C(紫)</div>
    <div>D(紅)</div>
  </div>
</template>
複製代碼
web
ios、android

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

<template>
  <div>
    <div>D(紅)</div>
    <div>C(紫)</div>
    <div>B(藍)</div>
    <div>A(綠)</div> 
  </div>
</template>
複製代碼

十一、安卓下遮擋問題

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

十二、微信環境輸入框失焦時,當前頁面的視圖偏移量未回覆到初始位置。

微信環境輸入框收起會改變頁面dom結構佈局,能夠採起捕獲失去焦點事件, 執行window.scrollTo(0, 0);

1三、微信環境下超過一屏的長圖在加載時渲染不出來

能夠對圖片的父容器(scroller、 list)設置一個背景顏色,便可成功加載。

1四、漸變

weex不支持徑向漸變radial-gradient,只支持建立線性漸變。而且只支持兩種顏色的漸變,漸變方向以下:

  • to right: 從左向右漸變
  • to left: 從右向左漸變
  • to bottom: 從上向下漸變
  • to top: 從下向上漸變
  • to bottom right: 從左上角向右下角漸變
  • to top left: 從右下角向左上角漸變

注意

  • background-image優先級高於background-color,這意味着同時設置background-image和background-color,後者會被覆蓋。
  • background不支持簡寫。

1五、富文本

weex在0.20版本添加一個新的標籤richtext即富文本標籤。但在以前的版本內weex是不支持富文本功能的,基本富文本功能都是使用圖片來表明,由於weex的字體標籤只有text,而且都是weex全部的標籤結構都是彈性佈局;可是weex也提供了一個方案,即在weex中空格也是佔據必定空間的,因此能夠支持一些特定的富文本功能。

富文本
<template>
  <div>
    <image class="tag-image" :src="data.userType | typeImg" :style="{ top: `${getEnvValue(17,18,13)}px`}"></image>
    <text class="item-title">{{' ' + getEnvValue(' ','',' ')+ data.title}}</text>
  </div>
</template>
<script>
export default {
  methods: {
    // 根據環境不一樣返回不一樣的三個值
    getEnvValue(webValue, iOSValue, androidValue) {
      if (this.isWeb) {
        return webValue;
      } else if (this.isIos) {
        return iOSValue;
      } else if (this.isAndroid) {
        return androidValue;
      }
      return iOSValue;
    },
  }
}
</script>
複製代碼

輸入事件

一、輸入框不能清空內容

須要清空輸入框內已經輸入的內容時,不能直接將綁定的值置爲空,而是應該先隱藏輸入框內顯示的值,在一次渲染以後將在將值置爲空。

<template>
  <div class="input-wrap">
    <wxs-icon name="search" size='40px' color='#b2b2b2'></wxs-icon>
    <input
      :value="searchKeyWord"
      returnKeyType="search"
      @focus="onInputFocus"
      @blur="onInputBlur"
      @input="onInputInput"
      @return="onInputReturn"
      class="input-hint"
      ref="input"
      placeholder-color="#cccccc"
      :singleline="true"
      :lines="1" />
    <div class="erase" @click="onClickErase">
      <wxs-icon v-if="isInputFocus || isWeb" name="erase" size='36px' color='#b2b2b2' ></wxs-icon>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      searchKeyWord: '',
    };
  },
  methods: {
    onClickErase() {
      this.searchKeyWord = ' ';
      this.$nextTick(() => {
        this.searchKeyWord = '';
      });
    },
  }
}
</script>
複製代碼

二、Weex input輸入框組件 在安卓下input事件BUG

當使用v-model綁定值時,還原到綁定值原始狀態時,沒法觸發input事件,此時還影響到v-model的綁定。在android上的表現爲對輸入框的input事件進行監聽;打開頁面選中輸入框,對輸入框輸入一串文字,此時成功的觸發了input事件。按鍵盤上的刪除,最初也是成功的觸發input事件,當最後一個字符被刪除時,input事件並不會觸發。若是不使用value來設置值,改使用v-model,也會出現這樣的狀況。經過查閱資料,發現這個是weex android sdk存在的一個坑點(做者沒太接觸過安卓開發)segmentfault.com/q/101000001…裏面給出了一張修改源碼的方式來解決該BUG。主要問題是在WXInput的父類AbstractEditComponent類中, mIgnoreNextOnInputEvent 這個變量在組件初始化的時候被設置爲了TRUE,致使了第一次輸入input內容顯示不出來。使用上一個問題的方法也能夠成功的解決該問題,也能夠將searchKeyWord的初始值置爲undefined也能夠很好的規避該問題。

組件

命令

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

<template>
  <div>
    <Loading></Loading> /* 改用其餘名稱 */
  </div>
</template>
複製代碼

自定義slider組件

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

<template>
  <!-- 首頁banner區塊 -->
  <div class="activity-wrap" :style="{ top: (topSafeAreaHeight + 123) + 'px' }">
    <slider class="activity" :autoPlay="true" interval="4000" @change="sliderChange">
      <div class="activity-cell"
        v-for="(item, index) in bannerList" :key="index"
        @click="clickInBanner(item)">
        <image class="activity-wrap-bg" resize="cover" :src="imageRes.bannerBgImg"></image>
        <image class="activity-wrap-image" :src="item.pictureUrl"></image>
      </div>
    </slider>
    <div class="slider-indicator-wrap" v-if="bannerList && bannerList.length > 1">
      <div
        v-for="(icon, index) in bannerList"
        :key="index"
        ref="activeSliderKey"
        class="slider-indicator"
        :class="[index === 0 ? 'slider-indicator-left' : '']"
      ></div>
    </div>
  </div>
</template>
<script>
export default {
  ...,
  methods: {
    // 首頁banner切換回調
    sliderChange({ index }) {
      const self = this;
      if (self.bannerList.length > 0) {
        for (let i = 0; i < self.bannerList.length; i += 1) {
          animation.transition(self.$refs.activeSliderKey[i], {
            styles: {
              backgroundColor: 'rgba(255, 255, 255, 0.3)',
            },
            delay: 0,
          });
        }
        animation.transition(self.$refs.activeSliderKey[index], {
          styles: {
            backgroundColor: 'rgba(255, 255, 255)',
          },
          delay: 0,
        });
      }
    },
  },
}
</script>
複製代碼

動畫

weex不支持幀動畫,但自己自帶的transition能夠傳入對應的style,並經過setInterval來控制動畫循環播放

animation.js

const animation = weex.requireModule('animation');

export function transition(el, opts, dd) {
  const duration = dd || 400;
  if (!el) {
    return Promise.resolve();
  }
  return new Promise((resolve) => {
    animation.transition(el, {
      duration,
      timingFunction: 'linear',
      delay: 0,
      ...opts,
    }, resolve);
  });
}

export function run(el) {
  transition(el, {
    styles: {
      transform: 'scale(1.02)',
    },
  }, 100).then(() => {
    transition(el, {
      styles: {
        transform: 'scale(1.08)',
      },
    }, 200);
  }).then(() => {
    transition(el, {
      styles: {
        transition: 'scale(1)',
      },
    }, 300);
  });
}
複製代碼

page.vue

<template>
  <div ref="btn"></btn>
</template>
<script>
export default {
  ...
  mounted() {
    setTimeout(() => {
      setInterval(() => {
        animation.run(this.$refs.btn);
      }, 600);
    }, 300);
  },
}
</script>
複製代碼

參考連接

相關文章
相關標籤/搜索