Vue組件
文章目錄
一.概念
在vue裏,一個組件的本質上是一個擁有預定義選項的一個Vue實例
二.組件的使用
- 定義(註冊)組件
- 調用(使用)組件
將組件就看成是一個函數
1.組件的註冊
-
全局組件註冊
當前Vue項目中,任何組件中都可以去使用
/**
* componentName 組件的名字
* componentOptions 組件的選項配置
*/
Vue.component(componentName,componentOptions);
//com1 全局組件
Vue.component('com1', {
template: `<div>
我是hello組件
</div>`
});
-
局部組件註冊
在哪個組件中註冊的,就只能使用在哪個組件中
/**
* 局部組件註冊
* 在組件的components配置選項中去定義
* new Vue 構造函數 ,生成的實例,一般我們叫它根組件
* componentName1 局部組件名字
* componentOptions1 局部組件對應的選項
* */
new Vue({
components:{
componentName1:componentOptions1
componentName2:componentOptions2
}
});
在組件的components配置選項中去定義
new Vue,生成的實例,一般我們叫它根組件
compontentOptions就是一個對象,裏面有配置與new Vue時類似,但有一些例外:
- 組件沒有el選項,因爲後續調用組件在哪裏,這個組件的掛載點就是哪裏
- 必須有template或者render選項,用來規定組件的模版內容
- data選項必須是一個函數返回對象的形式
2.組件的調用
將組件名當做自定義的html標籤使用即可
//全局組件註冊
Vue.component('hello', {
// 注意:必須有template和render選項,用來規定組件的模版內容
template: `<div>我是全局組件hello </div>`
});
//根組件
var vm = new Vue({
el: '#app'
});
//調用組件 這個div可以看成是根組件的template
<div id="app">
<hello></hello>
</div>
調用時,必須要在根組件裏面,我這裏的根組件的掛載點是 #app, 這個hello 組件放在了根組件的div中,實際上就是把hello組件的template渲染到了根組件上,那麼這裏就是 hello組件是 根組件Root的子組件
//com1 全局組件
Vue.component('com1', {
// 這裏,com3是不能用的,會報錯,因爲com3是com2的子組件,只能在com2中使用
template: `<div>
我是hello組件
</div>`
});
//com2和com1是全局組件,任何組件都可以使用
Vue.component('com2', {
//com3和com4只能在com2中使用,局部組件,只屬於com3和com4的子組件
template:
`
<div>
我是com2組件
<com3></com3>
</div>`
,
components: {
'com3': {
template: `<div>我是com3組件,只能在com2中使用</div>`
},
'com4': {
template: `<div>我是com4組件,只能在com2中使用</div>`
}
}
});
//根組件
var vm = new Vue({
el: '#app'
});
3.組件的複用
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script>
// 定義一個名爲 button-counter 的新組件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">你點擊了 {{ count }} times.</button>'
})
var vm = new Vue({
el: '#app'
});
</script>
定義的全局組件可以在根組件下任意使用多個,進行組件的複用
注意
data必須是一個函數
爲什麼組件的data選項要寫成函數形式呢?
原因是組件是可以進行復用的,如果data直接寫成對象,那麼複用的時候,會造成數據污染(多個實例對象共用一個變量)
當我們點擊上面按鈕的時候,因爲使用了函數形式的返回data數據,所以每個組件都會各自獨立維護它的變量count,y因爲每用一個組件,就會有一個新的實例被創建.
4.組件名
組件名不能是現有的html標籤名,也不能是之前已經註冊過的組件(實際上是可以,只不過會覆蓋之前的)
Vue.component('nav', {
template: '<button v-on:click="count++">你點擊了 {{ count }} times.</button>'
})
var vm = new Vue({
el: '#app'
});
nav是html5的標籤名,這裏不能使用,會報錯.也不能是 a,button,div之類,總之不能使用現有的html標籤名.
組件名的規則:
可以使用短橫線寫法:
- hello-world
可以使用駝峯寫法
- HelloWorld
調用組件時,需要使用短橫線寫法 上述兩種,都可以使用hello-world
但是也有例外,以下三種情況可以無視這種規則
1.寫在template選項中
//寫在template選項中,可以無視這種規則
Vue.component('com1', {
template:
'<div>
COM1
<HelloWorld></HelloWorld>
</div>'
})
Vue.component('HelloWorld', {
template: '<div>HelloWorld</div>'
})
//這裏又template選項,會覆蓋頁面上的#app
//駝峯命名的組件,這裏使用駝峯和短橫線都可以使用
var vm = new Vue({
el: '#app',
template:
`<div id='app'>
<HelloWorld></HelloWorld>
<hello-world></hello-world>
<com1></com1>
</div> `
});
2.寫在裏面的
我們寫了組件這麼多代碼,特別是在寫template選項中的寫模版內容代碼時,發現非常的不方便,沒有語法高亮,也沒有代碼提示,這時可以將模版內容,放置在一個script標籤裏面
要注意:
- 需要設置script 的type屬性爲text/x-template
- 給這個script設置一個id
調用時,直接使用template:’#xxxx’即可
<script id="appTemplate" type="text/x-template">
<div id='app'>
<HelloWorld></HelloWorld>
<hello-world></hello-world>
<com1></com1>
</div>
</script>
<script>
Vue.component('com1', {
template: '<div>COM1<HelloWorld></HelloWorld></div>'
})
Vue.component('HelloWorld', {
template: '<div>HelloWorld</div>'
})
//調用模版內容
var vm = new Vue({
template: `#appTemplate`
});
</script>
這種情況時,使用template選項中調用組件,可以無視上面的組件調用規則
3.vue後綴的單文件組件時
5.組件的注意事項
-
全局組件註冊時,必須要放置在new Vue之前
Vue.component('com1', { template: '<button v-on:click="count++">你點擊了 {{ count }} times.</button>' }) //上面定義的全局組件,必須寫在new Vue之前,否則會報錯 var vm = new Vue({ el: '#app' });
//這是錯誤的寫法,報錯 var vm = new Vue({ el: '#app' }); Vue.component('com1', { template: '<button v-on:click="count++">你點擊了 {{ count }} times.</button>' })
2.組件的template模版內容,必須只能有一個根元素.
<script id="appTemplate" type="text/x-template"> //調用組件時,必須只能有一個根組件 <div id='app'> <HelloWorld></HelloWorld> <hello-world></hello-world> <com1></com1> </div> </script>
<script id="appTemplate" type="text/x-template"> //這種情況會報錯,因爲必須只能有一個根元素 <HelloWorld></HelloWorld> <hello-world></hello-world> <com1></com1> </script>
三.Props選項
將組件看成是一個函數,props就是這個函數接收到的參數集合
prop就是props中具體的一個參數
//這樣理解props選項
//定義一個函數,接收props形參
function hello(props){
}
//調用hello函數 傳遞一個對象,給到參數
hello({name:liuqiao,age:18,sex:'男'});
//props指的就是這些個參數集合
props=>{name:liuqiao,age:18,sex:'男'}
name =>prop 這都是其中的一個prop
age =>prop
sex =>prop
1.props命名規則
HTML 中的 屬性 名是大小寫不敏感的,所以瀏覽器會把所有大寫字符解釋爲小寫字符,
如果是在html中寫prop時,如果props設置時是使用駝峯命名法,則需要改用短橫線
```js
Vue.component('hello', {
props: ['postTitle'],
template: '<div> 我的姓名是:{{ postTitle }} </div>'
})
<div id="app">
<hello post-title='liuqiao'></hello>
</div>
```
注意,這裏的props命名規則與組件名命名的規則一樣,也有三種情況可以無視這種規則
- 寫在template選項中
- 寫在裏面的
- vue後綴的單文件組件時
官網的說明是:使用字符串模板,那麼這個限制就不存在了。
2.設置props
組件定義時,如何設置形參?就是設置props選項
最簡單的方式就是:寫成數組形式,數組中每一項就是一個prop
定義的每一個prop,可以直接通過實例對象去訪問到,就像訪問data數據和computed數據一樣
Vue.component('hello', {
//props選項:寫成數組形式,數組中每一項就是一個prop
props: ['name', 'age', 'sex'],
template: `
<div>
我的姓名是:{{ name }},我的年齡:{{age}}
<button @click="hi('abc')">點我</button>
</div>
`,
methods:{
hi(a){
console.log(this.name+this.age+a);
console.log(this.sex);//不傳遞sex參數時,打印結果是undefined
}
}
})
3.傳遞參數
調用組件時,在組件上的標籤上寫屬性即可
注意:調用時:不傳遞參數是沒有問題的
//調用模版內容
var vm = new Vue({
el:'#app',
template: `
<div id="app">
<hello name='liuqiao' age='19'></hello>
</div>
`
});
如:
hello組件上name就是liuqiao
hello組件上age就是19
hello組件上sex沒有傳遞,是undefined
4.props的默認值
如果調用組件時,沒有傳遞某個prop下來,那麼組織中的這個prop的值是undefined
設置props默認值:也就是調用時如果沒有傳遞某prop,那我就使用默認值
類似函數中es6的設置默認值
es6中函數設置默認值
funciton hello(name='liuqiao'){
}
hello();
在組件中給props設置默認值>關鍵點是:將數組格式的props改成對象格式
props:{
key1:{
type:String,
default:'liuqiao'
},
key2:{
type:Number,
default:18
}
}
key1,key2就是props的名字
type:是接收這個參數的數據類型
default:是這個prop的默認值
Vue.component('hello', {
props: {
'name':{
type:String,
default:'zhangsan'
},
'age':{
type:Number,
default:18
}
},
template: `
<div>
我的姓名是:{{ name }},我的年齡:{{age}}
</div>
`
})
var vm = new Vue({
el: '#app',
template: `
<div id="app">
<hello></hello>
</div>
`
});
5.props的校驗
如果調用組件時,我希望可以保證你傳過來的prop是有效的,所以需要設置 正確的數據類型
比如我在組件中規定,你需要傳遞string類型的參數,你就必須傳遞string類型,否則報錯
這叫做props的類型校驗
官網的例子是這樣的:
Vue.component('my-component', {
props: {
// 基礎的類型檢查 (`null` 和 `undefined` 會通過任何類型驗證)
propA: Number,
// 多個可能的類型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 帶有默認值的數字
propD: {
type: Number,
default: 100
},
// 帶有默認值的對象
propE: {
type: Object,
// 對象或數組默認值必須從一個工廠函數獲取
default: function () {
return { message: 'hello' }
}
},
// 自定義驗證函數
propF: {
validator: function (value) {
// 這個值必須匹配下列字符串中的一個
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
我這邊自己也就是總結了4中寫法:
1.直接寫需要的類型
2.寫成對象形式
3.寫成數組形式(意思是string和number都可以接收)
props:{
key:String //第一種
key:{
type:String //第二種
}
key:[String,Number],//第三種
//第四種,自定義驗證函數
key:{
abc:function(){
}
}
}
其中type類型可以有以下幾種:
String
Number
Boolean
Array
Object
Date
Function
- Symbol
另外,傳遞prop的時候,默認都是字符串格式,需要轉化的話,只需加上 v-bind 即可
Vue.component('hello', {
props: {
'name':String,
'age':{
type:Number
},
'sex':[String,Number]
},
template: `
<div>
我的姓名是:{{ name }},我的年齡:{{age}}
</div>
`
})
//調用模版內容
var vm = new Vue({
el: '#app',
template: `
<div id="app">
<hello name='liuqiao'></hello>
<hello :age='18'></hello>
<hello sex='男'></hello>
</div>
`
});
v-bind可以省略,直接使用冒號 : 即可
6.傳遞動態的props
傳入一個對象所有需要的屬性
Vue.component('hello', {
props: {
name: String,
age: Number
},
template: `
<div>
我的姓名是:{{ name }},我的年齡:{{age}}
</div>
`
})
//調用模版內容
var vm = new Vue({
el: '#app',
data: {
userinfo: {
name: 'liuqiao',
age: 28
}
},
template: `<hello v-bind='userinfo'></hello>`
});
調用組件時,直接屬性上寫v-bind=
<hello v-bind='userinfo'></hello>
實際上,這種寫法等價於
<hello v-bind:name='userinfo.name' v-bind:age='username.age'></hello>
7.Props單向數據流
單向數據流:props傳遞參數時,都是單向下行綁定的.父組件的prop會向下傳遞到子組件,反過來不行
所有的prop都使得其父子prop之間形成了一個單向下行綁定.父級 prop 的更新會向下流動到子組件中,但是反過來則不行。這樣會防止從子組件意外變更父級組件的狀態,從而導致你的應用的數據流向難以理解。
額外的,每次父級組件發生變更時,子組件中所有的 prop 都將會刷新爲最新的值。這意味着你不應該在一個子組件內部改變 prop。如果你這樣做了,Vue 會在瀏覽器的控制檯中發出警告。
上面一段是官網的原話.總結一句話就是:不要去直接修改prop傳過來的數據
一般有兩種情況改變prop
-
父組件傳過來的初始值 通過props傳過來的,子組件想作爲自己本地存儲
props:{ msg:{ type:String, required:true } }, data(){ return{ msgInfo:this.msg; } }
這種方式,就是在本地聲明一個屬性,然後初始化去接收,作爲本地存儲,就不會修改prop了
-
父組件傳過來的初始值,通過props傳過來,然後需要自己做轉換
props:{ msg:{ type:String, required:true } }, computed:{ newMsg:function(){ return this.msg.trim().toLowerCase() } }
這種方式,就是通過一個計算屬性去處理