Vue組件(知識)


form最后一節。


 

組件基礎

  • 組件的復用:  data必須是函數
  • 組織
  • 通過Prop向子組件傳遞data
  • 單個根元素
  • 通過event向父組件發送消息: 使用事件拋出一個value, 在組件上用v-model
  • 動態組件
  • 解析DOM模版時的⚠️.

深入組件

  • 組件注冊
  • Prop
  • 自定義事件: this.$emit('my-event')用kebab-case做事件名稱
  • 插槽
  • 異步組件
  • 處理邊界情況


 

例子:

組件是可復用的 Vue 實例,且帶有一個名字,如Vue.component("名字", {data..., template...})

因為組件是可復用的 Vue 實例,所以它們與 new Vue 接收相同的選項,例如 datacomputedwatchmethods 以及生命周期鈎子等。僅有的例外是像 el 這樣根實例特有的選項。

 

組件可以復用


 

無限次反復用比如上例。多次使用<button-counter>, 每用一個,就創建了一個實例。

 

data是函數

和新建Vue中的data:{...}不一樣,

data必須是函數 data: function(){...},  這是為了每個實例可以維護一份被返回對象的獨立的拷貝。

即data不是共用的數據集合,它是函數,是方法,通過它每個實例都會得到各自的結果。

 

組件的組織


 

為了能在模板中使用,這些組件必須先注冊以便 Vue 能夠識別。這里有兩種組件的注冊類型:全局注冊和局部注冊

  • Vue.component 全局注冊:
  • 全局注冊的組件可以用在其被注冊之后的任何 (通過 new Vue) 新創建的 Vue 根實例,也包括其組件樹中的所有子組件的模板中。

(深入看: 組件注冊

 

通過 Prop 向子組件傳遞數據


 

Prop 是你可以在組件上注冊的一些自定義特性

當一個值傳遞給一個 prop 特性的時候,它就變成了那個組件實例的一個屬性

可以使用 v-bind 來動態傳遞 prop。這在你一開始不清楚要渲染的具體內容,比如從一個 API 獲取博文列表的時候,是非常有用的。

 

單個根元素


 

每個組件只能有一個根元素,一般使用<div>包裹其他元素。

否則會報錯 every component must have a single root element

⚠️:

JavaScript 的模板字符串來讓多行的模板更易讀。

它們在 IE 下並沒有被支持,所以如果你需要在不編譯的情況下支持 IE,請使用折行轉義字符取而代之。

 

什么是模版字符串:

  • 模板字符串使用反引號 (` `) 來代替普通字符串中的用雙引號和單引號。
  • 模板字符串可以包含特定語法(${expression})的占位符。

折行轉義字符

在多行string每行結尾加上反斜杠  \  

var htmlSTring = "<div>\

 This is a string.\

</div>";

 

 

通過事件向父級組件發送消息


案例: https://codepen.io/chentianwei411/pen/EeXxrM/?editors=1010 

分析:

在我們開發 <blog-post> 組件時,它的一些功能可能要求和父級組件進行溝通。

例如我們可能會引入一個可訪問性的功能來放大博文的字號,同時讓頁面的其它部分保持默認的字號。

注意:⚠️:

1.自定義組件可以使用v-for,但必須配合使用v-bind:key 

2. 任何數據都不會被自動傳遞到組件里,因為組件有自己獨立的作用域。為了把迭代數據傳遞到組件里,我們要用 props :

<my-component
v-for="(item, index) in items"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
></my-component>
  • 明確組件數據的來源能夠使組件在其他場合重復使用。

 

3. vm.$emit( eventName, […args] )  (點擊看api)關於事件的實例方法。

  • 觸發當前實例上的事件。附加參數都會傳給監聽器回調。

  • 監聽器指v-on,用於監聽當前實例上的自定義事件,事件可以由vm.$emit觸發,

參數的上傳:

第一種:

在監聽v-on:enlarge-text用$event獲得上傳的參數:v-on:enlarge-text="postFontSize += $event" 

 

 

第二種:

如果這個事件處理函數是一個方法,那么這個值將會作為第一個參數傳入這個方法:

1. v-on:enlarge-text='onEnLargeText'

2.在nev Vue中添加這個方法:

methods: {
 onEnlargeText: function(enlargeAmount) {
  this.postFontSize += enlargeAmount
 }
}

 

 

在組件上用v-model 

點擊:查看(詳細分析了數據的流入和流出。及相關。)

還需要⚠️:

 

自己寫的案例分析:https://codepen.io/chentianwei411/pen/bxozoj?editors=1010

在DOM上增加了一個組件實例<custom-input>,

  • 這個組件把外部數據傳給 prop特性value, 
  • 有一個監聽v-on:input事件。

 

關於$event.target.value

$event是觸發的事件,這里是在輸入框輸入的動作。

$event.target是這個動作作用在哪個元素上。target特性返回被事件激活的元素。這里是輸入框input元素。

value指的是input中的value特性,即輸入的內容。

 

el的作用

定位html中的元素,這個元素將作為Vue實例的掛載目標。在實例掛載后,元素可以用vm.$el訪問。

template: Vue實例的模版

模版會替換被掛載的html元素,被掛載的元素的內容會被忽略,除非使用inline-template。

 

 <custom-input v-bind:value="searchText"

這是把初始化中的data屬性中的數據對象和自定義的prop特性value綁定在一切。

 

 <custom-input v-on:input='searchText = $event'

用於監聽input事件,並對參數進行回調處理。

 

template中的 <input v-bind:value='value'> 

把Props: ['value']特性的值賦予了<input>的value屬性。

 

template中的<input v-on:input=''"$emit('input', $event.target.value)">

  1. 當監聽到input這個原生HTML事件時, 執行$emit這個實例方法。
  2. $emit會觸發當前Vue實例上的自定義事件input(自定義,自定義,自定義),並傳遞參數。
  3. Vue實例上的監聽器v-on會監聽到這個觸發事件input,並執行預期的行為。這里是執行一條inline statement。

 

 


 

動態組件

根據‘組件名稱’來動態的調用組件。類似動態調用方法。把動態和異步組件讀完。

<component v-bind:is='組件名稱'></component>

用法:

渲染‘元組件’為動態組件。 根據v-bind:is的值,來決定渲染哪個組件。

這里是根據vm的計算屬性中currentTabComponent函數來得到組件的名稱

 

內置的組件:

component

Props: 

  • is - string | ComponentDefinition | ComponentConstructor
  • inline-template -boolean

 

在動態組件上使用keep-alive緩存組件

keep-alive

目的:提高效能:保留組件狀態,或避免重新渲染。

Props:

  • include -字符串或正則表達式。 匹配的組件會被cache
  • exclude -字符串或正則表達式。任何匹配的組件都不會被cache

用法:

  • <keep-alive>包裹動態組件</keep-alive>, cache不活動的組件,不會銷魂它們。
  • <keep-alive>是一個抽象組件,不會渲染DOM元素,不會出現在父組件鏈中。

鈎子函數:(這兩個鈎子,放到聲明組件的代碼中)

  • activated: 在keep-alive組件激活時用
  • deactivated: 在keep-alive組件停用時調用。

Vue.component('tab-home', {
 template: '<div>Home component</div>',
 activated() {
  console.log('activatsse')
 },
 deactivated() {
  console.log('deactivated')
 }
})


 

 

異步組件

以工廠函數的方式定義組件。

Vue.component('async', function(resolve, reject) {  ...  })

這個工廠函數會異步解析你的組件定義。 

在這個組件被渲染的時候,會觸發該工廠函數,並把結構緩存起來供未來重新渲染。

 

工廠函數?

當一個函數返回一個對象時,並且函數沒有使用new關鍵字,這個函數稱為factory function。

不是類,也不是構造函數。

個人理解:工廠函數好像就是類,傳遞不同的參數,返回不同的對象,但對象們的結構都一樣,只是值不一樣。

const noop = () => { foo: 'bar' };
console.log(noop()); //返回 undefined, 使用大括號,JavaScript默認你想要創建一個函數體。
 
const createFoo = () => ({ foo: 'bar' });
console.log(createFoo()); //返回 { foo: "bar" },大括號外面加上小括號,大括號里面的內容被解釋為表達式

將異步組件和 webpack 的 code-splitting 功能一起配合使用,未學習這個功能!!
 

 

Promise是什么?(點擊看api)

new Promise( function(resolve, reject) {...} );

一個代表了異步操作最終完成或者失敗的對象。大多數人都在使用由其他函數創建並返回的promise.

promise本質上是一個綁定了回調的對象.

  • 通過.then形式添加回調函數。
  • 通過多次調用.then,可以添加多個回調函數。
  • 鏈式調用,涼鞋執行多個異步操作。  

誕生的原因猜測: 傳統的多重回調的寫法是各地獄,因此改用promise的方式。

   回調地獄:崩潰的寫發和讀發:

doSomething(function(result) { doSomethingElse(result, function(newResult) { doThirdThing(newResult, function(finalResult) { console.log('Got the final result: ' + finalResult); }, failureCallback); }, failureCallback); }, failureCallback);

現代的方法:
doSomething().then(function(result) { return doSomethingElse(result); }) .then(function(newResult) { return doThirdThing(newResult); }) .then(function(finalResult) { console.log('Got the final result: ' + finalResult); }) .catch(failureCallback);

或者使用箭頭函數:
doSomething() .then(result => doSomethingElse(result)) .then(newResult => doThirdThing(newResult)) .then(finalResult => { console.log(`Got the final result: ${finalResult}`); }) .catch(failureCallback);
 
        
 
        

 

解析 DOM 模板時的注意事項 

部分HTML標簽限制子元素的標簽類型,

如<ul>內部只能是<li>,如果在里面用自定義組件則會渲染報錯。

可以使用is特性,進行變通:

<table>
<tr is="blog-post-row"></tr>
</table>

但是⚠️,如果從以下來源使用模板的話,這條限制是不存在的:

 

案例: 列表渲染一章,最下面

 


 

Class用在組件上

  • 可以直接在組件上寫:
    <my-component class="baz boo"></my-component>
  • 也可以用在v-bind:class='{active: isActive}'上面, 當isActive是true時,類加上active.
<p class="foo bar active">Hi</p>

 

深入Prop  

camelCase vs kebab-case

當你使用 DOM 中的模板時,camelCase (駝峰命名法) 的 prop 名需要使用其等價的 kebab-case (短橫線分隔命名) 命名:

<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>

 當定義組件的時候,即在JavaScript中用:props: ['postTitle']

 

Prop類型:

  • 使用字符串數組的形式:
    props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
  • 使用對象形式
  • 使用對象形式:可以進行Prop的驗證。
    • type,  可以是任意類型null, 多個類型的任意一種(用數組)
    • required: true/false  是否必須填
    • default,默認可以是值,也可以是function(){ return ...}
    • 自定義驗證函數validator
  • 用到這個組件的時候,傳入的數據必須符合prop指定的類型,並通過驗證,否則browser的控制台會提示❌)
props: {
title: null,         #type可以任意類型,用null
likes: [Number, String, Date] #可以設置多個類型。
isPublished: Boolean,
commentIds: Array,
author: [Object, Function, Symbol]
}

傳遞靜態或者動態Prop類型:

 需要用 v-bind, 即使數據是靜態的,仍然需要 v-bind來告訴Vue:

 <blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>

 或者用一個變量進行動態賦值:

 <blog-post v-bind:comment-ids="post.commentIds"></blog-post>

 

 ⚠️(即使加了雙括號v-bind="xxxxx"這還是Javascript表達式)

 

可以傳遞任何類型的值給一個prop。每個類型略有使用區別:

  • 傳入一個數字:
  • 傳入一個boolean:
  • 傳入一個數組:
  • 傳入一個對象:
  • 傳入一個對象的所有屬性。綁定對象名即可 v-bind:prop-name

 

父子組件中的prop的數據流動是單向的:

但⚠️: JS中對象和數組是通過引用傳入的。所以對這兩種類型的prop, 在子組件中改變這個對象或數組,改變的是對象和數組本身,因此會影響到父組件的狀態。

 

非Prop的特性

一個非prop特性是:傳向一個組件的特性,但該組件沒有對應prop定義的特性。

這個非prop特性會添加到這個組件的根元素上。

因為組件的作者不能遇見組件會被什么場景使用,為了讓組件更加的靈活,所以組件可以接受任意的特性。

 

禁用特性繼承

Vue.component('my-component', {
inheritAttrs: false,
// ...
})

 

自定義事件


 推薦你始終使用 kebab-case 的事件名。

自定義組件v-model: 見上面用v-model案例,或者api。其實就是語法糖。

 

將原生事件綁定到組件

在v-on上使用修飾符.native,它用於監聽根元素上的原生事件。

base-input v-on:focus.native="onFocus"></base-input>

案例:

 

JS對象知識點)知識點:

A Javascript object is a collection of named values

Object是mutable: 對象的地址是引用的,不是by value。

JS variable是by value的。

Object.assign(target, ..sources) 返回一個新的Object,他的值包括target和sources,但不重復同時value會被覆蓋。

 

vm.$listeners

一個對象,包含父作用域(不含.native)的事件監聽器。

可以通過v-on='$listeners'把它傳入內部組件,即父組件上的事件監聽,也可以用在內部組件中了。

 

vm.$attrs(沒有案例,不是很懂。)

類型: { |key: string|: string}

詳細: 包含了父作用域中不作為prop被識別獲取的特性綁定。可以用v-bind='$attrs'傳入內部組件。

inheritAttrs選項和$attrs是一對兒。同時出現在2.4版本

 

選項/其他 #inheritAttrs

類型 boolean

詳細:當寫包裹一個目標元素(或另一個組件)的組件時,目標元素(或子組件)不能得到父作用域的非prop特性綁定。這些特性會‘回退’並且作為普通的HTML特性應用在目標元素上(或子組件的根元素上)。

去掉這個默認行為,可以使用inheritAttrs: false。不繼承屬性。

想要繼承特性綁定,可以使用v-bind='$attrs',把這些特性綁定到目標元素(非根元素)上。

inheritAttrs選項和$attrs是一對兒。同時出現在2.4版本

 

 
        

.sync修飾符 沒有看


 

 

<solt>插槽

通過slot可以分發內容。

Vue自定義的標簽。見:插槽

理解: 組件實例內的html會被保留。

<solt> 有一個特別的name特性,用於和其他solt區別

  • 可以在父組件的<template>元素上使用slot的name特性
  • 可以直接用在一個普通的元素上

插槽的默認內容

可以為solt提供默認內容。如在template中有一個插槽

  • 如果組件實例內沒有html內容就會使用插槽默認內容。
  • 如果父組件為這個插槽提供了內容,默認的內容就會被替換掉。 

 

編譯作用域 (不是很理解,沒有案例)

<navigation-link url="/profile">
Logged in as {{ user.name }}
</navigation-link>

可以在組件實例中的插槽位置加上{{xxx}},來插入數據。

但不能訪問url, 這屬於<navigation-link> 的作用域。

  • 父組件模板的所有東西都會在父級作用域內編譯;
  • 子組件模板的所有東西都會在子級作用域內編譯。 

 

作用域slot 

 


 

處理邊界情況(特殊情況)

訪問元素/組件

有些特定情況,需要觸及另一個組件實例內部,或手動操作DOM元素。

 

訪問子組件實例/子元素

除了prop,event, 有時需要在JS中直接訪問一個子組件。

方法:

通過使用ref特性,為子組件/元素賦予一個id引用。

例如,這個子組件:

<base-input ref="username"></base-input>

然后,用this.$refs.username來訪問組件實例。

注意⚠️: ref的使用是非響應式的,並且只會在組件渲染完成后生效。所以盡量避免使用它。

 

可以用於從父組件聚焦一個輸入框:

<input ref="input">

然后添加一個方法:
methods: { // 用來從父級組件聚焦輸入框 focus: function () { this.$refs.input.focus() } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM