自定义组件、组件之间传值
说到自定义组件,我们先来了解下什么是组件。
组件
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。
使用组件
想要使用组件,就需要先注册一个组件。而组件又分为全局组件和局部组件。
全局注册
到目前为止,我们只用过 Vue.component
来创建组件:
Vue.component('my-component-name', {
// ... 选项 ...
})
这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。比如:
Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。
局部注册
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
然后在 components 选项中定义你想要使用的组件:
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。
注意局部注册的组件在其子组件中不可用。
data必须是一个函数
当我们定义这个 <button-counter>
组件时,你可能会发现它的 data
并不是像这样直接提供一个对象:
data: {
count: 0
}
取而代之的是,一个组件的 data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
data: function () {
return {
count: 0
}
}
如果 Vue 没有这条规则,点击一个按钮就可能会影响到其它所有实例,即点击一个按钮,其它按钮出现同样的效果。
Prop
Prop类型
到这里,我们只看到了以字符串数组形式列出的 prop:
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
但是,通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
这不仅为你的组件提供了文档,还会在它们遇到错误的类型时从浏览器的 JavaScript 控制台提示用户。
Prop验证
我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。
为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
template
template属性
template组件的模板html,属性值拼接字符串
template中可以调用简单的可以直接返回的一元运算符,并且能直接返回数据的,也可以调用js的全局方法比如,Date.now(),但是不能调用自己在全局定义的变量
template标签
template标签,HTML5提供的新标签,更加规范和语义化 ;
可以把列表项放入template标签中,然后进行批量渲染;
在vue中template节点在html生成的时候不会显示出来 ;
可以使用v-for把想要多次出现的内容重复出现,却不会出现<template></template>
标签。
<template v-for="i in 5">
<h5>我是一个h5标签</h5>
<p>我是一个p标签</p>
</template>
组件传值
对于组件传值,有父组件向子组件传值、子组件向父组件传值、非相关组件之间传值。
1. 父组件向子组件传值
父组件向子组件传值 ,使用props
父组件部分:Parent.vue
<template>
<div>
<ul>
<li v-for="(item,index) in nameList" :key="index">{{item.name}}</li>
</ul>
</div>
</template>
<script>
export default {
props: ["nameList"]
};
</script>
2. 子组件向父组件传值
子组件向父组件传值 ,使用事件派发
($emit)
父组件部分:Parent.vue
<template>
<div>
<div>这是父组件</div>
<child :name-list='names' @emitData='getData'></child>
</div>
</template>
<script>
import child from './child.vue'
export default {
components:{
child
},
data(){
return{
names:[
{name:'柯南'},
{name:'小兰'},
{name:'工藤新一'}
]
}
},
methods:{
getData(data){
console.log(data); //123
}
}
}
</script>
子组件部分:Child.vue
<template>
<div>
<ul>
<li v-for='(item,index) in nameList' :key='index'>{{item.name}}</li>
</ul>
<Button @click='toParent'>点击我</Button>
</div>
</template>
<script>
export default {
props:['nameList'],
methods:{
toParent(){
this.$emit('emitData',123)
}
}
}
</script>
3. 非相关组件之间传值
非相关组件之间传值,使用事件总线
(Bus)
如何实现非父子组件间的通信,可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,之后通过分别调用Bus事件触发和监听来实现组件之间的通信和参数传递。
首先需要在任意地方添加一个bus.js
import Vue from 'vue'
export default new Vue;
在需要通信的组件都引入Bus.js
如果你的bus.js是自定义一个bus的文件那from后面就改成你的所放的位置
import Bus from './bus.js'
接下来就是要组件通信了
添加一个 触发 #emit的事件按钮
<template>
<div id="emit">
<button @click="bus">按钮</button>
</div>
</template>
import Bus from './bus.js'
export default {
data() {
return {
message: ''"
}
},
methods: {
bus () {
Bus.$emit('msg', '我要传给兄弟们组件,你收到没有')
}
}
}
打开要和$emit
通信的另外一个组件 添加
import Bus from './bus.js'
在钩子函数中监听msg
事件
<template>
<div id="on">
<p>{{message}}</p>
</div>
</template>
import Bus from './bus.js'
export default {
data() {
return {
message: ''
}
},
mounted() {
let self = this
Bus.$on('msg', (e) => {
self.message = e
console.log(`传来的数据是:${e}`)
})
}
}
最后p
会显示来自$emit
传来的信息