为什么组件化
组件注册
1.全局组件
通用过 Vue.component 来创建全局组件,在注册之后可以用在任何新创建的 Vue 根实例 (new Vue ) 的模板中,也可以用在任意子组件中,相互之间也可以使用。记住全局注册的行为必须在根 Vue 实例 (通过 new Vue) 创建之前发生。
<script>
Vue.component('componentName(组件名,可随意)', {
template:`<section style="background:red;">
<button @click="handleLeft">left</button>
猫眼电影-{{myname}}
<child></child>
<child></child>
</section>`
methods:{
handleLeft(){
console.log("left")
},
},
computed:{},
watch:{},
data(){
return {
myname:"11111111"
}
},
components:{
"child":{
template:`
<div>child-{{myname}}</div>
`,
data(){
return {
myname:"child-11111"
}
}
}
}
})
</script>
2.局部组件
可以通过一个普通的 JavaScript 对象来定义组件,然后在 components (Vue中的一个属性)选项中定义你想要使用的组件,也可直接在 components 中定义并使用。对于 components 对象中的每个 property 来说,其 property 名就是自定义元素的名字,其 property 值就是这个组件的选项对象。
<script>
var ComponentA = { }
var ComponentB = { }
var ComponentC = { }
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
new Vue({
el: '#app',
components: {
"component-a":{ },
"component-b":{ }
}
})
</script>
局部注册的组件在其子组件中不可用,若要在子组件A中使用子组件B,则要在A的components 中添加子组件B。
编写组件时要注意:
- 起名字 :js驼峰命名法, 还可使用html 链接符-
template 选项中的dom 片段 没有代码提示,没有高亮显示,书写时注意漏写错写。css 样式只能写成行内。template 包含一个根节点(root element ),该节点不能有兄弟节点。- 组件是孤岛,无法直接访问外面的组件的状态或者方法。间接的组件通信来交流。
- 组件可以有
data,methods,computed 等Vue有的属性,但自定义的组件 data 必须是一个函数。
组件间的通信
1.父传子(props down)
- 第一步:父组件 在引用子组件时,通过属性绑定(
v-bind: )的形式,把需要传递给子组件的数据,传递到子组件内部,供子组件使用 。 - 第二步:把父组件传递过来的数据, 在子组件的
props 数组中定义一下。组件中的所有props 中的数据,都是通过父组件传递给子组件,props 中的数据都是只读的,无法重新赋值。可使用属性验证来接收数据,Number,String,Boolean,Array,Object,Function,null (不限制类型):
<div id="box">
<navbar myname="电影" :myright="false" :myparent="parent">
</div>
<script>
Vue.component("navbar",{
props:{
myname:String,
myright:Boolean
},
template:`<div>
<button>left</button>
<span>{{myname}}--{{myparent}}</span>
<button v-show="myright">right</button>
</div>`
})
new Vue({
el:"#box",
data:{
parent:"1111111"
}
})
</script>
2.子传父(events up)
- 在父组件中引入子组件,使用
$on(eventName) 监听事件 ,在子组件中使用 $emit(eventName) 触发事件,可以将子组件的数据当做参数传递给父组件。 - 具体参考以下代码:
<div id="box">
<navbar @myevent="handleEvent"></navbar>
<sidebar v-show="isShow" ></sidebar>
</div>
<script>
Vue.component("navbar", {
template: `
<div style="background-color: red;">
<button @click="handleClick()">点击</button>-导航栏
</div>
`,
methods:{
handleClick(){
this.$emit("myevent",1000000000)
}
}
})
Vue.component("sidebar", {
template: `
<div style="background-color: yellow">
<li>11111</li>
<li>11111</li>
<li>11111</li>
<li>11111</li>
</ul>
</div> `
})
new Vue({
el: "#box",
data: {
isShow: true
},
methods:{
handleEvent(data){
console.log("父组件的定义的事件",data)
this.isShow = !this.isShow
}
}
})
</script>
3.组件refs
在JavaScript 中需要通过document.querySelector("#demo") 来获取dom节点,然后再获取这个节点的值。在Vue中,我们不用获取dom节点,元素绑定ref之后,直接通过this.$refs 即可调用,这样可以减少获取dom节点的消耗。
ref 介绍
ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向该子组件实例。
通俗的讲,ref 特性就是为元素或子组件赋予一个ID引用,通过this.$refs.refName 来访问元素或子组件的实例,相当于父子组件卖你对面通信。
this.$refs介绍
this.$refs是一个对象,持有当前组件中注册过 ref特性的所有 DOM 元素和子组件实例
注意: $refs 只有在组件渲染完成后才填充,在初始渲染的时候不能访问它们,并且它是非响应式 的,因此不能用它在模板中做数据绑定。
接下来看一个实例:
<div id="box>
<button @click=""handelAdd>add</button>
<child ref="myChild"></child>
</div>
<script>
Vue.component("child",{
data(){
return{
myName:"child--111"
}
},
template:`<div>
child---{{myName}}
</div>`
})
new Vue({
el: "box",
methods:{
handelAdd(){
this.refs.myChild.myName = "child--222"
}
}
})
</script>
4.中央事件总线(bus,兄弟间通信)
利用一个空的vue实例作为中央事件总线(bus),这样无论是组件树的哪一层都能通信到,使用$emit, $on, $off 分别来触发、监听、取消监听事件, 在mounted 生命周期中进行监听。
案例:
<div id="box">
<child1></child1>
<child2></child2>
</div>
<script>
var bus = new Vue()
Vue.component("child1",{
template:`
<div>child1</div>
`,
mounted(){
bus.$on("kerwin",(data)=>{
console.log("child1监听的函数",data)
})
}
})
Vue.component("child2",{
template:`
<div>child2
<button @click="handleClick">click</button>
</div>
`,
methods:{
handleClick(){
bus.$emit("kerwin","111111111")
}
}
})
var vm = new Vue({
el:"#box",
methods: {
}
})
</script>
5.补充 动态组件
component 元素(标签),动态地绑定多个组件到它的 is 属性keep-alive 保留状态,避免重新渲染
slot 插槽(内容分发)
- 混合父组件的内容与子组件自己的模板,进行内容分发 。
- 父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
slot 元素作为组件模板之中的内容分发插槽。在调用该组件时slot 元素自身将被替换。- 插槽的意义 : 扩展组件能力, 提高组件的复用性
插槽使用情况:
- 子组件访问不到父作用域的时候,可以先把该内容拿出来,在子组件中留好插槽就行。
- 要做一些可复用的组件,但不知道使用者要轮播什么或者做什么列表的时候,也留好插槽就行。
单个插槽
<slot></slot>
-
假如子组件没有slot插槽,父组件的内容将被会丢弃 -
假如子组件只有一个插槽,并且这个slot没有属性,那么父组件的所有包含在自定义组件标签里面的内容将插入到slot所在的位置,slot标签消失 -
假如自定义组件标签里面没有内容,就会显示slot里面的备用内容
<div>
<navbar>
<button @click="isShow = !isShow">show/hide<button>
</navbar>
<sidebar v-show="isShow"> </sidebar>
</div>
<script>
Vue.component("navbar",{
template:`<div>
navbar
<slot></slot>
</div>`
}
</script>
具名slot插槽
有时我们需要多个插槽,slot 元素有一个特殊的 属性:name 。这个 属性可以用来定义额外的插槽,不带 name 的 <slot > 出口会带有隐含的名字“default ”。
<hello>
<div slot="a">aaa</div>
<div slot="b">bbb</div>
</hello>
<script>
Vue.component("hello",{
template:`<div>
<div style="background:yellow"> 第一部分
<slot name="a"></slot>
</div>
<div style="background:red"> 第二部分
<slot name="b"></slot>
</div>
</div>`
}
</script>
|