Vue.js 2.0 最佳實踐 & 踩坑記錄

最近在團隊的小組里做了一次關于Vue.js 2.0的一些 最佳實踐 和常見的 采坑記錄 的小分享,這里總結了一下分享給大家~ 如果哪里有問題歡迎大家diss ^_^

代碼規(guī)范

關于代碼規(guī)范,我的理解是不一定非要用什么特別嚴苛的標準或是特別權威的規(guī)范,只要項目團隊遵循一套統(tǒng)一的約定就可以。當然,參考他人的經驗沉淀從而制定自己的代碼規(guī)范還是很有必要的。

1. 對齊

  • 靜態(tài)屬性 (static binding) 在前, 動態(tài)屬性 (dynamic binding) 在后
  • 屬性綁定 (:屬性)在前, 事件綁定 (@事件) 在后
  • 如果有使用指令,則指令語句寫在最前面

e.g:

<!-- bad -->
<li
    :name="n.name"
    @click="check"
    v-for="n in list"
    :key="n.id"
    class="list-item"
    :tag="n.tag"
    type="product"
>{{ n.name }}
</li>

<!-- good -->
<li
    v-for="n in list"
    class="list-item"
    type="product"
    :key="n.id"
    :name="n.name"
    :tag="n.tag"
    @click="check"
>{{ n.name }}
</li>

2. 簡化的表達式(不要在模版里使用復雜的表達式)

  • 對于列表里的數(shù)據表達式,可以用 filter 來處理
  • 其他情況下,可以使用 computed property

e.g:

<!-- bad -->
<template>
      <h1>
          {{ `${(new Date()).getUTCFullYear()}-${('0' + ((new Date()).getUTCMonth()+1)).slice(-2)}` }}
      </h1>
</template>

<!-- good -->
<template>
    <h1>
        {{ `${year}-${month}` }}
    </h1>
</template>
<script type="text/javascript">
    export default {
        computed: {
            month() {
                return this.twoDigits((new Date()).getUTCMonth() + 1);
            },
            year() {
                return (new Date()).getUTCFullYear();
            }
        },
        methods: {
            twoDigits(num) {
                return ('0' + num).slice(-2);
            }
        },
    };
</script>

3. 組件編碼規(guī)范

  • 導出一個清晰、組織有序的組件,使得代碼易于閱讀和理解。同時也便于標準化。
  • 能避免操作 dom 就盡量避免,實在要用的話最好使用 ref 來代替 querySelector 等選擇器方法
  • 一個 .vue 的文件行數(shù)最好控制在 200 行左右
  • 善用 v-ifv-show。比如,涉及到權限的必須用 v-if 而非 v-show。例如,用戶必須登錄后才能查看的,請用 v-if
  • 請盡量保證數(shù)據流的可追蹤性。盡量不要使用 $parent,而是通過 props 屬性接收父組件的傳入

參考:Vue組件設計規(guī)范

最佳實踐

1. 屬性綁定

1.1 綁定字符串不需要加冒號

e.g:

<!-- bad -->
<component :message="hello" />

<!-- good -->
<component message="hello" />

1.2 布爾屬性省略值時默認為 true

e.g :

<my-modal visible />
<!--等價于-->
<my-modal :visible="true" />

1.3 HTML原生屬性可以不用 props 綁定 或者 組件特有的特性也不用 props 綁定

e.g:

<component class="className" />

<bootstrap-date-input data-date-picker="activated" />

2. 事件綁定

2. 綁定無參函數(shù)不需要加 ()

e.g:

<!-- bad,括號多余 -->
<button @click="onClick()">按鈕</button>

<!-- good,隱式傳遞了 event 對象 -->
<button @click="onClick">按鈕</button>

2.2 只有一行代碼的事件函數(shù),可以直接寫在標簽上

e.g:

<button @click="visible = !visible">顯示/隱藏</button>

2.3 在監(jiān)聽原生DOM事件時,方法以 事件 為唯一的參數(shù)。如果使用內聯(lián)語句,語句可以訪問一個 $event 屬性:

e.g:

<button @click="handle($event, 1)">click me</button>

如果在父組件中想要給子組件拋出的事件添加自定義參數(shù),可利用此屬性:

e.g: https://jsfiddle.net/hysunny/eywraw8t/228187/

3. 修飾符

Vue 內置了許多常用的 修飾符 ,可以讓你少寫幾行代碼,提高開發(fā)效率。

e.g:

<!-- 阻止單擊事件繼續(xù)傳播 -->
<a v-on:click.stop="doThis"></a>

<!-- 提交事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修飾符可以串聯(lián) -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件監(jiān)聽器時使用事件捕獲模式 -->
<!-- 即元素自身觸發(fā)的事件先在此處理,然后才交由內部元素進行處理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只當在 event.target 是當前元素自身時觸發(fā)處理函數(shù) -->
<!-- 即事件不是從內部元素觸發(fā)的 -->
<div v-on:click.self="doThat">...</div>

4. 按需加載組件

一般配合 Vue-Router 使用,適用于大型應用,將應用分割成小的代碼塊,只在需要的時候才從服務器加載。

實現(xiàn)方式:

  • 異步組件實現(xiàn)
  • es6 import

好處:

  • 按需加載,節(jié)省首次加載實踐,提高速度,也算是一個性能優(yōu)化;
  • 組件只會加載一次,加載完成后會緩存下來,使用一個組件多次使用的場景。

e.g:

// 異步組件實現(xiàn)
export default new Router({
    routes: [
        {
            path: '/test',
            name: 'test',
            component: resolve => require(['../components/Test'], resolve)
        },
    ]
})

// ES6 import
const Test1 = () => import('../components/Test1')
const Test2 = () => import('../components/Test2')

export default new Router({
    routes: [
        {
            path: '/test1',
            name: 'test1',
            component: Test1
        },
        {
            path: '/test2',
            name: 'test2',
            component: Test2
        }
    ]
})

5. 過濾器

用于一些常見的文本格式化,如展示發(fā)布時間。

e.g:

<template>
    <!-- 在雙花括號中 -->
    <span>{{ message | capitalize }}</span>
    <!-- 在 `v-bind` 中 -->
    <div :message="message | capitalize"></div>
</template>

<script>
    export default {
        data() {
            return {
                message:1
            }
        },
        filters: {
            capitalize: function (value) {
                if (!value) return ''
                value = value.toString()
                return value.charAt(0).toUpperCase() + value.slice(1)
            }
        }
    }
</script>

6. 多個元素塊可以用template包裹

參考: Vue.js 在-lt-template-gt-元素上使用-v-if-條件渲染分組

e.g:

<template v-if="list.length">
    <div>header</div>
    <div>list</div>
    <div>footer</div>
</template>
<template v-else>
    <div>no list</div>
</template>

7. v-for 循環(huán)加 key

Vue.jsv-for 正在更新已渲染過的元素列表時,它默認用 就地復用 策略。如果數(shù)據項的順序被改變,Vue 將不會移動 DOM 元素來匹配數(shù)據項的順序,而是簡單復用此處每個元素,并且確保它在特定索引下顯示已被渲染過的每個元素。

稍微深入一點,加 key 的原因是為了給 virtualDom中diff 做優(yōu)化,結果就是提高 virtualDom 更新效率。

patch參考: https://github.com/aooy/blog/issues/2

8. 使用頻率較高的方法掛載到Vue實例上

這樣做的好處是不需要每次使用都要 import,提高開發(fā)效率。

e.g:

Vue.prototype.$utils = {
    cookie,
    formatDate,
    ...vdom,
    getQueryString
}

new Vue();

// 使用
this.$utils.getQueryString('from_url');

9. 多級組件傳遞數(shù)據使用 $attrs$listeners

Vue 2.4 版本,配合 interitAttrs 選項,父組件中未被 props(v-on) 綁定的屬性(事件) 可以在子組件中,通過 $attrs, $listeners 獲取。個人認為好處是不用再每個組件都顯式綁定 props 或 事件,壞處是傳遞的屬性或事件不夠明確。一般情況下不需要使用,但是在創(chuàng)建更高層次的組件時非常有用。

參考:

$attrs: https://cn.vuejs.org/v2/api/#vm-attrs

$listeners: https://cn.vuejs.org/v2/api/#vm-listeners

常見的坑

1. 對象和數(shù)組的更新檢測

由于 JavaScript 的限制,Vue 不能檢測以下變動的數(shù)組

  • 當你利用索引直接設置一個項時,例如:vm.items[indexOfItem] = newValue
  • 當你修改數(shù)組的長度時,例如:vm.items.length = newLength

還是由于 JavaScript 的限制,Vue 不能檢測對象屬性的添加或刪除

解決方法: 對于數(shù)組來說可以使用 vm.$set或改用可觀察數(shù)組的變異方法,對于對象來說可以使用 vm.$setObject.assign

e.g. https://jsfiddle.net/hysunny/eywraw8t/228152/

2. mixins同名選項混合問題

當我們想覆蓋一個組件的一些東西或想擴展某個組件時,可以用 Vuemixins

不過要注意:

當組件和混合對象含有同名選項時,同名鉤子函數(shù)將混合為一個數(shù)組,都會被調用;混合對象的鉤子將在組件自身鉤子之前調用。
值為對象的選項,例如 methods, componentsdirectives,將被混合為同一個對象。兩個對象鍵名沖突時,取組件對象的鍵值對。

e.g: https://jsfiddle.net/hysunny/eywraw8t/228225/

3. v-if 與 v-for 的優(yōu)先級問題

v-ifv-for 一起使用時,v-for 具有比 v-if 更高的優(yōu)先級,因此如果想有條件的跳過循環(huán)的執(zhí)行,則需將 v-if 置于外層元素(或 template)上。如:

<ul v-if="todos.length">
    <li 
        v-for="todo in todos" 
        :key="todo.id"
    >
       {{ todo.name }}
    </li>
</ul>
<p v-else>No todos left!</p>

4. 遍歷對象順序不一致

使用 v-for 遍歷對象時,是按 Object.keys() 的結果遍歷,但是不能保證它的結果在不同的 JavaScript 引擎 下是一致的。

比如: 在 ios 下當對象的key為字母時,排序為降序,其他機型為升序。

解決方法: 如果要保證順序,可以加個排序的 filter 或者 改用數(shù)組。

參考: https://github.com/vuejs/vue/issues/1827

5. event bus 多次觸發(fā)

$on 的事件可在 createdmounted 注冊

需在 beforeDestroydestoryed 的時候使用用 $off 銷毀

否則在某些情況下會被被多次觸發(fā)

e.g. https://jsfiddle.net/hysunny/eywraw8t/232163/

6. 變量命名

變量名不要以_、$開頭,因為名字以 _$ 開始的屬性不會被 Vue 實例代理,

因為它們可能與 Vue 的內置屬性與 API 方法沖突。

需要用 vm.$data._property 訪問它們。

e.g: https://jsfiddle.net/hysunny/eywraw8t/224835/

7. vue 2.0 給組件綁定事件無效

對于一般的 html 元素,綁定自定義事件使用 v-on即可,但是在某個組件的 根元素 上監(jiān)聽一個 原生事件 ,比如:

<my-component v-on:click="handleClick" />

我們會發(fā)現(xiàn)這樣是不起作用的,可以使用 .native 修飾符(某些情況) 或是 $listeners

<my-component v-on:click.native="handleClick" />

e.g. 用.native給自定義組件綁定事件

哦啦~

以上部分內容參考了: Vue最佳實踐,非常感謝!O(∩_∩)O~

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內容,還有我對于 Vue 1.0 印象不深的內容。關于...
    云之外閱讀 5,180評論 0 29
  • Vue 實例 屬性和方法 每個 Vue 實例都會代理其 data 對象里所有的屬性:var data = { a:...
    云之外閱讀 2,374評論 0 6
  • 喜歡將流年絮語交付于文字,不為自己,只為遠方的牽念,愛文字,一如戀上了初春滿園的鶯飛鳥語。 輕關上窗,隔開塵世的喧...
    大頭爸爸的號閱讀 263評論 0 0
  • (作者,簡寧寶兒) 愛的特質:愛是沒有犧牲和付出的。 當你覺得你在付出與一個人,當你覺得你對別人的好,你在做了一個...
    簡寧寶兒閱讀 497評論 0 0
  • 翻以前的筆記無意發(fā)現(xiàn),想想自己那時候真的有點小清新。當然逝者已逝,我也就不打擾了。
    邂逅夢雨閱讀 213評論 0 0

友情鏈接更多精彩內容