註冊元件
元件其他補充
元件資料存放
父子元件通訊
父級向子級傳遞資訊
子級向父級傳遞資訊
插槽slot
1.1什麼是元件化
1.2
註冊元件的基本步驟
建立元件構造器
註冊元件
使用元件
<div id="app">
<mycpn></mycpn>
</div>
<script src="../js/vue.js"></script>
<script>
//1.建立元件構造器物件
const cpn = Vue.extend({
template: `
<div>
<h2>我是標題</h2>
<p>我是內容,哈哈哈哈</p>
<p>我是內容,呵呵呵呵呵呵</p>
</div>`
}) Vue.component('mycpn',cpn) const app = new Vue({
el: '#app',
data: { }
})
</script>
1.3全域性元件和區域性元件
當我們通過呼叫Vue.component()註冊元件時,元件的註冊是全域性的
這意味著該元件可以在任意Vue例項下使用
 
如果我們註冊的元件時掛載在某個例項中,那麼就是區域性元件
 
<div id="app">
<mycpn></mycpn>
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script>
//1.建立元件構造器
const cpn = Vue.extend({
template: `
<div>
<h2>我是標題1</h2>
<p>我是內容 哈哈哈哈</p>
</div>
`
})
// 2.註冊元件(全域性元件,意味著可以再多個vue例項中使用)
Vue.component('mycpn',cpn) const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn:cpn
}
})
</script>
1.4父元件和子元件:
<div id="app">
<cpn2></cpn2>
<h2>--------</h2>
<cpn1></cpn1>
</div> <script src="../js/vue.js"></script> <script>
// 1.建立第一個元件構造器
const cpn1 = Vue.extend({
template: `<div>
<h2>我是子元件標題</h2>
<p>我是子元件內容 哈哈哈</p>
</div>`
}) //2.建立第二個元件構造器
const cpn2 = Vue.extend({
template:`<div>
<h2>我是父元件標題</h2>
<p>我是父元件內容 呵呵呵呵呵</p>
<cpn1></cpn1>
</div>`,
//在元件內部使用帶s的components
components:{
cpn1: cpn1
}
})
const app = new Vue({
el:'#app',
data:{
},
components:{
cpn2: cpn2,
cpn1: cpn1
}
})
</script>
1.5註冊元件語法糖:
<div id="app">
<cpn></cpn>
</div>
<script src="../js/vue.js"></script>
<script> //一.全域性元件註冊的語法糖
//1.創造元件構造器
// const cpn1 = Vue.extend() //2.註冊元件
// Vue.component('cpn',{
// template: `<div>
// <h2>我是全域性元件標題</h2>
// <p>我是全域性元件內容 呵呵呵呵呵</p>
// </div>`
// }) const app = new Vue({
el: '#app',
data: {
},
components:{
cpn: {
template: `<div>
<h2>我是區域性元件標題</h2>
<p>我是區域性元件內容 呵呵呵呵呵</p>
</div>`
}
}
})
</script>
1.6模板的分離寫法:
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div> <!-- 第一種模板 注意:必須是text/x-template型別-->
<!-- <script type="text/x-template" id="cpn">
<div>
<h2>我是標題</h2>
<p>我是內容</p>
</div>
</script> --> <!-- 第二種模板:template -->
<template id="cpn">
<div>
<h2>這是標題哈哈</h2>
<p>這是內容哈哈</p>
</div>
</template> <script src="../js/vue.js"></script>
<script> // 1.註冊一個全域性元件
Vue.component('cpn',{
template: '#cpn'
}) const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
1.7元件資料的存放
元件自己的資料存放在哪裡呢?
元件物件也有一個data屬性(也可以有methods等屬性,下面我們有用到)
只是這個data屬性必須是一個函式
而且這個函式返回一個物件,物件內部儲存著資料

<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div> <!-- 第一種模板 注意:必須是text/x-template型別-->
<!-- <script type="text/x-template" id="cpn">
<div>
<h2>我是標題</h2>
<p>我是內容</p>
</div>
</script> --> <!-- 第二種模板:template -->
<template id="cpn">
<div>
<h2>{{title}}</h2>
<p>這是內容哈哈</p>
</div>
</template> <script src="../js/vue.js"></script>
<script> // 1.註冊一個全域性元件
Vue.component('cpn',{
template: '#cpn',
data() {
return {
title: '測試檔案' }
}
}) const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
1.8演示:為什麼data是一個函式?
首先,如果不是一個函式,vue直接回報錯
其次,原因在於Vue讓每個元件物件都返回一個新的物件,因為如果是同一個物件的,元件在多次使用後相互影響
 
<div id="app">
<cpn></cpn>
<cpn></cpn>
<cpn></cpn>
</div>
<template id="cpn">
<div>
<h2>當前計數是 : {{counter}}</h2>
<button @click='innerment'>+</button>
<button @click='denerment'>-</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script> Vue.component('cpn',{
template: '#cpn',
data () {
return {
counter: 0
}
},
methods:{
innerment(){
this.counter++
},
denerment(){
this.counter--
},
}
}) const app = new Vue({
el: '#app',
data: {
message: '你好啊'
}
})
</script>
1.9.1父子元件的通訊
一些資料需要從上層傳遞到下層
vue官方提到:
通過props向子元件傳遞資料
通過事件向父元件傳送訊息
props基本用法
在元件中,使用選項props來宣告需要從父級接收到的資料
props的值有兩種方式
方式一: 字串陣列,陣列中的字串就是傳遞時的名稱
方式二: 物件,物件可以設定傳遞時的型別,也可以設定預設值等
<body>
<div id="app">
<!-- 使用cpn子元件 動態繫結movies和message -->
<cpn :cmovies="movies" :cmessage="message"></cpn>
</div> <!-- 子元件模板 -->
<template id="cpn">
<div>
<ul>
<!-- 迴圈cmovies的電影 -->
<li v-for="item in cmovies">{{item}}</li>
</ul>
<h2>{{cmessage}}</h2>
</div>
</template>
<!-- 引入vue檔案 -->
<script src="../js/vue.js"></script>
<script>
//例項化子元件
const cpn = {
//模板物件,和el掛載點相似,注意:template必須要有id為cpn的
template: '#cpn',
//子元件data必須是一個函式,每個元件呼叫的時候不能是同一個物件,
//只能是一個函式,必須帶有return返回值
data(){
return {}
},
methods:{},
//父元件向子元件傳遞資訊使用props方法
props:{
cmovies:{
type:Array,
default(){
return []
},
required: true
},
cmessage: {
type:String,
default: 'aaaa',
required: true
}
}
} //根元件,也可以算父元件,例項化vue物件
const app = new Vue({
//掛載點:#app
el: '#app',
//物件中資料現在不用函式
data: {
message: '測試檔案',
movies:['肖申克的救贖','當幸福來敲門','加勒比海盜','了不起的蓋茨比']
},
//註冊元件
components:{
cpn
}
})
</script>
除了陣列之外,也可以使用物件,當需要對props進行型別驗證時,就需要物件寫法了
支援的型別:
String(字串) Number(數字) Boolean(布林值) Array(陣列)
Object(物件) Date(時間) Function(函式) Symbol
 
1.9.2子級向父級傳遞
方式:自定義事件
流程:
在子元件中,通過$emit() 來出發事件
在父元件中,通過v-on來監聽子元件事件
 
<div id="app">
<cpn @itembtn="cpnclick"></cpn>
</div> <template id="cpn">
<div>
<button v-for="item in categories"
@click="itemclick(item)">{{item.name}}</button>
</div>
</template> <script src="../js/vue.js"></script>
<script>
const cpn = {
template: '#cpn',
data () {
return {
categories: [
{id: 'aaa',name: '開啟應用'},
{id: 'bbb',name: '獲取應用'},
{id: 'ccc',name: '新建應用'},
{id: 'ddd',name: '儲存應用'},
{id: 'eee',name: '關閉應用'},
]
}
},
methods: {
itemclick (item) {
console.log(item.id)
this.$emit('itembtn',item)
}
}
} const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn
},
methods:{
cpnclick (item) {
console.log(item.id)
}
}
})
</script>
2.0父子元件的訪問方式: $children
有時候需要父元件直接訪問子元件,子元件直接訪問父元件,或者子元件訪問根元件
父元件訪問子元件: 使用$children或者$refs
子元件訪問父元件: 使用$parent
 
<div id="app">
<cpn ref="ccc"></cpn>
<cpn ref="bbb"></cpn>
<cpn ref="aaa"></cpn>
<button @click='btnClick'>測試按鈕</button>
</div> <template id="cpn">
<div>
<h2>我是子元件</h2>
</div>
</template> <script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
methods: {
btnClick() {
//1$children 用法比較少 是獲取全部的自元件裡面方法
// console.log(this.$children)
// // this.$children[0].showMessage()
// for(let c of this.$children){
// c.showMessage()
// console.log(c.name)
// } //2 $refs 用的最多 注意此處寫的 是refs ,上面寫的是ref=""
// $refs => 物件型別 ,預設是一個空的物件 如果使用上面要用 ref="bbb"
console.log(this.$refs.aaa.name)
this.$refs.aaa.showMessage()
console.log(this.$refs.bbb.name)
this.$refs.bbb.showMessage()
console.log(this.$refs.ccc.name)
this.$refs.ccc.showMessage() }
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: `中級的慾望 通過努力可以獲得
低階的慾望 通過放縱可以獲得`
}
},
methods: {
showMessage() {
console.log('頂級的慾望 通過煎熬才能獲得')
}
}
}
}
})
</script>
this.$children是一個數組型別,它包含了所有子元件物件
$children的缺陷
通過$children訪問子元件時,是一個數組型別,訪問其中的子元件必須通過索引值.
但是當子元件過多,我們需要拿到其中一個時,往往不能確定他的索引值,甚至還可能發生變化
有時候,我們想明確獲取其中一個特定的元件,這個時候就可以使用$refs
 
$refs的使用:
$refs和ref指令通常是一起使用的
首先,我們通過ref 給某一個子元件繫結一個特定的ID
其次,通過this.$refs.ID就可以訪問到該元件了
 
 
2.1父子元件的訪問方法: $parent
儘管在Vue開發中,我們允許通過$parent來訪問父元件,但是在真實開發中儘量不要這樣做
子元件應該儘量避免訪問父元件的資料,因為這樣耦合度太高了
如果我們將子元件放在另外一個元件之內,很可能該父元件沒有對應的屬性,往往會引起問題
另外,更不好做的是用過$parent直接改父元件的狀態,那麼父元件中的狀態將變得不穩定
 
<div id="app">
<h2>這是vue例項</h2>
<cpn></cpn>
</div> <template id="cpn">
<div>
<h2>這是自元件</h2>
<ccpn></ccpn>
</div>
</template> <template id="ccpn">
<div>
<h2>我是子元件內部元件</h2>
<button @click="btnClick">點選按鈕</button>
</div>
</template> <script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: '你好啊'
},
components: {
cpn: {
template: '#cpn',
data(){
return {
name: `
低階的慾望 通過放縱就可獲得
高階的慾望 通過自律方可獲得
頂級的慾望 通過驕傲才可獲得`
}
},
components: {
ccpn: {
template: '#ccpn',
methods: {
btnClick() {
//1第一種 $parent 只能訪問父級元件的資料,但是耦合性很高,不能擴充套件
// console.log(this.$parent)
// console.log(this.$parent.name) //2第二種,通過root 獲取根元件的資料
console.log(this.$root)
console.log(this.$root.message)
}
}
}
}
}
}
})
</script>
2.2插槽slot
編譯作用域:
父元件模板的所有東西都會在父級作用域內編譯,子元件模板的所有東西都會在子級作用域內編譯
 
插槽的作用:為了讓我們封裝的元件更加具有擴充套件性
如何使用slot:
在子元件中,使用特殊的元素<slot>就可以為子元件開啟一個插槽
該插槽的插入什麼內容取決於父元件如何使用
<div id="app">
<cpn>
<span>姓名</span>
<input type="text" name='username' placeholder="請輸入姓名">
</cpn>
<cpn>
<span>密碼</span>
<input type="text" name="password" placeholder="請輸入密碼">
</cpn>
<cpn>
<button>登入</button>
<button>註冊</button>
</cpn>
</div> <template id="cpn">
<div>
<!-- <h2>使用slot</h2>
<button>slot</button> -->
<slot>
<button>初始按鈕</button>
</slot>
</div>
</template> <script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hell Vue.js'
},
components: {
cpn: {
template: '#cpn',
data() {
return {}
},
methods:{}
}
}
})
</script>
具名插槽slot
當子元件的功能複雜時,插槽並非一個
只要給slot元素一個name屬性即可
<slot name="myslot"></slot>
<div id="app">
<cpn>
<button slot="left">返回</button>
</cpn>
<cpn>
<span slot="left">姓名</span>
<input type="text" slot="center" placeholder="請輸入姓名">
</cpn>
<cpn>
<span slot="left">密碼</span>
<input type="text" slot="center" placeholder="請輸入密碼">
</cpn>
<cpn>
<button slot="left">登入</button>
<button slot="right">註冊</button>
</cpn>
</div> <template id="cpn">
<div>
<slot name="left"></slot>
<slot name="center"></slot>
<slot name="right"></slot>
<slot name="noname"></slot>
</div>
</template> <script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello Vue.js'
},
components:{
cpn: {
template: '#cpn',
methods:{},
data() {
return {}
},
props:{},
computed:{}
}
}
})
</script>
作用域插槽:
父元件替換插槽的標籤,但是內容由子元件來提供
 
<div id="app">
<cpn v-show="isShow"></cpn>
</div> <template id="cpn">
<div>
<h2>我是子元件</h2>
<h3>你有為自己努力過嗎</h3>
<button v-show="isShow"></button>
</div>
</template> <script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello Vue.js',
isShow: true
},
components: {
cpn: {
template: '#cpn',
props:{},
methods:{},
data () {
return {
isShow: false
}
}
} }
})
</script>
插槽作用域的使用:
核心是在slot中加上屬性: :data
然後在父元件中呼叫自元件資料: slot-scope="slot"
 
<div id="app">
<cpn></cpn>
<cpn>
<span slot="aaa">測試檔案</span>
</cpn>
<cpn>
<div slot="aaa" slot-scope="slot">
<span v-for="item in slot.data">{{item}} -</span>
</div>
</cpn>
<cpn>
<div slot="aaa" slot-scope="slot">
<span v-for="item in slot.data">{{item}} $</span>
</div>
</cpn>
<cpn>
<div slot="aaa" slot-scope='slot'>
<!-- <span v-for="item in slot.data">{{item}}</span> -->
<span>{{slot.data.join('--')}}</span>
</div>
</cpn>
</div> <template id="cpn">
<div>
<slot name='aaa' :data="pLanges">
<ul>
<li v-for="item in pLanges">{{item}}</li>
</ul>
</slot>
</div>
</template> <script src="../js/vue.js"></script>
<script>
const app = new Vue({
el: '#app',
data: {
message: 'hello Vue.js'
},
components:{
cpn: {
template: '#cpn',
data() {
return {
pLanges: ['C++','python','java','js','php']
}
}
}
}
})
</script>