定义组件的两种方式
- 全局定义组件
- 局部定义组件
<div id="demo">
<!--使用组件-->
<my-component></my-component>
</div>
Vue.component("my-component",{ // 全局定义组件
template:`<div>my-component是组件名;第二个参数是对象,描述了组件的内容</div>`
});
new Vue({
el:"#demo"
components:{ //局部定义组件
"my-component2":{
template:`<div>my-component2是组件名,局部组件</div>`
}
}
})
此处定义组件使用了HTML模板,需要遵循html的规则。
例如table标签内不能有div标签,如果写了vue引擎就会把div标签放在table标签上面!
但如果我就想让div放在table标签里面呢?不遵循HTML的既有规则呢
使用is
关键字,等于组件名,如下:
<div id="demo">
<table>
<tr is="my-component"></tr>
</table>
</div>
则vue引擎生成的html如下:
<div id="demo">
<table>
<tbody>
<div>my-component是组件名;第二个参数是对象,描述了组件的内容</div>
</tbody>
</table>
</div>
而当直接使用字符串模板时,不会遵循HTML的规则。如下:
<div id="demo">
</div>
new Vue({
el:"#demo",
template:`<table>
<div>my-component是组件名;第二个参数是对象,描述了组件的内容</div>
</table>`,
})
则vue引擎生成的html如下:
<table>
<div>my-component是组件名;第二个参数是对象,描述了组件的内容</div>
</table>
因此,再不同的模板下组件有不同的行为
在Vue实例中(new Vue({})
),会有一个data用来绑定数据,而组件同样作为Vue的实例,也同样可以绑定数据。只不过data并不是一个直接的对象,而是以函数的方式,返回一个对象,如下:
<div id="demo">
<my-component></my-component>
</div>
Vue.component("my-component",{ // 全局定义组件
template:`<div>我是一个{{name}}</div>`,
data:function(){
return {name:"组件"}
}
});
new Vue({
el: "#demo"
})
这是因为如果直接把data写成一个对象,就会是全局的,组件间会相互改变data值,而函数的形式,使其不会是全局的变量,组件间不会相互影响data值。
组件的自定义
组件是为了满足可复用的需求,如上面所写的组件demo,就太过单一,无法满足多样化的需求。
在使用组件的时候,是以标签的形式插入在HTML中,在标签中可以写一些自定义属性,然后在组件中使用props
接收该属性。
<div id="demo">
<my-component name="tanjw"></my-component>
</div>
Vue.component("my-component",{ // 全局定义组件
template:`<div>我叫{{name}}</div>`,
props:["name"]
});
new Vue({
el: "#demo"
})
props简单使用时,是一个数组,内只有变量名。
但需要对变量添加权限时,是一个对象的形式。如:
Vue.component("my-component",{ // 全局定义组件
template:`<div>我叫{{name}}</div>`,
props:{
name:{
type:String, //规定其类型
default:"tanjw", //默认值
required:true //是否必须传递name的值
}
}
});
new Vue({
el: "#demo"
})
注意与v-band的区别,<my-component :name="name" name="tanjw"></my-component>
。
在:name="name"
中,属性值name是data中的变量,而在name="tanjw"
中,属性值tanjw是字符串。
我们现在就可以使用组件的自定义特性来进行组件的父子通信。
要注意的是,我们要避免直接改变props的值,通过组件的data:function(){},来间接改变,否则在发生某些重新渲染的情况下,会取到原来的值,而不是直接改变后的值。
组件的自定义事件
上面说了,我们不能直接改变父组件传递过来的属性值即props,那么就想直接使用传递得属性值呢?
利用组件的自定义事件。
上面说了,可以利用props从父组件向子组件传值,
而子组件向父组件传递可以利用自定义事件。
下例演示了点击子组件的按钮,父组件改变显示的总值。
<div id="demo">
{{total}}
<component1 v-on:addtotal="addTotal"></component1>
<component1 v-on:addtotal="addTotal"></component1>
</div>
Vue.component("component1", {
template: `
<div>
<button @click="addCount">{{count}}</button>
</div>
`,
data: function(){
return {count:0};
},
methods:{
addCount:function(){
this.count++;
this.$emit("addtotal"); //count每改变一次,就触发一次自定义事件
}
}
});
new Vue({
el: "#demo",
data: {
total: 0
},
methods:{
addTotal:function(){
this.total++;
}
}
})
内容分发(插槽)
作用:改变组件内的内容节点
<div id="demo">
<component1>
<div>我是被插进来的div</div>
</component1>
</div>
Vue.component("component1", {
template: `
<div>
<slot>
<p>我是组件内的p标签</p>
</slot>
</div>`
});
new Vue({
el: "#demo"
})
如上,在组件内使用slot
标签作为内容分发的入口,当调用组件时,如果在组件标签内写了元素标签,则组件内slot
的内容不会被渲染出来,只有在调用组件时没有写元素标签,solt
的内容才会被渲染出来。其中,slot
不能作为根标签。
// 而写作下面这样的形式时,甚至根据组件内`slot`的顺序,对调用组件的内容标签进行排序。
<div id="demo">
<component1>
<div slot="one">我是被插进来的div1</div>
<div slot="two">我是被插进来的div2</div>
</component1>
</div>
Vue.component("component1", {
template: `
<div>
<slot name="one">
<p>我是组件内的p1标签</p>
</slot>
<slot name="two">
<p>我是组件内的p2标签</p>
</slot>
</div>`
});
new Vue({
el: "#demo"
})