公司的項目,記錄開發快應用中踩的坑。
版本:1030
更新日期:2019-07-10
PS:因為版本更新會有些快,手機的換代有些快,所以可能這里說的問題在手機上并不會出現問題,所以這里僅供參考。
html+css
UI的坑太多了,太多不支持了,感覺一時也列表出太多。簡單寫寫吧。
選擇器
快應用太多選擇器不支持,詳見官方文檔:快應用 - style 樣式
規則
太多規則不支持,并且建議不要省略樣式的定義,會出現無法預料的問題。
<!-- 原本的寫法 -->
.a,
.b {
color: red;
}
.a {
font-size: 14px;
}
.b {
font-size: 20px;
}
<!--建議寫法-->
.a {
color: red;
font-size: 14px;
}
.b {
color: red;
font-size: 20px;
}
包括動畫的,如果 0% 和 100% 是一模一樣的,也要分開。。因為...就是不支持。。會出現編輯器ok手機不ok。。。
布局
建議使用某種布局的工具,像我們公司使用的一個 flex 布局的工具。。
如果頁面布局都是flex布局,還算方便,原有的布局不用太大修改,默認的 div 元素需要加上
flex-grow: 1;
flex-direction: column;
這樣才是類似 block,占據整行,由上至下。
另外,定位元素最好設定高度,不然它的高度很可能占據屏幕的100%。
UI切換的類
手機上有個bug,一般情況下,我們會定義某個元素塊一些樣式,然后使用 .active 再去定義一些新的樣式,已到達在點擊或者某個操作修改類而更新UI,例如:
<div class="test-div">
<h1>你好</h1>
</div>
<div class="test-div active">
<h1>你好</h1>
</div>
<style>
<!--正常的情況-->
.test-div {
background-color: red;
}
.test-div h1 {
font-size: 12px;
color: #000;
}
<!--active的情況-->
.test-div.active {
background-color: gray;
}
.test-div.active h1 {
font-size: 20px;
color: red;
}
</style>
我們一般會這樣寫,給元素加個 active 來切換UI。
但是快應用很神奇的地方在于,切換的UI的類名,只有當前元素的規則生效,其后代元素的不生效。
也就是,在正常的H5中,給 div.test-div 加一個 active ,它會改變背景色,然后它的子元素 h1 會改變字體大小和顏色。
快應用中,給 div.test-div 加一個 active ,它會改變背景色,然后...就沒有然后了,h1 的樣式不生效。。。
所以,在不知道什么時候會修復的情況下,上面的例子建議改成這樣(只寫一下 active 的 css):
<div class="test-div">
<h1>你好</h1>
</div>
<div class="test-div div-active">
<h1 class="h1-active">你好</h1>
</div>
<style>
<!--active的情況-->
.test-div.div-active {
background-color: gray;
}
.test-div h1.h1-active {
font-size: 20px;
color: red;
}
</style>
JS
JS部分,普通方法大多可以共用,但是對于頁面、結構的部分快應用和 vue 還是有一些不同的地方,所以使用一些 hack 方法來模擬 vue 的開發結構,最大適應自己的編程習慣。
文件結構
因為快應用的生命周期、方法都在同級,所以為了保持vue開發的習慣,對文件進行了分割,如下部分:
- data.js :頁面/組件的數據部分,包含 data 、props 等定義數據的地方,示例:
const BASE_URL = '/Common/img';
export default {
props: {
list: {
default: []
}
},
data() {
return {
iconXXX: BASE_URL + '/xxxxx.png'
};
}
};
- computed.js :計算屬性,下面一章有說講解使用計算屬性
export default {
// 這個是掛載計算屬性的方法,下一節會講解
initComputed() {
let _this = this;
let computed = _this.computed();
for (let key of Object.keys(computed)) {
Object.defineProperty(_this, key, {
get() {
return computed[key].call(_this);
}
});
}
},
// 以 data 的形式以 function 定義
computed() {
return {
a() {
// code ...
},
b() {
// code ...
}
};
}
};
- life.js :生命周期,這里放置生命周期函數
export default {
onInit() {}
};
- methods.js :自定義的方法
export default {
funcA() {},
funcB() {}
};
使用的話,就在 ux 文件中引入并拼接:
import dataMixin from './mixin/data';
import computedMixin from './mixin/computed';
import methodsMixin from './mixin/methods';
import lifeMixin from './mixin/life';
export default {
...dataMixin, // 數據
...computedMixin, // 計算屬性
...methodsMixin, // 方法
...lifeMixin // 生命周期
};
計算屬性 computed
1030不支持計算屬性,而 computed 是在1050版本才出的,現在還沒有兼容,所以修改了一下寫法。
快應用中,computed 寫法:
<script>
export default {
data(){
return {
a: 1,
b: 2
}
},
computed(){
return {
// 似 data 的寫法
data1(){
// some code...
}
}
},
// 計算屬性初始化
initComputed() {
let _this = this;
let computed = _this.computed();
for (let key of Object.keys(computed)) {
Object.defineProperty(_this, key, {
get() {
return computed[key].call(_this);
}
});
}
},
onInit(){
this.initComputed(); // 執行計算屬性初始化
}
}
</script>
父子組件的通訊
子元素 $emit ,外層監聽,不能用駝峰式,并且返回的在對象的 detail 中。
針對上面的情況,寫了一個輔助方法來引入。
// proxyEvent.js
export default {
proxyEmit(f = '', p = {}) {
if (f) {
this.$emit('proxyOn', { f, p });
}
},
proxyOn({ detail: { f, p } } = {}) {
if (this[f] && typeof this[f] === 'function') {
this[f](p);
}
}
};
在 .ux 文件中以內掛在到主對象中。
import proxyEvent from './proxyEvent';
export default {
...proxyEvent
}
在子組件中,所有使用 this.$emit 的方法地方修改成 this.proxyEmit,第一個參數為要觸發的事件名稱,也為要觸發的父元素函數。
在父組件中,組件上只需要 @proxy-on="proxyOn" 即可。
例子:
- 子組件:sayHello.ux
<template>
<div>
<text @click="proxyEmit('sayHelloEvent', { value: 'hello~' })">點擊觸發</text>
</div>
</template>
<script>
import proxyEvent from './proxyEvent';
export default {
...proxyEvent
}
</script>
- 父組件:
<template>
<sayHello @proxy-on="proxyOn"></sayHello>
</template>
<import name="sayHello" src="./sayHello.ux"></import>
<script>
import proxyEvent from './proxyEvent';
export default {
...proxyEvent,
sayHelloEvent(params){
console.log(params); // { value: 'hello~' }
}
}
</script>