前言
本文主要介绍属性、事件和插槽这三个vue基础概念、使用方法及其容易被忽略的一些重要细节。如果你阅读别人写的组件,也可以从这三个部分展开,它们可以帮助你快速了解一个组件的所有功能。
组件的分类
一般来说,Vue.js 组件主要分成三类:
- 由 vue-router 产生的每个页面,它本质上也是一个组件(.vue),主要承载当前页面的 HTML
结构,会包含数据获取、数据整理、数据可视化等常规业务。整个文件相对较大,但一般不会有 props 选项和 自定义事件,因为它作为路由的渲染,不会被复用,因此也不会对外提供接口 - 不包含业务,独立、具体功能的基础组件,比如日期选择器、模态框等。这类组件作为项目的基础控件,会被大量使用,因此组件的 API进行过高强度的抽象,可以通过不同配置实现不同的功能。比如笔者开源的 iView,就是包含了 50 多个这样基础组件的 UI 组件库。
- 业务组件。它不像第二类独立组件只包含某个功能,而是在业务中被多个页面复用的,它与独立组件的区别是,业务组件只在当前项目中会用到,不具有通用性,而且会包含一些业务,比如数据请求;而独立组件不含业务,在任何项目中都可以使用,功能单一,比如一个具有数据校验功能的输入框。
Vue.js 组件
组件(Component)是 Vue.js 最强大的功能之一。
组件可以扩展 HTML 元素,封装可重用的代码。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
全局组件
所有实例都能用全局组件。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
<blog-post title="入海"></blog-post>
</div>
<script>
//全局注册
Vue.component('button-counter',{
data:function(){//data必须是一个函数
return {
count:0
}
},
template:'<button v-on:click="count++">{{count}}</button>'
})
new Vue({el:"#app"})
</script>
</body>
</html>
这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中.
局部注册
var Child = {
template: '<div>一个自定义组件</div>'
}
new Vue({
// ...
components: {
// <my-child></my-child> 将只在父组件模板中可用
'my-child': Child
}
})
data 必须是一个函数 一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
var counter = {
template:`<button @click="num++">{{num}}</button>`,
data:function(){return {num:1}}
}
new Vue({
el:"#app",
components:{
counter,
}
})
Prop
prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<blog-post v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"></blog-post>
</div>
<script type="text/javascript">
Vue.component('blog-post',{
props:['title'],
template:'<h1>{{title}}</h1>'
})
new Vue({
el:"#app",
data:{
posts:[
{id:1,title:'入海'},
{id:1,title:'樱花'},
{id:1,title:'梦醒'}
]
}
})
</script>
</body>
</html>
动态 Prop
类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="./js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<input v-model="parentmsg" />
<blog-post v-bind:msg="parentmsg"></blog-post>
</div>
<script type="text/javascript">
Vue.component('blog-post',{
props:['msg'],
template:'<p>{{msg}}</p>'
})
new Vue({
el:"#app",
data:{
parentmsg:"樱花"
}
})
</script>
</body>
</html>
Vue.component('example', {
props: {
// 基础类型检测 (`null` 指允许任何类型)
propA: Number,
// 可能是多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数值且有默认值
propD: {
type: Number,
default: 100
},