概述
组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展HTML元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用is特性进行了扩展的原生 HTML 元素。组件注册的时候需要为该组件指定各种参数。
组件定义
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
let component = {
data: function () {
return { count: 0 }
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
}
一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝
组件注册
要想进行组件使用得先进行组件注册
1. 全局注册
可以使用Vue.component(tagName, options) 注册一个全局组件, 注册之后可以用在任何新创建的 Vue 根实例的模板中
Vue.component('my-component-name',component)
2. 局部注册
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。局部注册的组件只能在当前组件中使用
new Vue({
el: '#app',
components: { 'component-a': ComponentA, 'component-b': ComponentB }
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>组件基础</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
{{msg}}
<!-- <my-com2></my-com2> -->
<my-com1></my-com1>
</div>
<script>
// 定义组件
let component1 = {
data() {
return {
comMsg: '组件数据'
}
},
template: `
<div>
<p>我是vue的组件</p>
<h1>{{comMsg}}</h1>
<button @click="clickHandler">修改数据</button>
</div>
`,
methods: {
clickHandler() {
this.comMsg = '新的组件数据'
}
}
}
let component2 = {
data() {
return {
}
},
template: `
<div>
<p>组件二</p>
<my-com1></my-com1>
</div>
`,
//局部注册
components: {
'my-com1': component1
}
}
// 组件注册
// 全局注册
Vue.component('my-com2', component2)
let vm = new Vue({
el: '#app',
data: {
msg: 'hello vue component'
},
methods: {
},
//局部注册
components: {
'my-com1': component1
}
})
</script>
</body>
</html>
组件交互
组件 A 在它的模板中使用了组件 B。它们之间必然需要相互通信:父组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。
1.prop 向下传递
props
父组件通过属性绑定的方式将参数传递给子组件,子组件通过props声明期望从父组件那里获取的参数。camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>
prop类型
希望每个prop都有指定的值类型。这时,你可以以对象形式列出prop,这些property的名称和值分别是prop各自的名称和类型
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
prop验证
我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: { type: String, required: true },
// 带有默认值的数字
propD: { type: Number, default: 100 }
})
Vue.component('my-component', {
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () { return { message: 'hello' } } },
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1 }
}
}
})
动态传参
prop 可以通过v-bind动态赋值。传递什么类型的变量就可以将该类型变量直接进行赋值,也可以赋常量。如果不使用v-bind就只能传递字符串。
1. 传入一个数字
<blog-post v-bind:likes="42"></blog-post>
<blog-post v-bind:likes="post.likes"></blog-post>
2. 传入一个布尔值
<blog-post v-bind:is-published="false"></blog-post>
3. 传入数组
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
4. 传入一个对象
<blog-post v-bind:author="{ name: 'Veronica', company: 'Veridian Dynamics' }" ></blog-post>
2.事件向上传递
自定义事件
自定义事件是子组件向父组件传递状态的一种机制。事件名大小写严格区分。
子组件
this.$emit('myEvent')
父组件
<my-component v-on:myEvent="doSomething"></my-component>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>组件基础</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="app">
{{msg}}
<my-com1 @my-event="childHandler" :msg-attr="11" :flag="true"></my-com1>
</div>
<script>
// 定义组件
let component1 = {
data() {
return {
comMsg: '我是子组件数据'
}
},
template: `
<div>
<button @click="emitHandler">发送数据</button>
</div>
`,
methods: {
clickHandler() {
this.comMsg = '新的组件数据'
},
emitHandler() {
// 两个参数,第一个参数是向上发送事件的名称
// 第二个参数,是发送上去的子组件数据
this.$emit('my-event', this.comMsg)
}
},
created() {
console.log(this.flag);
}
}
// 组件注册
// 全局注册
// Vue.component('my-com2', component2)
let vm = new Vue({
el: '#app',
data: {
msg: 'hello vue component'
},
methods: {
childHandler(val) {
console.log(val);
}
},
components: {
'my-com1': component1
}
})
</script>
</body>
</html>