一、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>