在网页开发过程中,页面中有许多地方都是使用的同样的布局与样式,html文件中会有多段重复性的代码,而且不便于维护,改一处,其他地方都得改,十分麻烦,而Vue提供了组件这一概念,我们可以将相同的布局抽取出来当作为一个组件,这样后期维护也会十分方便
简单使用
我们定义一个组件之后,页面就可以使用组件名作为标签来使用组件
<div id="app">
<button-counter></button-counter>
</div>
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
//注意这里使用方法
data: function () {
return {
count: 0
}
},
//注意,这是js的模版语法,用的是 `(tab键上面那个键),而不是单引号
template: `<button v-on:click="count++">You clicked me {{ count }} times.</button>`
});
//创建Vue实例
var app = new Vue({
el: "#app",
data: {
},
});
下面对上面的代码进行解析
Vue.component()
是组件注册**(全局注册)**需要调用的方法,其接收两个参数,第一个参数为组件名,第二个参数为一个Json对象
组件名,官方推荐使用
-
或者首字母大写,在使用的时候只能使用-
,组件名大写,标签也得使用-
,如下
Vue.component('ButtonCounter', {
data: function () {
return {
count: 0
}
},
template: `<button v-on:click="count++">You clicked me {{ count }} times.</button>`
});
<!-- 会报错 -->
<ButtonCounter></ButtonCounter>
第二个参数与我们new一个Vue的实例传递的参数基本相同,不同的是,**组件注册传递的参数不包含el**
需要注意,第二个参数里的的data需要使用方法而不是使用对象,使用方法才能保证每个组件绑定的数据是相互独立,互不影响
传递数据
一般情形,我们使用组件肯定不止一个,可能是多个组件嵌套,这就涉及到了数据的传递
Vue中组件注册传递的json对象中,提供了prop参数(相当于给子控件的标签实现了自定义的属性),可以方便我们从父组件中传递数据到子组件中
<div id="app">
<!-- title属性是在组件注册时候定义的 -->
<nav-item title="导航1"></nav-item>
<nav-item title="导航2"></nav-item>
<nav-item title="导航3"></nav-item>
</div>
//定义组件
Vue.component('nav-item', {
//自定义属性title
props: ['title'],
template: `<p>{{title}}</p>`
});
//创建实例
var app = new Vue({
el: "#app",
});
可以注意到props传递的参数是一个数组,所以可以组件的自定义属性可以有任意多个
自定义属性也可以使用v-bind命令,当然,也可以使用v-for创建多个重复组件,这个就比较灵活,可以根据需求使用即可
<div id="app">
<nav-item v-for="item in navList" v-bind:title="item.title"></nav-item>
</div>
Vue.component('nav-item', {
props: ['title'],
template: '<p>{{title}}</p>'
});
var app = new Vue({
el: "#app",
data: {
navList: [
{
id: 1,
title: 'My journey with Vue'
},
{
id: 2,
title: 'Blogging with Vue'
},
{
id: 3,
title: 'Why Vue is so fun'
}
]
}
});
上面只是传递一个属性,如果有多个属性,就得声明多个属性,我们可以定义属性接收Object对象,之后取值也是比较方便
内容传递(插槽)
上面都是通过自定义属性来传递数据,但有时候,我们需要将标签内容传递给组件,可以使用组件提供的插槽<slot></slot>
进行传值
<alert-box>
Something bad happened.
</alert-box>
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<!--接收组件标签的内容 -->
<slot></slot>
</div>
`
})
事件传递
子组件回调父类事件
如果父类想要监听子组件的事件,可以让字组件事件中使用$emit
,进行回调父类事件,如下面有个简单的例子:
子组件是一个只有按钮的视图,点击按钮后,会回调父组件中的sayHi
方法,$emit
中传递父类组件定义的事件名即可
<div id="app">
<!-- 这里的btn-click是自定义的一个事件名 -->
<nav-item title="标题1" v-on:btn-click="sayHi"></nav-item>
</div>
Vue.component('nav-item', {
props: ['title'],
template: `<button v-on:click="$emit('btn-click')">{{title}}</button>`
});
var app = new Vue({
el: "#app",
data: {
},
methods:{
sayHi:function(){
console.log("hello");
}
}
});
事件传递数据
如果我们想要子组件传递在回调父类组件,并且需要传递数据,可以使用$emit
的第二个参数
<button v-on:click="$emit('btn-click', 0.1)">
Enlarge text
</button>
之后,在父类中,我们可以通过$event
来接收这个数值(父类是使用内联的方式),如官方的例子:
<blog-post
...
v-on:enlarge-text="postFontSize += $event"
></blog-post>
如果是像我们上面,是调用了方法的话,方法的第一个参数即为该数值
<div id="app"
<nav-item title="标题1" v-on:btn-click="sayHi"></nav-item>
</div>
sayHi:function(value){
...
}
组件使用v-model
如果组件中是包含相关的表单元素,需要稍微改造一下,我们可以看看官方给出的等价例子:
参考上图,我们可以得到以下在组件中使用v-model的规则:
- 将其 value attribute 绑定到一个名叫 value 的 prop 上
- 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
})
使用:
<div id="app">
<!-- 与下面的代码等价 -->
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
<!--使用v-model -->
<custom-input
v-model="searchText"
></custom-input>
</div>
var app = new Vue({
el: "#app",
data: {
searchText:""
},
});
动态组件
动态组件,一般是有多标签切换的情况下,如官方给的示例中:
下方显示的内容就是动态组件,每个标签都有其对应的一个组件,当点击上方不同的选项,其会发生改变
<div id="app">
<div>
<!-- 绑定点击事件 -->
<button v-on:click="showContent(1)">标签1</button>
<button v-on:click="showContent(2)">标签2</button>
<button v-on:click="showContent(3)">标签3</button>
</div>
<!-- 使用component标签和is属性 -->
<component v-bind:is="currentContentDiv"></component>
</div>
//定义三个组件,名字各不相同
Vue.component('content1', {
template: `
<div>标签1的内容</div>`
});
Vue.component('content2', {
template: `
<div>标签2的内容</div>`
});
Vue.component('content3', {
template: `
<div>标签3的内容</div>`
});
var app = new Vue({
el: "#app",
data: {
contentIndex : 1
},
computed:{
currentContentDiv:function(){
//当contentIndex数据发生变化(也就是点击按钮操作),返回不同的组件名
//从而让页面显示不同的组件
return 'content'+this.contentIndex;
}
},
methods:{
//点击按钮改变下标值,之后会自动计算,从而使currentContentDiv数据发生变化
showContent:function(num){
this.contentIndex =num;
}
}
});
currentContentDiv可接受已注册组件的名字或一个组件的选项对象
这个 attribute 可以用于常规 HTML 元素,但这些元素将被视为组件,这意味着所有的 attribute 都会作为 DOM attribute 被绑定。对于像
value
这样的 property,若想让其如预期般工作,你需要使用.prop
修饰器。
评论区