国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

Vue組件的使用及個人理解與介紹

2019-11-19 12:10:12
字體:
供稿:網(wǎng)友

組件的基本使用

注冊組件

注冊組件就是利用Vue.component()方法,先傳入一個自定義組件的名字,然后傳入這個組件的配置。

 Vue.component('mycomponent',{  template: `<div>這是一個自定義組件</div>`,  data () {   return {    message: 'hello world'   }  } })

如上方式,就已經(jīng)創(chuàng)建了一個自定義組件,然后就可以在Vue實例掛在的DOM元素中使用它。

 <div id="app">  <mycomponent></mycomponent>  <my-component></my-component></div><script> var app = new Vue({  el: '#app',  data: {  },  components: {   'my-component': {    template: `<div>這是一個局部的自定義組件,只能在當(dāng)前Vue實例中使用</div>`,   }  } })</script>

直接使用Vue.component()創(chuàng)建的組件,所有的Vue實例都可以使用。還可以在某個Vue實例中注冊只有自己能使用的組件。

var app = new Vue({  el: '#app',  data: {  },  components: {   'my-component': {    template: `<div>這是一個局部的自定義組件,只能在當(dāng)前Vue實例中使用</div>`,   }  } })

模板的要求

注意:組件的模板只能有一個根元素。下面的情況是不允許的。

template: `<div>這是一個局部的自定義組件,只能在當(dāng)前Vue實例中使用</div>      <button>hello</button>`,

組件中的data必須是函數(shù)

可以看出,注冊組件時傳入的配置和創(chuàng)建Vue實例差不多,但也有不同,其中一個就是data屬性必須是一個函數(shù)。
這是因為如果像Vue實例那樣,傳入一個對象,由于JS中對象類型的變量實際上保存的是對象的引用,所以當(dāng)存在多個這樣的組件時,會共享數(shù)據(jù),導(dǎo)致一個組件中數(shù)據(jù)的改變會引起其他組件數(shù)據(jù)的改變。

而使用一個返回對象的函數(shù),每次使用組件都會創(chuàng)建一個新的對象,這樣就不會出現(xiàn)共享數(shù)據(jù)的問題來了。

關(guān)于DOM模板的解析

當(dāng)使用 DOM 作為模版時 (例如,將 el 選項掛載到一個已存在的元素上), 你會受到 HTML 的一些限制,因為 Vue 只有在瀏覽器解析和標(biāo)準(zhǔn)化 HTML 后才能獲取模板內(nèi)容。尤其像這些元素 <ul>,<ol>,<table>,<select> 限制了能被它包裹的元素,而一些像 <option> 這樣的元素只能出現(xiàn)在某些其它元素內(nèi)部。

在自定義組件中使用這些受限制的元素時會導(dǎo)致一些問題,例如:

<table> <my-row>...</my-row></table>

自定義組件 <my-row> 被認為是無效的內(nèi)容,因此在渲染的時候會導(dǎo)致錯誤。這時應(yīng)使用特殊的 is 屬性:

<table> <tr is="my-row"></tr></table>

也就是說,標(biāo)準(zhǔn)HTML中,一些元素中只能放置特定的子元素,另一些元素只能存在于特定的父元素中。比如table中不能放置div,tr的父元素不能div等。所以,當(dāng)使用自定義標(biāo)簽時,標(biāo)簽名還是那些標(biāo)簽的名字,但是可以在標(biāo)簽的is屬性中填寫自定義組件的名字。

應(yīng)當(dāng)注意,如果您使用來自以下來源之一的字符串模板,這些限制將不適用:

<script type="text/x-template">
JavaScript 內(nèi)聯(lián)模版字符串
.vue 組件
其中,前兩個模板都不是Vue官方推薦的,所以一般情況下,只有單文件組件.vue可以忽略這種情況。

組件的屬性和事件

在html中使用元素,會有一些屬性,如class,id,還可以綁定事件,自定義組件也是可以的。當(dāng)在一個組件中,使用了其他自定義組件時,就會利用子組件的屬性和事件來和父組件進行數(shù)據(jù)交流。
<img src="/assets/images/props-events.png"/>

如上如所示,父子組件之間的通信就是 props down,events up,父組件通過 屬性props向下傳遞數(shù)據(jù)給子組件,子組件通過 事件events 給父組件發(fā)送消息。
比如,子組件需要某個數(shù)據(jù),就在內(nèi)部定義一個prop屬性,然后父組件就像給html元素指定特性值一樣,把自己的data屬性傳遞給子組件的這個屬性。
而當(dāng)子組件內(nèi)部發(fā)生了什么事情的時候,就通過自定義事件來把這個事情涉及到的數(shù)據(jù)暴露出來,供父組件處理。

<my-component v-bind:foo="baz" v-on:event-a="doThis(arg1,...arg2)"></my-component>

如上代碼,

foo是<my-component>組件內(nèi)部定義的一個prop屬性,baz是父組件的一個data屬性,
event-a是子組件定義的一個事件,doThis是父組件的一個方法
過程就是這樣:

父組件把baz數(shù)據(jù)通過prop傳遞給子組件的foo;
子組件內(nèi)部得到foo的值,就可以進行相應(yīng)的操作;
當(dāng)子組件內(nèi)部發(fā)生了一些變化,希望父組件能知道時,就利用代碼觸發(fā)event-a事件,把一些數(shù)據(jù)發(fā)送出去
父組件把這個事件處理器綁定為doThis方法,子組件發(fā)送的數(shù)據(jù),就作為doThis方法的參數(shù)被傳進來
然后父組件就可以根據(jù)這些數(shù)據(jù),進行相應(yīng)的操作

屬性Props

Vue組件通過props屬性來聲明一個自己的屬性,然后父組件就可以往里面?zhèn)鬟f數(shù)據(jù)。

Vue.component('mycomponent',{  template: '<div>這是一個自定義組件,父組件傳給我的內(nèi)容是:{{myMessage}}</div>',  props: ['myMessage'],  data () {   return {    message: 'hello world'   }  } })

然后調(diào)用該組件

<div id="app">  <mycomponent my-message="hello"></mycomponent></div>

注意,由于HTML特性是不區(qū)分大小寫的,所以傳遞屬性值時,myMessage應(yīng)該轉(zhuǎn)換成 kebab-case (短橫線隔開式)my-message="hello"。

v-bind綁定屬性值
這里說一下v-bind綁定屬性值的一個特性:一般情況下,使用v-bind給元素特性(attribute)傳遞值時,Vue會將""中的內(nèi)容當(dāng)做一個表達式。
比如:

<div attr="message">hello</div>

上面這樣,div元素的attr特性值就是message。

而這樣

<div v-bind:attr="message">hello</div>

這里的message應(yīng)該是Vue實例的data的一個屬性,這樣div元素的attr特性值就是message這個屬性的值。

之所以說是一般情況,是因為class和style特性并不是這樣。用v-bind:class和class傳入正常的類名,效果是一樣的,因為對于這兩個特性,Vue采用了合并而不是替換的原則。

動態(tài)綁定特性值

根據(jù)上面,想要把父組件的屬性綁定到子組件,應(yīng)該使用v-bind,這樣,父組件中數(shù)據(jù)改變時能反映到子組件。
注意,根據(jù)父組件傳遞給子組件的屬性類型的不同,當(dāng)在子組件中更改這個屬性時,會有以下兩種情況:

當(dāng)父組件傳遞的屬性是引用類型時,在子組件中更改相應(yīng)的屬性會導(dǎo)致父組件相應(yīng)屬性的更改。

  <div id="app2">   <div>這是父組件的parentArray:{{parentArray}}</div>   <my-component :child-array="parentArray"></my-component>  </div>  <script>   Vue.component('my-component', {    template: `    <div>這是接收了父組件傳遞值的子組件的childArray: {{childArray}} <br>      <button type="button" @click="changeArray">      點擊我改變父元素的parentArray</button>     </div>`,    props: ['childArray'],    data () {     return {      counter: 1     }    },    methods: {     changeArray () {      this.childArray.push(this.counter++)     }    }   })   new Vue({    el: '#app2',    data: {     parentArray: []    }   })  </script>

當(dāng)父組件傳遞值為基本類型時,在子組件中更改這個屬性會報錯。正確的做法是,在父組件中綁定屬性值時,加上.sync修飾符。

<my-component :child-array.sync="parentArray"></my-component>

然后在子組件中改變相應(yīng)的屬性

  methods: {   changeArray () {    this.counter++    this.$emit('update:childArray', this.counter)   }  }

子組件希望對傳入的prop進行操作

一般來說,是不建議在子組件中對父組件中傳遞來的屬性進行操作的。如果真的有這種需求,可以這樣:

父組件傳遞了一個基本類型值,那么可以在子組件中創(chuàng)建一個新的屬性,并以傳遞進來的值進行初始化,之后就可以操作這個新的屬性了

props: ['initialCounter'],data: function () { return { counter: this.initialCounter }}

父組件傳遞了一個引用類型值,為了避免更改父組件中相應(yīng)的數(shù)據(jù),最好是對引用類型進行復(fù)制。復(fù)雜的情況,肯定應(yīng)該是深復(fù)制。

給子組件傳遞正確類型的值

同樣是上面的原因,靜態(tài)的給子組件的特性傳遞值,它都會把他當(dāng)做一個字符串。

<!-- 傳遞了一個字符串 "1" --><comp some-prop="1"></comp>

子組件中,特性的值是字符串 "1" 而不是 number 1。如果想傳遞正確的數(shù)值,應(yīng)該使用v-bind傳遞,這樣就能把傳遞的值當(dāng)做一個表達式來處理,而不是字符串。

<!-- 傳遞實際的 number 1 --><comp v-bind:some-prop="1"></comp>

Prop驗證

我們可以給組件的props屬性添加驗證,當(dāng)傳入的數(shù)據(jù)不符合要求時,Vue會發(fā)出警告。

Vue.component('example', { props: {  // 基礎(chǔ)類型檢測 (`null` 意思是任何類型都可以)  propA: Number,  // 多種類型  propB: [String, Number],  // 必傳且是字符串  propC: {   type: String,   required: true  },  // 數(shù)字,有默認值  propD: {   type: Number,   default: 100  },  // 數(shù)組/對象的默認值應(yīng)當(dāng)由一個工廠函數(shù)返回  propE: {   type: Object,   default: function () {    return { message: 'hello' }   }  },  // 自定義驗證函數(shù)  propF: {   validator: function (value) {    return value > 10   }  } }})

type 可以是下面原生構(gòu)造器:

String
Number
Boolean
Function
Object
Array
Symbol
type 也可以是一個自定義構(gòu)造器函數(shù),使用 instanceof 檢測。

 // 自定義Person構(gòu)造器 function Person(name, age) {  this.name = name  this.age = age } Vue.component('my-component', {  template: `<div>名字: {{ person-prop.name }}, 年齡: {{ person-prop.age }} </div>`,  props: {   person-prop: {    type: Person   // 指定類型   }  } }) new Vue({  el: '#app2',  data: {   person: 2    // 傳入Number類型會報錯  } })

非Prop類型的屬性

也可以像在html標(biāo)簽中添加data-開頭的自定義屬性一樣,給自定義組件添加任意的屬性。而不僅限于data-*形式,這樣做的話,Vue會把這個屬性放在自定義組件的根元素上。一個自定義組件的模板只能有一個根元素。

覆蓋非Prop屬性

如果父組件向子組件的非prop屬性傳遞了值,那么這個值會覆蓋子組件模板中的特性。

<div id="app3">  <my-component2 att="helloParent"></my-component2></div><script> Vue.component('my-component2', {  template: `<div att="helloChild">子組件原有的特性被覆蓋了</div>` }) new Vue({  el: '#app3' })</script>

上面渲染的結(jié)果是,div的att屬性是helloParent。
注意:前面已經(jīng)提到過,覆蓋原則對于class和style不適用,而是采用了合并(merge)的原則。

<div id="app3">  <my-component2 att="helloParent" class="class2" style="color: red;"></my-component2></div><script> Vue.component('my-component2', {  template: `<div att="helloChild" class="class1" style="background: yellow;">子組件原有的特性被覆蓋了</div>` }) new Vue({  el: '#app3' })</script>

上面的渲染結(jié)果是,div的類名是class1 class2,行內(nèi)樣式是color:red; background:yellow;。

自定義事件

通過prop屬性,父組件可以向子組件傳遞數(shù)據(jù),而子組件的自定義事件就是用來將內(nèi)部的數(shù)據(jù)報告給父組件的。

<div id="app3">  <my-component2 v-on:myclick="onClick"></my-component2></div><script> Vue.component('my-component2', {  template: `<div>  <button type="button" @click="childClick">點擊我觸發(fā)自定義事件</button>  </div>`,  methods: {   childClick () {    this.$emit('myclick', '這是我暴露出去的數(shù)據(jù)', '這是我暴露出去的數(shù)據(jù)2')   }  } }) new Vue({  el: '#app3',  methods: {   onClick () {    console.log(arguments)   }  } })</script>

如上所示,共分為以下步驟:

子組件在自己的方法中將自定義事件以及需要發(fā)出的數(shù)據(jù)通過以下代碼發(fā)送出去

this.$emit('myclick', '這是我暴露出去的數(shù)據(jù)', '這是我暴露出去的數(shù)據(jù)2')

第一個參數(shù)是自定義事件的名字
后面的參數(shù)是依次想要發(fā)送出去的數(shù)據(jù)
父組件利用v-on為事件綁定處理器

<my-component2 v-on:myclick="onClick"></my-component2>

這樣,在Vue實例的methods方法中就可以調(diào)用傳進來的參數(shù)了

注意: 在使用v-on綁定事件處理方法時,不應(yīng)該傳進任何參數(shù),而是直接寫v-on:myclick="onClick",不然,子組件暴露出來的數(shù)據(jù)就無法獲取到了

綁定原生事件

如果想在某個組件的根元素上監(jiān)聽一個原生事件。可以使用 .native 修飾 v-on

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

探究v-model

v-model可以對表單控件實現(xiàn)數(shù)據(jù)的雙向綁定,它的原理就是利用了綁定屬性和事件來實現(xiàn)的。比如input控件。不使用v-model,可以這樣實現(xiàn)數(shù)據(jù)的雙向綁定:

<div id="app4">  <input type="text" v-bind:value="text" v-on:input="changeValue($event.target.value)">  {{text}} </div> <script>   new Vue({    el: '#app4',    data: {     text: '444'    },    methods: {     changeValue (value) {      this.text = value     }    }   }) </script>

上面的代碼同樣實現(xiàn)了數(shù)據(jù)的雙向綁定。其本質(zhì)就是:

把input的value特性綁定到Vue實例的屬性text上,text改變,input中的內(nèi)容也會改變
然后把表單的input事件處理函數(shù)設(shè)置為Vue實例的一個方法,這個方法會根據(jù)輸入?yún)?shù)改變Vue中text`的值
相應(yīng)的,在input中輸入內(nèi)容時,觸發(fā)了input事件,把event.target.value傳給這個方法,最后就實現(xiàn)了改變綁定的數(shù)據(jù)的效果。
而v-model就是上面這種方式的語法糖,也就是把上面的寫法封裝了一下,方便我們使用。

使用自定義事件創(chuàng)建自定義的表單輸入組件

理解了v-model的內(nèi)幕,也就可以把這個效果用在自定義表單組件上了。
來實現(xiàn)一個簡單的只能輸入hello的表單輸入組件。

<div id="app5">  <my-component3 v-model="hello"></my-component3>  <div>{{hello}}</div></div><script> Vue.component('my-component3', {  template: `<input ref="input" type="text" :value="value" @input="checkInput($event.target.value)">`,  props: ['value'],  methods: {   checkInput (value) {    var hello = 'hello'    if (!hello.includes(value)) {     this.$emit('input', hello)     this.$refs.input.value = hello    } else {     this.$emit('input', value)    }   }  } }) new Vue({  el: '#app5',  data: {   hello: ''  } })</script>

定制組件的v-model

默認情況下,一個組件的 v-model 會使用 value 屬性和 input 事件,但是諸如單選框、復(fù)選框之類的輸入類型可能把 value 屬性用作了別的目的。model 選項可以回避這樣的沖突:

Vue.component('my-checkbox', { model: {  prop: 'checked',  // 將輸入的特性改為checked  event: 'change'    // 觸發(fā)的自定義事件類型為change }, props: {  checked: Boolean,  // this allows using the `value` prop for a different purpose  value: String }})

這樣設(shè)置的話,

<my-checkbox v-model="foo" value="some value"></my-checkbox>

上面的代碼就等同于

<my-checkbox :checked="foo" @change="val => { foo = val }" value="some value"></my-checkbox>

實際使用時,與之前不同的地方是:

把子組件中接收外部數(shù)據(jù)的prop屬性改為checked
向父組件發(fā)出事件時,事件類型應(yīng)改為change

Vue.component('my-component3', {  template: `<input ref="input" type="text" :value="checked" @input="checkInput($event.target.value)">`,  props: ['checked'],    // 屬性名改變  model: {   prop: 'checked',   event: 'change'  },  methods: {   checkInput (value) {    var hello = 'hello'    if (!hello.includes(value)) {     this.$emit('change', hello)  // 事件類型改變     this.$refs.input.value = hello    } else {     this.$emit('change', value) // 事件類型改變    }   }  } })

動態(tài)組件

通過使用保留的 <component> 元素,動態(tài)地綁定到它的 is 特性,可以讓多個組件使用同一個掛載點,并動態(tài)切換:

 <div id="app6">  <select v-model="currentComponent">   <option value="home">home</option>   <option value="post">post</option>   <option value="about">about</option>  </select>  <component :is="currentComponent"></component> </div> <script>   new Vue({    el: '#app6',    data: {     currentComponent: 'home'    },    components: {     home: {      template: `<header>這是home組件</header>`     },     post: {      template: `<header>這是post組件</header>`     },     about: {      template: `<header>這是about組件</header>`     }    }   })</script>

也可以直接綁定到組件對象上:

var Home = { template: `<header>這是home組件</header>`}new Vue({ el: '#app6', data: {  currentComponent: Home }})

保留切換出去的組件,避免重新渲染

如果把切換出去的組件保留在內(nèi)存中,可以保留它的狀態(tài)或避免重新渲染。為此可以添加一個 keep-alive 指令參數(shù):

<keep-alive> <component :is="currentComponent">  <!-- 非活動組件將被緩存! --> </component></keep-alive>

使用slot分發(fā)內(nèi)容

終于到了基本知識的最后一個了。官網(wǎng)寫的很詳細。

單個slot

上面用到的很多組件的使用方式是這樣的:

<component></component>

也就是說組件中是空的,沒有放置任何文本或元素。但是原生的html元素都是可以進行嵌套的,div里面放table
什么的。自定義組件開閉標(biāo)簽之間也可以放置內(nèi)容,不過需要在定義組件時使用slot。

slot相當(dāng)于子組件設(shè)置了一個地方,如果在調(diào)用它的時候,往它的開閉標(biāo)簽之間放了東西,那么它就把這些東西放到slot中。

當(dāng)子組件中沒有slot時,父組件放在子組件標(biāo)簽內(nèi)的東西將被丟棄;
子組件的slot標(biāo)簽內(nèi)可以放置內(nèi)容,當(dāng)父組件沒有放置內(nèi)容在子組件標(biāo)簽內(nèi)時,slot中的內(nèi)容會渲染出來;
當(dāng)父組件在子組件標(biāo)簽內(nèi)放置了內(nèi)容時,slot中的內(nèi)容被丟棄
子組件的模板:

<div> <h2>我是子組件的標(biāo)題</h2> <slot>  只有在沒有要分發(fā)的內(nèi)容時才會顯示。 </slot></div>

父組件模板:

<div> <h1>我是父組件的標(biāo)題</h1> <my-component>  <p>這是一些初始內(nèi)容</p> </my-component></div>

渲染結(jié)果:

<div> <h1>我是父組件的標(biāo)題</h1> <div>  <h2>我是子組件的標(biāo)題</h2>  <p>這是一些初始內(nèi)容</p> </div></div>

具名slot

slot可以有很多個。那么子組件對于父組件放置的多余的內(nèi)容如何放到各個slot中呢?方法就是子組件給每個slot起一個名字name,父組件放置多余的元素時,給每個元素的slot屬性分配一個代表slot的名字。到時候,多余的內(nèi)容就會根據(jù)自己的slot屬性去找具有對應(yīng)名字的slot元素。

注意:

子組件可以有一個匿名的slot,當(dāng)分發(fā)的多余內(nèi)容找不到對應(yīng)的slot時,就會進入這里面
如果子組件沒有匿名的slot,當(dāng)分發(fā)的多余內(nèi)容找不到對應(yīng)的slot時,就會被丟棄
例如,假定我們有一個 app-layout 組件,它的模板為:

<div class="container"> <header>  <slot name="header"></slot> </header> <main>  <slot></slot> </main> <footer>  <slot name="footer"></slot> </footer></div>

父組件模版:

<app-layout> <h1 slot="header">這里可能是一個頁面標(biāo)題</h1> <p>主要內(nèi)容的一個段落。</p> <p>另一個主要段落。</p> <p slot="footer">這里有一些聯(lián)系信息</p></app-layout>

渲染結(jié)果為:

<div class="container"> <header>  <h1>這里可能是一個頁面標(biāo)題</h1> </header> <main>  <p>主要內(nèi)容的一個段落。</p>  <p>另一個主要段落。</p> </main> <footer>  <p>這里有一些聯(lián)系信息</p> </footer></div>

作用域插槽

作用域插槽也是一個插槽slot,但是他可以把數(shù)據(jù)傳遞給到父組件的特定元素內(nèi),然后有父組件決定如何渲染這些數(shù)據(jù)。

首先,子組件的slot需要有一些特性(prop)

 Vue.component('my-component4', {   template: `<div>    <slot :text="hello" message="world"></slot>   </div>`,   data () {    return {     hello: [1,'2']    }   }  })

父組件在調(diào)用子組件時,需要在里面添加一個template元素,并且這個template元素具有scope特性

<div id="app7"> <my-component4>  <template scope="props">  </template> </my-component4> </div>

scope特性的值,就代表了所有子組件傳過來的數(shù)據(jù)組成的對象。相當(dāng)于

props = {  text: '',  message: ''}

最后,父組件就可以在template中渲染子組件傳過來的數(shù)據(jù)了

 <div id="app7">  <my-component4>   <template slot-scope="props">    <span>{{props.text}}</span>    <span>{{props.message}}</span>   </template>  </my-component4> </div>

最新的Vue支持將作用域插槽的屬性解構(gòu)。所以上述代碼可以簡寫為:

 <div id="app7">  <my-component4>   <template slot-scope="{text, message}">    <span>{{text}}</span>    <span>{{message}}</span>   </template>  </my-component4> </div>

作用域插槽也是插槽,只不過是多加了些特性,然后父組件多進行了些處理。

以上即是個人對Vue中的組件的理解,希望對大家有所幫助

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 丹棱县| 通道| 南充市| 河南省| 南汇区| 阜阳市| 龙州县| 镇远县| 新龙县| 武功县| 道真| 闽清县| 正镶白旗| 合肥市| 逊克县| 嘉义市| 砚山县| 延吉市| 东丽区| 沂水县| 广安市| 合作市| 扶绥县| 长丰县| 东宁县| 新龙县| 广汉市| 蓬安县| 崇义县| 郴州市| 宜都市| 梧州市| 四会市| 商河县| 和林格尔县| 鸡西市| 太谷县| 桐庐县| 延庆县| 化隆| 三江|