一、Vue組件概念
組件是可復用的 Vue 實例,且帶有一個名字,例如:
Vue.component("input-content", {
data: function () {
return {
message: ""
}
},
template: `<div>
<input type="text" v-model="message">
<p>輸入的值為{{message}}</p>
</div>`
});
在這個例子中,組件的名字是:input-content
, 可以通過new Vue 創建的 Vue 根實例中,把這個組件作為自定義元素來使用
<div id="app">
<input-content></input-content>
</div>
因為組件是可復用的 Vue 實例,所以它們與 new Vue 接收相同的選項,例如 data、computed、watch、methods 以及生命周期鉤子等。僅有的例外是像 el 這樣根實例特有的選項。
二、Vue組件組織
為了能在模板中使用,這些組件必須先注冊以便 Vue 能夠識別。這里有兩種組件的注冊類型:全局注冊和局部注冊。全局注冊的組件可以用在其被注冊之后的任何 (通過 new Vue) 新創建的 Vue 根實例,也包括其組件樹中的所有子組件的模板中。
三、組件傳值
組件傳值主要有父組件向子組件傳值和子組件向父組件傳值
-
父組件向子組件傳值:通過prop向子組件傳遞數據
舉例說明:
<body>
<div id="app">
<input-content :content="message"></input-content>
</div>
<script src="js/vue.js"></script>
<script>
Vue.component("input-content", {
props: ["content"],
data: function () {
return {
content: ""
}
},
template: `<div>
<p>父組件傳過來的值為:{{content}}</p>
</div>`
});
const vm = new Vue({
el: '#app',
data: {
message: 56
}
});
</script>
</body>F
上面這段代碼定義了父組件中的message的值通過props向子組件<input-content></input-content>
傳入,具體步驟如下。
- 第一步 :子組件首先定義一個props選項,表示已經準備好接收來自父組件中message數據。
- 第二步:子組件準備接受數據的時候就在標簽里說明一下我要接收的是父組件的message數據,也就是上面代碼中的
<input-content :content="message"></input-content>
,這樣父組件中的message數據就傳給子組件了。這里傳值的時候注意了,如果傳的是對象或者數組就必須綁定才能接收到,如果是靜態數值就不需要綁定。
-
子組件向父組件傳值,用一個書籍管理來舉例
上面是效果圖,思路是這樣的,輸入書籍的信息后,在表格里顯示出來,這里運用Vue組件傳值的思路,將書籍信息的輸入框作為子組件,顯示的表格作為父組件,也可以反著來,輸入框作為父組件。表格作為子組件,這里主要為練習子組件向父組件傳值。
- 首先布局用bootstrap,就不做過多介紹
- 接下來是綁定數據,就是將輸入的書籍信息作為一個數組傳給父組件顯示出來
1.首先定義子組件,將表單作為template模版寫入子組件中
Vue.component("book-list", {
data: function () {
return {
}
},
template: `
<form action="">
<div class="form-group">
<label for="exampleInputEmail1">書名</label>
<input type="text" class="form-control" id="exampleInputEmail1">
</div>
<div class="form-group">
<label for="exampleInputPassword1">作者</label>
<input type="text" class="form-control" id="exampleInputPassword1">
</div>
<div class="form-group">
<label for="exampleInputPassword1">價格</label>
<input type="text" class="form-control" id="exampleInputPassword1">
</div>
<div class="form-group">
<label for="exampleInputPassword1">數量</label>
<input type="text" class="form-control" id="exampleInputPassword1">
</div>
<button type="button" class="btn btn-default" @click="addbook">添加書籍</button>
</form>
`,
});
2.在data里定義四個對象,分別與書籍信息的四個屬性綁定
Vue.component("book-list", {
props: ["books"],
data: function () {
return {
name: "", //與書名綁定
author: "", //與作者綁定
price: "", //與價格綁定
number: "", //與數量綁定
}
},
template: `
<form action="">
<div class="form-group">
<label for="exampleInputEmail1">書名</label>
<input type="text" class="form-control" id="exampleInputEmail1" v-model.lazy="name">`
</div>
<div class="form-group">
<label for="exampleInputPassword1">作者</label>
<input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy="author">
</div>
<div class="form-group">
<label for="exampleInputPassword1">價格</label>
<input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy.number="price">
</div>
<div class="form-group">
<label for="exampleInputPassword1">數量</label>
<input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy.number="number">
</div>
<button type="button" class="btn btn-default" @click="addbook">添加書籍</button>
</form>
`,
});
- 將書籍信息添加到定義的一個
books
數組中去
1 .由于books
數組在父組件中,這里就步入正題了,子組件向父組件傳值。先定義一個book
對象,來裝綁定的書籍信息
methods: {
addbook: function () {
const book = {
name: this.name,
author: this.author,
price: this.price,
number: this.number
};
},
},
2.那么這個book
對象要如何傳到父組件中去呢,這里用到監聽子組件事件$emit
方法,就好比是一個人給另一個人寄東西,寄東西需要啥?有要寄去的東西,有寄東西的方式,還要有對方的地址。這里就當是把書籍信息book
寄到books
數組中去,寄的東西有了,那么我怎么寄?選什么快遞?$emit
方法就好比是快遞。這個快遞有啥?是不是有寄的東西,有地址。this.$emit("book", book);
第一個book
就相當于是地址,第二個book
相當于是要寄的東西。快遞送到了我要怎么去通知父組件?這個時候就用到了<book-list @book="addbook"></book-list>
。就說在某某快遞來取東西,這個時候父組件就知道了東西寄到了。那么book對象傳到了,就到了下一步。
3.將book
添加到books
數組中
data: {
books: [],
},
methods: {
addbook: function (book) {
this.books.push(book);
}
}
4.在父組件中用v-for方法遍歷books
數組
<tr v-for="(content,index) in books">
<td>{{index+1}}</td>
<td>{{content.name}}</td>
<td>{{content.author}}</td>
<td><input type="number" name="" id="" v-model.number="content.price"></td>
<td><input type="number" name="" id="" v-model.number="content.number"></td>
<td><button @click="delebook">刪除</button></td>
</tr>
這個時候就實現了添加書籍信息顯示在列表中這一基本功能。但是會發現這本書沒有編號,一開始的想法是用數組下標來作為編號,這時就出現了一個問題,當刪除一本書的時候,就會把后面的編號打亂,就沒有達到給一本書編號的的基本功能,解決方法是用獲取當前數組的長度作為書的編號,添加一本書數組的長度就加1,再把當前數組長度作為當前書籍的編號,所以再刪除一本書的時候就不會對書的編號產生影響
5.獲取數組長度作為書籍編號,但是數組定義在了父元素上,所以就用props屬性來給子元素傳值,然后再回傳給父元素作為書籍的編號。這里props屬性的運用就不做過多介紹了。
6.源碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>書籍管理</title>
<link rel="stylesheet" href="css/bootstrap.css">
<style>
input {
width: 55px;
}
</style>
</head>
<body>
<div id="app">
<div class="container">
<h3>書籍管理系統</h3>
<table class="table table-striped table-bordered">
<tr>
<th>序號</th>
<th>編號</th>
<th>名稱</th>
<th>作者</th>
<th>價格</th>
<th>數量</th>
<th>操作</th>
</tr>
<tr v-for="(content,index) in books">
<td>{{index+1}}</td>
<td>{{content.id}}</td>
<td>{{content.name}}</td>
<td>{{content.author}}</td>
<td><input type="number" name="" id="" v-model.number="content.price"></td>
<td><input type="number" name="" id="" v-model.number="content.number"></td>
<td><button @click="delebook">刪除</button></td>
</tr>
<tr>
<td>總價格:{{allprice}}</td>
</tr>
</table>
<div>
<h4>添加書籍</h4>
<book-list @book="addbook" :books="books"></book-list>
</div>
</div>
</div>
</body>
<script src="js/jquery-3.4.1.js"></script>
<script src="js/bootstrap.js"></script>
<script src="js/vue.js"></script>
<script>
Vue.component("book-list", {
props: ["books"],
data: function () {
return {
name: "",
author: "",
price: "",
number: "",
}
},
template: `
<form action="">
<div class="form-group">
<label for="exampleInputEmail1">書名</label>
<input type="text" class="form-control" id="exampleInputEmail1" v-model.lazy="name">
</div>
<div class="form-group">
<label for="exampleInputPassword1">作者</label>
<input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy="author">
</div>
<div class="form-group">
<label for="exampleInputPassword1">價格</label>
<input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy.number="price">
</div>
<div class="form-group">
<label for="exampleInputPassword1">數量</label>
<input type="text" class="form-control" id="exampleInputPassword1" v-model.lazy.number="number">
</div>
<button type="button" class="btn btn-default" @click="addbook">添加書籍</button>
</form>
`,
methods: {
addbook: function () {
const book = {
id: this.books.length + 1,
name: this.name,
author: this.author,
price: this.price,
number: this.number
};
this.$emit("book", book);
},
},
});
// --------------------------------------------------------------------------------------
const vm = new Vue({
el: "#app",
data: {
books: [],
},
methods: {
addbook: function (book) {
this.books.push(book);
},
//刪除書籍功能
delebook: function (index) {
this.books.splice(index, 1);
}
},
computed: {
//計算當前書籍的總價
allprice: function () {
let totalprice = 0;
let books = this.books;
books.forEach(function (book) {
totalprice = totalprice + book.price * book.number;
});
return totalprice;
}
},
});
</script>
</html>