Vue本身是基於組件化開發的,每個組件相當於一個Vue實例。Vue的組件部分搞清楚,是學好Vue的重要一步。
相關demo示例的github地址:vue-component
https://github.com/liwudi/Vue.git
1、Vue組件的全局註冊
要註冊一個全局組件,可以使用 Vue.component(tagName, options)。例如:
Vue.component('my-component', {
// 選項
})
- 1
- 2
- 3
使用的時候直接在dom中使用組件名。例如:
<my-component></my-component>
- 1
下面是一個完整的帶有屬性傳遞的組件應用實例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<ol>
<!--使用組件-->
<todo-item
v-for="item in todoList"
v-bind:todo="item"
></todo-item>
</ol>
</div>
<script>
//定義一個最簡單的組件
Vue.component('todo-item',{
props:['todo'],
template:'<li>name:{{todo.name}},age:{{todo.age}}</li>'
});
new Vue({
el:'#app',
data:{
todoList:[{name:'張三',age:23},{name:'李四',age:24},{name:'王五',age:25}]
}
});
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
2、Vue組件的局部註冊
可以通過Vue實例/組件示例的實例選項 components 來註冊屬於他們自己的組件。
var Child = {
template:"<p>我是中國人</p>"
}
new Vue({
el:'#app',
components: {
"my-comp": Child
}
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
一個完整的局部組件註冊的示例demo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<todo-item></todo-item>
</div>
<script>
var Child = {
template: '<div>A custom component!</div>'
};
new Vue({
el:'#app',
components:{
'todo-item': Child
}
});
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
3、組件中的data應該是函數
在new Vue()的實例的過程中,data可以是一個對象,但是在組件component中,data是一個函數。
下面的寫法在Vue中會報錯。
Vue.component('my-com',{
template:'<span>{{message}}</span>',
data: {
message: 1
}
})
- 1
- 2
- 3
- 4
- 5
- 6
這個示例纔是正確的寫法:
Vue.component('my-com',{
template:'<span>{{message}}</span>',
data: function () {
return {
message: 1
}
}
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
4、組件應該是組合使用的
在react中,最外層是一個根組件,裏層的組件被一層層的嵌套在外層組件內,從而形成一個組件樹。
在 Vue 中,父子組件的關係可以總結爲 prop 向下傳遞,事件向上傳遞。父組件通過 prop 給子組件下發數據,子組件通過事件給父組件發送消息。
使用props傳遞數據的語法:
Vue.component('child', {
// 聲明 props
props: ['message'],
// 就像 data 一樣,prop 也可以在模板中使用
// 同樣也可以在 vm 實例中通過 this.message 來使用
template: '<span>{{ message }}</span>'
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
4_1、通過props進行屬性傳遞的demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<ol>
<!--使用組件-->
<my-com
v-bind:todo="message"
></my-com>
</ol>
</div>
<script>
//定義一個最簡單的組件
Vue.component('my-com',{
props:['todo'],
template:'<h3>{{todo}}</h3>'
});
new Vue({
el:'#app',
data:{
message:'hello!'
}
});
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
5、camelCase vs. kebab-case
兩者的區別是駝峯式命名規則,以及短橫線分隔式命名。
在JavaScript中,如果使用駝峯式命名camelCase。
由於在HTML中不區分大小寫,我們需要轉換成短橫線分隔式命名kebab-case。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<ol>
<!--使用組件-->
<todo-item
my-todo="hello"
></todo-item>
</ol>
</div>
<script>
//定義一個最簡單的組件
Vue.component('todo-item',{
props:['myTodo'],
template:'<h2>{{myTodo}}</h2>'
});
new Vue({
el:'#app'
});
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
6、動態props
一般使用V-bind的方式,把一個屬性動態的綁定到props。
<todo-com v-bind:todo='message'></todo-com>
- 1
如果沒有v-bind,就會展示message這個字符串;但是現在,展示的是在data中動態綁定的變量message的信息。
下面是一個動態綁定props的示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<ol>
<!--使用組件-->
<todo-item
v-bind:my-todo="message"
></todo-item>
</ol>
</div>
<script>
//定義一個最簡單的組件
Vue.component('todo-item',{
props:['myTodo'],
template:'<h2>{{myTodo}}</h2>'
});
new Vue({
el:'#app',
data: {
message: 'hello world!'
}
});
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
7、動態props,綁定一個對象作爲props傳遞給子組件。
比如一個對象是這樣的:
todo: {
text: 'Learn Vue',
isComplete: false
}
- 1
- 2
- 3
- 4
然後:
<todo-item v-bind="todo"></todo-item>
- 1
等價於:
<todo-item
v-bind:text="todo.text"
v-bind:is-complete="todo.isComplete"
></todo-item>
- 1
- 2
- 3
- 4
一個完整的示例demo如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<todo-com v-bind="todo"></todo-com>
</div>
<script>
//定義一個最簡單的組件
Vue.component('todo-com',{
props:['text','isComplete'],
template:'<h2>I has {{isComplete ? "completed ":"not completed "}}{{text}}</h2>'
});
new Vue({
el:'#app',
data: {
todo:{
text: 'Learn Vue',
isComplete: false
}
}
});
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
8、組件通信,props傳遞子組件的使用場景。
1、在子組件中獲取props的值,並且在子組件中需要改變這個值。
我們可以定義一個局部變量把props的值賦值給它。
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
- 1
- 2
- 3
- 4
2、在子組件中需要把這個props進行一定的處理,再進行使用。
定義一個計算屬性,處理 prop 的值並返回
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
- 1
- 2
- 3
- 4
- 5
- 6
9、props驗證
要指定驗證規則,需要用對象的形式來定義 prop,而不能用字符串數組:
Vue.component('example', {
props: {
// 基礎類型檢測 (`null` 指允許任何類型)
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 value > 10
}
}
}
})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
10、非props特性
所謂的非props特性是不用props申明,直接傳給子組件的一些特性。比如: class。
一般而言,父組件的非props特性對子組件的特性進行覆蓋和合並。
下面的示例中,如果父組件不使用class=’color2’,則數組顏色是紅色,如果使用了,則顏色爲綠色。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<style>
.color1{
color: red;
}
.color2{
color: green;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<foo-component class="color2" v-bind:foo-message="fooMessage"></foo-component>
</div>
<script>
var fooComponent = {
props: ['fooMessage'],
template: '<div class="color1"> {{ fooMessage }} </div>'
};
var vm = new Vue({
components: {
'foo-component': fooComponent
},
el: '#app',
data: {
fooMessage: 12345
}
});
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
11、自定義事件(子組件向父組件傳值。)
使用 $emit(eventName) 觸發一個事件。
使用 $on(eventName) 接受一個事件。
但是一般使用的時候,使用 v-on:eventName = eventFunction 的方式定義事件。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<button-com v-on:parent="myEvent"></button-com>
</div>
<script>
var Child = {
template:'<button v-on:click="childEvent"> {{ num }} </button>',
data: function () {
return {
num: 0
}
},
methods:{
childEvent: function () {
this.num += 1;
this.$emit("parent",this.num);
}
}
};
var vm = new Vue({
el:'#app',
data:{
total: 0
},
components: {
'button-com': Child
},
methods: {
myEvent: function (data) {
console.log(data);
}
}
})
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
12、.sync修飾符
<comp :foo.sync="bar"></comp>
- 1
等價於
<comp :foo="bar" @update:foo="val => bar = val"></comp>
- 1
當子組件需要更新 foo 的值時,它需要顯式地觸發一個更新事件:
this.$emit('update:foo', newValue)
- 1
下面是完整的demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue-demo</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
</head>
<body>
<div id="app">
<div>{{bar}}</div>
<my-comp :foo.sync="bar"></my-comp>
</div>
<script>
Vue.component('my-comp', {
template: '<div @click="increment">{{copyFoo}}點我+1</div>',
data: function() {
return {copyFoo: this.foo}
},
props: ['foo'],
methods: {
increment: function() {
this.$emit('update:foo', ++this.copyFoo);
}
}
});
new Vue({
el: '#app',
data: {bar: 0}
});
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32