推薦:Vue彙總
Vue - Vue元件基礎
為了介紹Vue的元件,先用Vue的元件來改造之前實作的
TodoList
:
- Vue - 用Vue寫一個TodoList小栗子
代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TodoList</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<input v-model.trim="inputValue" type="text">
<button @click.stop="bntClick">送出</button>
<ul>
<todo-item v-for="item in list" v-bind:plan="item.value" :key="item.id"></todo-item>
</ul>
</div>
</body>
</html>
<script>
Vue.component("todo-item" , {
props: ['plan'],
template: "<li>{{plan}}</li>"
});
var vue = new Vue({
el: '#div',
data: {
inputValue: '',
id: 1,
list: []
},
methods: {
bntClick(){
if(this.inputValue !== ''){
this.list.unshift({
id: this.id++,
value: this.inputValue
});
this.inputValue = '';
}
else{
alert('寫點東西再交');
}
}
}
})
</script>
這裡用
<todo-item v-for="item in list" v-bind:plan="item.value" :key="item.id"></todo-item>
代替原來
TodoList
裡的
<li v-for="item in list" :key="item.id">{{item.value}}</li>
。
元件全局注冊
Vue.component("todo-item" , {
props: ['plan'],
template: "<li>{{plan}}</li>"
});
效果和之前的
TodoList
是一樣的。
元件局部注冊
代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TodoList</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<input v-model.trim="inputValue" type="text">
<button @click.stop="bntClick">送出</button>
<ul>
<todo-item v-for="item in list" v-bind:plan="item.value" :key="item.id"></todo-item>
</ul>
</div>
</body>
</html>
<script>
var TodoItem = {
props: ['plan'],
template: "<li>{{plan}}</li>"
};
var vue = new Vue({
el: '#div',
components: {
TodoItem: TodoItem
},
data: {
inputValue: '',
id: 1,
list: []
},
methods: {
bntClick(){
if(this.inputValue !== ''){
this.list.unshift({
id: this.id++,
value: this.inputValue
});
this.inputValue = '';
}
else{
alert('寫點東西再交');
}
}
}
})
</script>
元件局部注冊:
var TodoItem = {
props: ['plan'],
template: "<li>{{plan}}</li>"
};
需要使用時(局部作用域),在
components
中指定即可。
components: {
TodoItem: TodoItem
}
效果也是一樣的。
元件基礎介紹
元件是可複用的Vue執行個體,且帶有一個名字:在上面例子中是
<todo-item>
。我們可以在一個通過 new Vue建立的Vue根執行個體中,把這個元件作為自定義元素來使用:
<ul>
<todo-item v-for="item in list" v-bind:plan="item.value" :key="item.id"></todo-item>
</ul>
因為元件是可複用的Vue執行個體,是以它們與new Vue接收相同的選項,例如
data
、
computed
、
watch
、
methods
以及生命周期鈎子等。僅有的例外是像
el
這樣根執行個體特有的選項。
元件的複用
你可以将元件進行任意次數的複用:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TodoList</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<input v-model.trim="inputValue" type="text">
<button @click.stop="bntClick">送出</button>
<ul>
<todo-item v-for="item in list" v-bind:plan="item.value" :key="item.id"></todo-item>
<todo-item v-for="item in list" v-bind:plan="item.id" :key="item.id"></todo-item>
</ul>
</div>
</body>
</html>
<script>
var TodoItem = {
props: ['plan'],
template: "<li>{{plan}}</li>"
};
var vue = new Vue({
el: '#div',
components: {
TodoItem: TodoItem
},
data: {
inputValue: '',
id: 1,
list: []
},
methods: {
bntClick(){
if(this.inputValue !== ''){
this.list.unshift({
id: this.id++,
value: this.inputValue
});
this.inputValue = '';
}
else{
alert('寫點東西再交');
}
}
}
})
</script>
效果:
每個元件都會各自獨立維護它的
plan
。因為你每用一次元件,就會有一個它的新執行個體被建立(上面例子中被建立了6次,通過
v-for
)。
data 必須是一個函數
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>count</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<count></count>
<count></count>
<count></count>
</div>
</body>
</html>
<script>
Vue.component('count',{
data: function () {
return {
cnt: 1
}
},
template: '<button @click="cnt++">點選{{cnt}}</button>'
});
var vue = new Vue({
el: '#div'
})
</script>
效果:
這樣點選一個元件,不會影響其他元件,因為元件的
data
選項是一個函數,是以每個執行個體可以維護一份被傳回對象的獨立的拷貝。
如果
data
不是一個函數呢?我的Vue版本(
v2.6.10
)是用不了的,和官網有點不同。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>count</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<count></count>
<count></count>
<count></count>
</div>
</body>
</html>
<script>
Vue.component('count',{
data:{
cnt: 1
},
template: '<button @click="cnt++">點選{{cnt}}</button>'
});
var vue = new Vue({
el: '#div'
})
</script>
效果:
沒有數字。
在官網文檔中是可以使用的,可能是因為版本不同,官網文檔大概的意思是:如果
data
不是一個函數,元件複用就可能會存在問題,因為所有執行個體的
data
實際上是指向同一個
data
,某一個執行個體改變了
data
的值,其他執行個體的
data
同樣也就改變了。
元件的組織通常一個應用會以一棵嵌套的元件樹的形式來組織:
例如,你可能會有頁頭、側邊欄、内容區等元件,每個元件又包含了其它的像導航連結之類的元件。
為了能在模闆中使用,這些元件必須先注冊,以便Vue能夠識别。有兩種元件注冊方式:全局注冊和局部注冊,在前面也都介紹過了。全局注冊的元件可以用在其被注冊之後的任何 (通過new Vue) 新建立的Vue根執行個體,也包括其元件樹中的所有子元件的模闆中。
通過 Prop 向子元件傳遞資料
在第一個用Vue元件改造
TodoList
的例子中就使用過
Prop
向子元件傳遞資料,
Prop
是你可以在元件上注冊的一些自定義
attribute
。當一個值傳遞給一個
prop attribute
的時候,它就變成了那個元件執行個體的一個
property
。為了給
todo-item
元件傳遞
plan
,我們可以用一個
props
選項将其包含在該元件可接受的
prop
清單中:
Vue.component("todo-item" , {
props: ['plan'],
template: "<li>{{plan}}</li>"
});
一個元件預設可以擁有任意數量的
prop
,任何值都可以傳遞給任何
prop
。在上述模闆中,你會發現我們能夠在元件執行個體中通路這個值,就像通路
data
中的值一樣。
例子:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>TodoList</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<input v-model.trim="inputValue" type="text">
<button @click.stop="bntClick">送出</button>
<ul>
<todo-item v-for="item in list" :plan="item.value" :key="item.id"></todo-item>
<todo-item v-for="item in list" plan="+1" :key="item.id"></todo-item>
</ul>
</div>
</body>
</html>
<script>
Vue.component("todo-item" , {
props: ['plan'],
template: "<li>{{plan}}</li>"
});
var vue = new Vue({
el: '#div',
data: {
inputValue: '',
id: 1,
list: []
},
methods: {
bntClick(){
if(this.inputValue !== ''){
this.list.unshift({
id: this.id++,
value: this.inputValue
});
this.inputValue = '';
}
else{
alert('寫點東西再交');
}
}
}
})
</script>
效果:
通過
v-bind
可以傳遞動态的值,通過變量名直接傳遞靜态的值。
<todo-item v-for="item in list" :plan="item.value" :key="item.id"></todo-item>
<todo-item v-for="item in list" plan="+1" :key="item.id"></todo-item>
監聽子元件事件
代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>count</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<count :count="count" v-on:bnt-click="bntClick"></count>
</div>
</body>
</html>
<script>
Vue.component("count" , {
props: ['count'],
template: `
<button v-on:click="$emit('bnt-click')">{{count}}</button>
`
});
var vue = new Vue({
el: '#div',
data: {
count: 1
},
methods: {
bntClick(){
this.count++;
}
}
})
</script>
效果:
當點選這個按鈕時,我們需要告訴父級元件将
count
加一。Vue執行個體提供了一個自定義事件的系統來解決這個問題。父級元件可以像處理native DOM(如
click
)事件一樣通過
v-on
監聽子元件執行個體的任意事件:
<count :count="count" v-on:bnt-click="bntClick"></count>
同時子元件可以通過調用内建的
$emit
方法并傳入事件名稱來觸發一個事件:
Vue.component("count" , {
props: ['count'],
template: `
<button v-on:click="$emit('bnt-click')">{{count}}</button>
`
});
事件名稱要用
bnt-click
這種格式,不要用
bntClick
這種格式,不然就不起作用(我這個版本是這樣的)。
使用事件抛出一個值
代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>count</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<count :count="count" v-on:bnt-click="bntClick"></count>
</div>
</body>
</html>
<script>
Vue.component("count" , {
props: ['count'],
template: `
<button v-on:click="$emit('bnt-click' , 5)">{{count}}</button>
`
});
var vue = new Vue({
el: '#div',
data: {
count: 1
},
methods: {
bntClick(value){
this.count += value;
}
}
})
</script>
點四下:
當在父級元件監聽這個事件的時候,我們可以通過
$event
通路到被抛出的這個值。
代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>count</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<count :count="count" v-on:bnt-click="count += $event"></count>
</div>
</body>
</html>
<script>
Vue.component("count" , {
props: ['count'],
template: `
<button v-on:click="$emit('bnt-click' , 5)">{{count}}</button>
`
});
var vue = new Vue({
el: '#div',
data: {
count: 1
}
})
</script>
效果是一樣的。
在元件上使用 v-model
自定義事件也可以用于建立支援
v-model
的自定義輸入元件。記住:
<input v-model="searchText">
等價于:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
當用在元件上時,
v-model
則會這樣:
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
為了讓它正常工作,這個元件内的
<input>
必須:
- 将其
綁定到一個名叫 value attribute
的 value
上prop
- 在其
事件被觸發時,将新的值通過自定義的 input
事件抛出。input
寫成代碼之後是這樣的:
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
現在
v-model
就應該可以在這個元件上完美地工作起來了:
<custom-input v-model="searchText"></custom-input>
通過插槽分發内容
和HTML元素一樣,我們經常需要向一個元件傳遞内容,Vue自定義的
<slot>
元素讓這變得非常簡單:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>count</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<slot-demo>kaven</slot-demo>
</div>
</body>
</html>
<script>
Vue.component("slot-demo" , {
template: `
<div>
<p>welcome </p>
<slot></slot>
</div>
`
});
var vue = new Vue({
el: '#div'
})
</script>
效果:
動态元件
有的時候,在不同元件之間進行動态切換是非常有用的。
可以通過 Vue的
<component>
元素加一個特殊的
is attribute
來實作:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>count</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="div">
<component v-bind:is="currentComponent">kaven</component>
<button @click="click">切換</button>
</div>
</body>
</html>
<script>
Vue.component("slot-welcome" , {
template: `
<div>
<p>welcome </p>
<slot></slot>
</div>
`
});
Vue.component("slot-hello" , {
template: `
<div>
<p>hello </p>
<slot></slot>
</div>
`
});
var vue = new Vue({
el: '#div',
data: {
currentComponent: 'slot-hello'
},
methods: {
click(){
if(this.currentComponent === 'slot-hello'){
this.currentComponent = 'slot-welcome'
}
else{
this.currentComponent = 'slot-hello'
}
}
}
})
</script>
效果:
點選按鈕。