自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Vue.js的注意事項(xiàng)與技巧

開(kāi)發(fā) 前端
Vue.js 是一個(gè)很棒的框架。然而,當(dāng)你開(kāi)始構(gòu)建一個(gè)大型 JavaScript 項(xiàng)目的時(shí)候,你將對(duì) Vue.js 感到一些困惑。這些困惑并不是來(lái)自框架本身,相反 Vue.js 團(tuán)隊(duì)會(huì)經(jīng)常調(diào)整一些重要設(shè)計(jì)策略。

 [[261192]]

Vue.js 是一個(gè)很棒的框架。然而,當(dāng)你開(kāi)始構(gòu)建一個(gè)大型 JavaScript 項(xiàng)目的時(shí)候,你將對(duì) Vue.js 感到一些困惑。這些困惑并不是來(lái)自框架本身,相反 Vue.js 團(tuán)隊(duì)會(huì)經(jīng)常調(diào)整一些重要設(shè)計(jì)策略。

相對(duì)于 React 和 Angular,Vue.js 面向一些不同水平的開(kāi)發(fā)者。它更加的友好,不管是對(duì)初學(xué)者還是經(jīng)驗(yàn)豐富的老手。它并不隱藏一些 DOM 操作,相反它與 DOM 配合的很好。

這篇文章更像是一個(gè)目錄,列舉了我在 Vue.js 的初學(xué)路上遇到一些問(wèn)題和技巧。理解這些關(guān)鍵性的設(shè)計(jì)技巧,有助于我們構(gòu)建大型的 Web 應(yīng)用。

寫(xiě)這篇文章的時(shí)候是 2018 年 5 月 18 日,下面這些技巧依然是有效的。但是框架升級(jí),或者瀏覽器底層或者 JS API 發(fā)生改變時(shí),他們可能會(huì)變得不是那么有用。

譯者注:盡管 Vue.js 3 即將到來(lái),但是下面的技巧大部分是有用的,因?yàn)?3 的版本并不會(huì)改變一些上層 API ,***的特性可能是底層數(shù)據(jù) Observer 改有 proxy 實(shí)現(xiàn),以及源碼使用 typescript 構(gòu)建。

1、為什么 Vue.js 不使用 ES Classes 的方式編寫(xiě)組件

如果你使用過(guò)類似于 Angular 的框架或者某些后端 OOP 語(yǔ)言后,那么你的***個(gè)問(wèn)題可能是:為什么不使用 Class 形式的組件?

Vue.js 的作者在 GitHub issues 中很好的回答了這個(gè)問(wèn)題:

Use standard JS classes instead of custom syntax?

為什么不使用 Class 這里有三個(gè)很重要的原因:

ES Classes 不能夠滿足當(dāng)前 Vue.js 的需求,ES Classes 標(biāo)準(zhǔn)還沒(méi)有完全規(guī)范化,并且總是朝著錯(cuò)誤的方向發(fā)展。如果 Classes 的私有屬性和裝飾器(當(dāng)前已進(jìn)入 Stage 3)穩(wěn)定后,可能會(huì)有一定幫助。

ES Classes 只適合于那些熟悉面向?qū)ο笳Z(yǔ)言的人,它對(duì)哪些不使用復(fù)雜構(gòu)建工具和編譯器的人不夠友好。

優(yōu)秀的 UI 組件層次結(jié)構(gòu)一般都是組件的橫向組合,它并不是基于繼承的層次結(jié)構(gòu)。而 Classes 形式顯然更擅長(zhǎng)的是后者。

譯者注:But,Vue.js 3.0 將支持基于 Class 的組件寫(xiě)法,真香。

2、如何構(gòu)建自己的抽象組件?

如果你想構(gòu)建自己的抽象組件(比如 transition、keep-alive),這是一個(gè)比構(gòu)建大型 web 應(yīng)用更加瘋狂地想法,這里有一些關(guān)于這個(gè)問(wèn)題的討論,但是并沒(méi)有什么進(jìn)展。

Any plan for docs of abstract components?

譯者注:在 Vue.js 內(nèi)部組件(transition、keep-alive)中,使用了一個(gè) abstract 屬性,用于聲明抽象組件,這個(gè)屬性作者并不打算開(kāi)放給大家使用,所以文檔也沒(méi)有提及。但是如果你要使用也是可以的,那么你必須深入源碼探索該屬性有何作用。

但是不要害怕,如果你可以很好地理解 slots ,你就可以構(gòu)建自己的抽象組件了。這里有一篇很好的博客介紹了要如何做到這一點(diǎn)。

Writing Abstract Components with Vue.js

譯者注:下面是《在 Vue.js 中構(gòu)建抽象組件》的簡(jiǎn)單翻譯

抽象組件與普通組件一樣,只是它不會(huì)在界面上顯示任何 DOM 元素。它們只是為現(xiàn)有組件添加額外的行為。

就像很多你已經(jīng)熟悉的 Vue.js 的內(nèi)置組件,比如:` `、``、``。

現(xiàn)在展示一個(gè)案例,如何跟蹤一個(gè) DOM 已經(jīng)進(jìn)入了可視區(qū)域 ,讓我們使用 IntersectionObserver API 來(lái)實(shí)現(xiàn)一個(gè)解決這個(gè)問(wèn)題的抽象組件。

(完整代碼在這里:[vue-intersect](https://github.com/heavyy/vue-intersect))

  1. // IntersectionObserver.vue 
  2. export default { 
  3.   // 在 Vue 中啟用抽象組件 
  4.   // 此屬性不在官方文檔中, 可能隨時(shí)發(fā)生更改,但是我們的組件必須使用它 
  5.   abstract: true
  6.   // 重新實(shí)現(xiàn)一個(gè) render 函數(shù) 
  7.   render() { 
  8.     // 我們不需要任何包裹的元素,只需要返回子組件即可 
  9.     try { 
  10.       return this.$slots.default[0]; 
  11.     } catch (e) { 
  12.       throw new Error('IntersectionObserver.vue can only render one, and exactly one child component.'); 
  13.     } 
  14.  
  15.     return null
  16.   }, 
  17.   mounted () { 
  18.     // 創(chuàng)建一個(gè) IntersectionObserver 實(shí)例 
  19.     this.observer = new IntersectionObserver((entries) => { 
  20.       this.$emit(entries[0].isIntersecting ? 'intersect-enter' : 'intersect-leave', [entries[0]]); 
  21.     }); 
  22.  
  23.     // 需要等待下一個(gè)事件隊(duì)列,保證子元素已經(jīng)渲染 
  24.     this.$nextTick(() => { 
  25.       this.observer.observe(this.$slots.default[0].elm); 
  26.     }); 
  27.   }, 
  28.   destroyed() { 
  29.     // 確保組件移除時(shí),IntersectionObserver 實(shí)例也會(huì)停止監(jiān)聽(tīng) 
  30.     this.observer.disconnect(); 
  31.   } 
  32.  

讓我們看看如何使用它?

  1. <intersection-observer @intersect-enter="handleEnter" @intersect-leave="handleLeave"
  2.   <my-honest-to-goodness-component></my-honest-to-goodness-component> 
  3. </intersection-observer> 

 

但是在這樣做之前,請(qǐng)你三思。我們一般依賴 mixins 和一些純函數(shù)來(lái)解決一些特殊場(chǎng)景的問(wèn)題,你可以將 mixins 直接看做一個(gè)抽象組件。

How do I extend another VueJS component in a single-file component? (ES6 vue-loader)

3、我不太喜歡 Vue.js 的單文件組件,我更希望 HTML、CSS 和 JavaScript 分離。

沒(méi)有人阻止你這樣做,如果你是個(gè)注重分離的哲學(xué)家,喜歡把不同的東西放在不同文件,或者討厭編輯器對(duì) .vue 文件的不穩(wěn)定行為,那么你這么做也是可以的。你要做的很簡(jiǎn)單:

  1. <!--https://vuejs.org/v2/guide/single-file-components.html --> 
  2. <!-- my-component.vue --> 
  3. <template src="./my-component.html"></template> 
  4. <script src="./my-component.js"></script> 
  5. <style src="./my-component.css"></style>  

這么做,就會(huì)出現(xiàn)下一個(gè)問(wèn)題:我的組件總是需要 4 個(gè)文件(vue + html + css + js)嗎?我能不能擺脫 .vue 文件? 答案是肯定的,你可以使用 vue-template-loader。

我的同事還為此寫(xiě)了一篇很棒的教程:

Using vue-template-loader with Vue.js to Compile HTML Templates

4、 函數(shù)式組件

感謝 React.js 讓函數(shù)式組件很流行,這是因?yàn)樗麄儫o(wú)狀態(tài)、易于測(cè)試。然而它們也存在一些問(wèn)題。

譯者注:不了解 Vue.js 函數(shù)式組件的可以先在官方文檔查看:官方文檔

4.1 為什么我不能對(duì)功能組件使用基于 Class 的 @Component 裝飾器?

再次回到 Classes,它只是一種用于保存本地狀態(tài)的數(shù)據(jù)結(jié)構(gòu)。如果函數(shù)式組件是無(wú)狀態(tài)的,那么使用 @Component 裝飾器就是無(wú)意義的。

這里有關(guān)于這個(gè)的討論:

How to create functional component in @Component?

4.2 外部類和樣式不應(yīng)用于函數(shù)式組件

函數(shù)式組件不能像普通組件那樣,綁定具體的類和樣式,必須在 render 函數(shù)中手動(dòng)應(yīng)用這些綁定。

DOM class attribute not rendered properly with functional components

class attribute ignored on functional components

4.3 函數(shù)式組件總是會(huì)重復(fù)渲染?

TLDR:在函數(shù)式組件中使用有狀態(tài)組件時(shí)務(wù)必要小心

Functional components are re-rendered when props are unchanged.

函數(shù)式組件相當(dāng)于直接調(diào)用組件的 Render 函數(shù),這意味著你應(yīng)該:

避免在 render 函數(shù)中直接使用有狀態(tài)組件,因?yàn)檫@會(huì)在每次調(diào)用 render 函數(shù)時(shí)創(chuàng)建不同的組件實(shí)例。

如果函數(shù)式組件是葉子組件,會(huì)更好地利用它們。 需要注意的是,同樣的行為也適用于 React.js。

4.4 如何在Vue.js 函數(shù)式組件中觸發(fā)一個(gè)事件?

在從函數(shù)式組件中觸發(fā)一個(gè)事件并不簡(jiǎn)單。不幸的是,文檔中也沒(méi)有提到這一點(diǎn)。函數(shù)式組件中不可用 $emit 方法。stack overflow 上有人討論過(guò)這個(gè)問(wèn)題:

How to emit an event from Vue.js Functional component?

5、Vue.js 的透明包裹組件

組件包裹一些DOM元素,并且公開(kāi)了這些DOM元素的事件,而不是根DOM的節(jié)點(diǎn)實(shí)例。

例如:

  1. <!-- Wrapper component for input --> 
  2. <template> 
  3.     <div class="wrapper-comp"
  4.         <label>My Label</label> 
  5.         <input @focus="$emit('focus')" type="text"/> 
  6.     </div> 
  7. </template> 

這里我們真正感興趣的是 input 節(jié)點(diǎn),而不是 div 根節(jié)點(diǎn),因?yàn)樗饕菫榱藰邮胶托揎椂砑拥?。用戶可能?duì)這個(gè)組件的幾個(gè)輸入事件感興趣,比如 blur、focus、click、hover等等。這意味著我們必須重新綁定每個(gè)事件。我們的組件如下所示。

  1. <!-- Wrapper component for input --> 
  2. <template> 
  3.     <div class="wrapper-comp"
  4.         <label>My Label</label> 
  5.         <input type="text" 
  6.             @focus="$emit('focus')" 
  7.             @click="$emit('click')" 
  8.             @blur="$emit('blur')" 
  9.             @hover="$emit('hover')" 
  10.         /> 
  11.     </div> 
  12. </template> 

實(shí)際上這是完全沒(méi)必要的。簡(jiǎn)單的解決方案是使用 Vue 實(shí)例上的屬性 vm.$listeners 將事件重新綁定到所需DOM 元素上:

  1. <!-- Notice the use of $listeners --> 
  2. <template> 
  3.     <div class="wrapper-comp"
  4.         <label>My Label</label> 
  5.         <input v-on="$listeners" type="text"/> 
  6.     </div> 
  7. </template> 
  8. <!-- Uses: @focus event will bind to internal input element --> 
  9. <custom-input @focus="onFocus"></custom-input> 

6、為什么你不能在 slot 上綁定和觸發(fā)事件

我經(jīng)??吹接行╅_(kāi)發(fā)人員,在 slot 上進(jìn)行事件的監(jiān)聽(tīng)和分發(fā),這是不可能的。

組件的 slot 由調(diào)用它的父組件提供,這意味著所有事件都應(yīng)該與父組件相關(guān)聯(lián)。嘗試去傾聽(tīng)這些變化意味著你的父子組件是緊密耦合的,不過(guò)有另一種方法可以做到這一點(diǎn),Evan You解釋得很好:

Is it possible to emit event from component inside slot #4332

Suggestion: v-on on slots

7、slot 中的 slot(訪問(wèn)孫輩slot)

在某些時(shí)候,可能會(huì)遇到這種情況。假設(shè)有一個(gè)組件,比如 A ,它接受一些 slot 。遵循組合的原則,使用組件 A 構(gòu)建另一個(gè)組件 B 。然后你把 B 用在 C 中。

那么現(xiàn)在問(wèn)題來(lái)了: 如何將 slot 從 C 組件傳遞到 A 組件?

要回答這個(gè)問(wèn)題,首先取決你使用何種方式構(gòu)建組件? 如果你是用 render 函數(shù),那就很簡(jiǎn)單。你只需要在組件 B 的 render 函數(shù)中進(jìn)行如下操作: 

  1. // Render function for component B 
  2. function render(h) { 
  3.     return h('component-a', { 
  4.         // Passing slots as they are to component A 
  5.         scopedSlot: this.$scopedSlots 
  6.     } 
  7.  

但是,如果你使用的是基于模板的方式,那么就有些糟糕了。幸運(yùn)的是,在這個(gè)問(wèn)題上有了進(jìn)展:

feat(core): support passing down scopedSlots with v-bind 

希望這篇文章讓你對(duì) Vue.js 的設(shè)計(jì)思路有了更深入的了解,并為你提供了一些在高級(jí)場(chǎng)景中的技巧。

責(zé)任編輯:龐桂玉 來(lái)源: segmentfault
相關(guān)推薦

2011-06-24 09:23:02

SEO

2010-05-11 11:03:41

Mysql索引

2011-05-26 11:22:04

SEO

2013-09-25 10:15:51

閃存存儲(chǔ)優(yōu)勢(shì)注意事項(xiàng)

2009-08-27 10:40:56

Java路徑

2010-06-21 14:39:56

光纖測(cè)試

2010-06-10 13:11:23

2009-12-15 17:47:17

VSIP

2013-03-14 14:07:55

活動(dòng)目錄域名控制器服務(wù)器虛擬化

2010-05-31 09:58:48

MySQL備份

2009-12-29 11:03:28

ADO代碼

2010-11-26 16:27:01

MySQL使用變量

2023-01-14 09:49:11

2020-10-20 14:05:48

用戶需求分析IT

2021-11-16 10:35:59

云計(jì)算云計(jì)算環(huán)境云應(yīng)用

2011-09-26 11:02:10

2022-04-04 16:53:56

Vue.js設(shè)計(jì)框架

2010-05-25 16:46:00

2010-02-05 14:13:17

Android平臺(tái)

2011-05-06 16:22:54

佳能MP198加墨注意事項(xiàng)噴墨打印機(jī)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)