组件
真实的业务场景中,我们的网页是被分成很多个模块的,比如导航栏,内容区,状态栏等等,同时我们开发的逻辑也是模块化组件化去耦合,因此我们需要以一种嵌套的组件树的形式来组织我们的视图和代码:
组件注册
我们可以先看一个例子,观察一下什么是组件注册。
const Foo = {
template:`
<div>this is component-Foo</div>
`
}
Vue.component("Bar",{
components:{
Foo,
},
data(){
return{
msg: "this is component-Bar"
}
},
template:`
<div>{{msg}}
<Foo></Foo>
</div>
`
});
const app = new Vue({
el:"#app",
data(){
return{
count : 100
}
},
template:`
<div>
{{count}}<br>
<Bar></Bar>
</div>
`,
})
通过上述例子,我们可以看到:
-
通过vue.component的方式注册的组件被称为全局组件,这一类之组件只要组成后,可以在任何位置使用。声明语法为:
vue.component('component-name',{ //options API })
-
通过创建函数对象,并在其他组件內通过
components:{component-a,component-b,component-c}
的方式注册的,被称为局部注册,仅在该声明的组件內生效。声明语法为:const Foo = { //options API... }; vue.component('Bar',{ components:{ Foo }, // other options API... })
通过props传参
如果我们想要在调用一个组件的时候,通过传入某些参数来控制组件內渲染的视图时,我们可以在注册声明组件的时候,声明一个props参数来实现这个需求:
Vue.component("Foo",{
props:['msg','count'],
template:`
<div>
{{msg}},{{count}}
</div>
`
})
然后在组件外部调用该组件的时候,可以通过上述制定一个attribute来传递进去:
<Foo msg="msg1" count="one"></Foo>
<Foo msg="msg2" count="two"></Foo>
<Foo msg="msg3" count="three"></Foo>
通过emit和v-on监听子组件事件
如果我们想要通过监听子组件的事件来更改父组件视图的话,比如:当点击子组件的button按钮的时候,父组件上显示的数字翻倍。这时就可以用到emit和v-on了。
其中emit是子组件用来向父组件传递事件的。
Vue.component('Foo',{
data(){
return{}
},
methods:{
handleClick(){
this.$emit('double',2);
this.$emit('treble',3);
}
}
template:`
<div><button v-on:click="handleClick">send msg to fatherComponent</button></div>
`
})
这样当点击子组件的按钮的时候,就会触发handleClicck的方法,然后在该方法內通过$emit发送了两个自定义事件和参数。父组件通过V-on监听对应事件,当该事件触发时执行对应的业务逻辑。
const app = new Vue({
methods: {
handleDouble(value) {
console.log("翻倍了:" , this.count * value);
},
handleTreble(value) {
console.log("三倍:", this.count * value);
},
},
template: `
<div>
<Foo @double="handleDouble" @treble="handleTreblee"></Foo>
</div>
`,
data() {
return { count:1 };
},
});
v-model语法糖实现自定义事件侦听
当我们在进行父级和子级通信的时候,是需要一方抛出一个自定义事件,然后另一方需要先接受到对应的事件,然后在进行处理逻辑,这样是比较麻烦的。因此v-model语法糖可以给我提供一种方式,不需要再抛出事件/监听事件。
首先,在需要发送消息的一方,需要定义model:
Vue.component('Sender',{
props:['visible'],
data(){return{}},
model:{
event:"close",
prop:"visible"
},
methods:{
handleClose(){
this.$emit("close", false)
}
},
template: `
<div v-if="visible">
this is sender, and its state is {{visible}}
<button @click="handleClose">close</button>
</div>
`,
})
当子组件点击close按钮的时候,回调用handleClose()方法,这时会向父组件发送一个("close", false),这两个值代表什么东西,等我们看完父组件的代码之后再说:
const app = new Vue({
template:`
<div>
this is receiver,this button can show Sender-component:
<button @click="handleShowSender">show</button>
<Sender v-model="showSender" ></Sender>
</div>
`,
data(){
return{
showSender:false
}
},
methods:{
handleShowSender(){
this.showSender = true
}
}
})
上述代码v-model="controlSenderr"
中的controlSender
对应的值对应着子组件定义的model.prop:"visible"
参数,当触发handleShowSender
函数时,会将showSender
的值修改为true
,对应的会传递给子组件的visible
使之变成true
。
刚才留着没有解释的子组件发来的("close", false)
这个close
其实就是model.event
定义的这个事件,与之对应的就是父组件的v-modle:"showSender"
这个事件,false
就是传过来的value
值,赋值给showSender
。
这样就实现了不用抛出事件,监听事件,再处理逻辑这样一套繁琐的操作。
sync实现自定义事件侦听
Vue还给我们提供了一种类似v-model的方法,也就是.sync修饰符,用法类似,但是我个人更倾向于使用这种方式,因为起名字这个问题永远困扰着程序员,而.sync这种方式个人认为表意更加清晰明确。
以下是.sync修饰符的使用方式,我们还是先看子组件:
Vue.component("Sender", {
components: {},
props: ["visible"],
data() {
return {};
},
methods: {
handleClose() {
this.$emit("update:visible", false);
},
},
template: `
<div v-if="visible">
state of Sender is {{visible}}
<button @click="handleClose">close</button>
</div>
`,
可以看到,我们同样是需要定义一个props:'visible'
这样才可以控制子组件模块的显示和隐藏;同样的,我们也是在组件内添加了一个close按钮,当点击按钮的时候会触发handleClose
的函数方法;不同的是,该方法$emit发送的却改变了,由之前的"close"改成了"update:visible",前面的update:
是这种方式的固定语法,后面跟着的就是需要修改的对应props,这样就表意十分明确,一眼可以认出来。
对应的,父组件需要进行如下操作:
const app = new Vue({
el: "#app",
template: `
<div>
<button @click="handleShowSender">showSender</button>
<Foo :visible.sync="isVisible" ></Foo>
</div>
`,
data() {
return {
isVisible: false,
};
},
methods: {
handleShowSender() {
this.isVisible = true;
},
},
});
父组件通过:visible:sync
监听来自自组件的自定义事件,当接收到自定义事件之后,会讲传过来的第二个参数赋值给后面的isVisible
响应式数据。
slot插槽实现组件自定义模版与替换
我们可以在子组件里面使用slot插槽,来预设一些模版内容;父组件可以按需加在,如果父组件想要更改模版内容,可以执行在template标签內加上加上自己需要的内容。否则就会渲染出来预设的内容。
Vue.component("Foo", {
components: {},
data() {
return {};
},
template: `
<div>
<slot name="header" test1="123" test2="234">header in slot</slot>
<slot name="main">main in slot</slot>
<slot name="footer">footer in slot</slot>
</div>
`,
在子组件预设slot插件的时候,可以通过name字段区分各个slot,并且也可以预设一些参数,父组件可以直接调用:
const app = new Vue({
el: "#app",
template: `
<div>
<Foo>
<template #header="{test1}">
{{test1}}
</template>
<template #main>
main in template
</template>
<template #footer>
</template>
</Foo>
</div>
`,
data() {
return {};
},
});
父组件通过#slotName="{propName}"的方式读取对应名称的slot插槽并使用预设的参数。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!