元件
元件(Component)是前端在單頁面應用(SPA)上最好的一種實現方式,把所有功能模組拆解成單獨的元件,每個元件都有獨立的作用域,且還可以相互通訊
認識單頁面應用(SPA)
在傳統的頁面之間跳轉,是通過重新整理,重新渲染一個頁面而實現,在渲染的過程中勢必要載入外部資原始檔,頁面在伺服器中渲染出來是通過一系列的生命週期,在這個過程中會因為網速等硬體問題直接影響頁面的載入速度,為解決這一問題,前端在新的設計模式上引入了元件的概念,頁面之間的跳轉變成了元件之間的切換,不需要重新載入整個頁面,也不用考慮頁面的生命週期,換成元件的生命週期,在效能上大大的提升了。
Vue 的元件實現
全域性元件
<div id="app">
<!--元件的使用-->
<global-component></global-component>
</div>
//元件的定義 Vue.component(元件名稱, {template})
Vue.component(`global-component`, {
template: `<h1>全域性元件</h1>`
})
var vm = new Vue({
el: `#app`
})
最終渲染的效果
<div id="app">
<h1>全域性元件</h1>
</div>
區域性元件
<div id="app">
<!--元件的使用-->
<private-component></private-component>
</div>
//元件的定義 Vue.component(元件名稱, {template})
var vm = new Vue({
el: `#app`,
components:{
`private-component`: {
template: `<h1>區域性元件</h1>`
}
}
})
最終渲染的效果
<div id="app">
<h1>區域性元件</h1>
</div>
元件是一個單獨的作用域
每個元件都有單獨的作用域
<div id="app">
<p>{{count}}</p>
<component1/>
</div>
var vm = new Vue({
el: `#app`,
data: {
count: 10
},
methods: {
increment: function(){
this.count += 1;
}
},
components:{
`component1`: {
template: `<button v-on:click="increment">{{ count }}</button>`,
data: function(){
//在元件裡面 data 一定是 function 並返回一個物件
return {
count: 0
}
},
methods: {
increment: function(){
this.count += 1;
}
}
}
}
})
渲染結果為
<div id="app">
<p>10</p>
<!--
此按鈕每次點選都會自增 1,而 p 標籤永遠都是為 10
原因為元件的作用域是單獨的
-->
<button>0</button>
</div>
特殊的 HTML 結構中使用 is
比如在下拉選單(select)元素裡面,子元素必須為 option,則在使用元件的時候用 is
<div id="app">
<select>
<option is="privateOption"></option>
</select>
</div>
var vm = new Vue({
el: `#app`,
components: {
`privateOption`: {
template: `<option value=1>1</otpion>`
}
}
})
渲染結果
<div id="app">
<select>
<option value="1">1</option>
</select>
</div>
動態元件 – :is
<div id="app" style="display: none;">
<input type="button" value="changeLight" @click="changeLight" />
<br/>
<p :is="show"></p>
</div>
<script type="text/javascript">
var vm = new Vue({
el: `#app`,
data: {
show: `red`,
},
methods:{
changeLight: function(){
this.show = this.show == `red` ? `green` : `red`;
}
},
components: {
red: {
template: `<h1>Red</h1>`
},
green: {
template: `<h1>Green</h1>`
}
}
})
</script>
元件屬性
元件的屬性要先宣告後使用,props: [`屬性名`…]
<div id="app">
<!--元件的使用-->
<private-component title="元件屬性" :text="mess"></private-component>
</div>
//元件的定義 Vue.component(元件名稱, {template})
var vm = new Vue({
el: `#app`,
data: {
mess: `-動態屬性`
}
components:{
`private-component`: {
template: `<h1>{{title + text}}</h1>`,
props: [`title`, `text`]
}
}
})
最終渲染的效果
<div id="app">
<h1>元件屬性-動態屬性</h1>
</div>
元件自定義事件
和元件屬性不一樣的在於 <元件名 v-bind:屬性名=””>,屬性名要在元件中先宣告再使用:props: [`屬性名`]
自定義事件:<元件名 v-on:自定義事件名=””>,自定義事件名不需要宣告,直接用 $emit() 觸發
<div id="app">
<p>{{total}}</p>
<increment-total v-on:count="incrementTotal"></increment-total>
</div>
var vm = new Vue({
el: `#app`,
data: {
total: 0
},
methods: {
incrementTotal: function(){
this.total += 1;
}
},
components: {
`incrementTotal`: {
template: `<input type="button" @click="incrementTotal" value="Total" />`,
data: function(){
return {
total: 0
}
},
methods: {
incrementTotal: function(){
this.total += 1;
this.$emit(`count`)
}
}
}
}
})
slot 分發內容
Vue 元件預設是覆蓋渲染,為了解決這一問題,Vue 提出了 slot 分發內容
<div id="app">
<component1>
<h1>Sam</h1>
<h1>Lucy</h1>
</component1>
</div>
Vue.component(`component1`, {
template: `
<div>
<h1>Tom</h1>
<slot></slot>
</div>
`
})
最終渲染的效果
<div id="app">
<component1>
<h1>Tom</h1>
<!--
如果在元件定義的 template 當中沒有 <slot></slot>,那麼下面兩個 h1 標籤將不會存在
換句話說就是 <slot></slot> = <h1>Sam</h1><h1>Lucy</h1>
<slot></slot>可以放到 <h1>Tom</h1> 上面進行位置調換
-->
<h1>Sam</h1>
<h1>Lucy</h1>
</component1>
</div>
具名 slot
如果要將元件裡面不同的子元素放到不同的地方,那就為子元素加上一個屬性 slot=”名稱”,然後在元件定義的時候用名稱對應位置 <slot name=”名稱”></slot>,其它沒有 slot 屬性的子元素將統一分發到 <slot></slot> 裡面
<div id="app">
<component1>
<h1>Sam</h1>
<h1 slot="lucy">Lucy</h1>
</component1>
</div>
Vue.component(`component1`, {
template: `
<div>
<slot name="lucy"></slot>
<h1>Tom</h1>
<slot></slot>
</div>
`
})
最終渲染的效果
<div id="app">
<component1>
<!--<slot name="lucy"></slot> = <h1 slot="lucy">Lucy</h1>-->
<h1>Lucy</h1>
<h1>Tom</h1>
<!--其它沒有 slot 屬性的子元素將全部分發到 <slot></slot> 標籤-->
<h1>Sam</h1>
</component1>
</div>
模版寫法
<template id="component1">
<div>
<input type="text" v-model="name"/>
<p>{{name}}</p>
</div>
</template>
<div id="app">
<component1/>
</div>
var vm = new Vue({
el: `#app`,
components: {
`component1`: {
template: `#component1`,
data: function(){
return {name: `Tom`};
}
}
}
})