Vue组件二——data选项、局部组件、组件通信
data选项
- data选项用于储存组件数据
与实例data差别
- 必须存储在有返回值的函数当中
- 数据设置在返回值对象里
1、方式一
data:function(){
return{
title:"组件标题",
content:"组件内容"
}
}
2、ES6的简写方式
data(){
return{
title:"组件标题",
content:"组件内容"
}
}
作用:确保每个组件实例单独维护一份返回对象的独立拷贝,相互之间不受影响(因为函数内部是单独的作用域)
Props选项
props命名规则
示例:我想跳转
建议prop定义时命名采用camelCase(驼峰命名),父组件绑定时使用kebab—case(因为html的属性不区分大小写)
局部注册
- 局部注册组件只能作用在当前实例或组件中
挂载在id为app的实例中的组件ComA,ComB只能在app实例内使用
<div id="app">
<com-a></com-a>
<com-b></com-b>
</div>
方式一:在实例内部定义
<script type="text/javascript">
new Vue({
el:"#app",
components:{
'ComA':{
template:"<div>{{word}}</div>",
data:function(){
return{
word:"this is A Compotent"
}
}
},
'ComB':{
template:"<div>{{word}}</div>",
data:function(){
return{
word:"this is B Compotent"
}
}
},
}
})
</script>
方式二:在实例外单独定义,实例内调用
<script type="text/javascript">
var ComA ={
template:"<div>{{word}}</div>",
data:function(){
return{
word:"this is A Compotent"
}
}
};
var ComB = {
template:"<div>{{word}}</div>",
data:function(){
return{
word:"this is B Compotent"
}
}
};
new Vue({
el:"#app",
components:{
//—kabak命名必须带'',pascal命名法可不带引号
'com—a':ComA,
ComB:ComB
}
})
</script>
ES6简写:
要求:组件定义的名称必须符合pascal命名规则
new Vue({
el:"#app",
components:{
ComA,
ComB
}
})
效果:
this is A Compotent
this is B Compotent
组件通信
组件通信——组件间传递数据的操作
常见类型:
- 父组件向子组件传值
- 子组件向父组件传值
- 非父子组件传值
- 其他通信方式
父组件向子组件传值
- 通过子组件的props选项参数接收父组件的传值
- 传值的类型可以是是值类型,也可以是数组及对象
三种传值方式:
- 直接赋值
- 传匿名值变量
- 传父实例变量,随父组件数据值的变化而改变
<div id="app">
<!--直接赋值—— props里的title直接赋值-->
<com-a my-title = "直接赋值的标题"></com-a>
<!--匿名值变量—— 相当于将值为'这是静态标题'的匿名变量赋值给props里的title -->
<com-a v-bind:my-title="'这是静态标题'"></com-a>
<!-- 将父实例数据title、content这两个变量赋值给props里的title、words -->
<com-a :my-title="title" :words="content"></com-a>
</div>
<script type="text/javascript">
Vue.component('ComA',{
props:['myTitle','words'],
template:`<div>
<h3>{{title}}</h3>
<p>{{words}}</p>
</div>`
});
new Vue({
el:"#app",
data:{
title:"全局标题",
content:"全局内容"
}
})
</script>
v-for在传值中的应用
<div id="app">
<com-a v-for="item in items" :key="item.title"
:item-title="item.title"
:item-words="item.content"
:item="item"
></com-a>
</div>
<script type="text/javascript">
Vue.component('ComA',{
props:['itemTitle','itemWords','item'],
template:`<div>
<h3>{{itemTitle}}</h3>
<p>{{item.content}}</p>
</div>`
});
new Vue({
el:"#app",
data:{
items:[
{
title:"全局标题1",
content:"全局内容1"
},
{
title:"全局标题2",
content:"全局内容2"
},
{
title:"全局标题3",
content:"全局内容3"
}
]
}
})
</script>
子组件向父组件传值
自定义触发事件
子组件向父组件传值需要自定义事件
- 子组件数据变化时,通过$emit() 触发自定义事件
- 自定义事件名称建议使用kebab-case
具体步骤:
- 在子组件的方法里通过$emit() 自定义触发事件名称
- 在子组件实例html上指定自定义触发事件名称对应的响应函数或表达式
- 在父组件定义函数的具体内容(如果响应是表达式此步骤省略)
<div id="app">
<!-- 2、在自定义组件里声明这个事件对应的函数或者表达式 -->
<com-a v-for="item in items" :key="item.id"
:item-title="item.title"
@count-change="TotalCount++"
></com-a>
<span>TotalCount:{{TotalCount}}</span>
</div>
<script type="text/javascript">
Vue.component('ComA',{
props:['itemTitle','itemWords','item'],
template:`<div>
<div >
<span>{{itemTitle}}</span>
<span>{{count}}</span>
<button type="button" @click="countIns">+1</button>
</div>
</div>`,
data(){
return {
count:0
}
},
methods:{
'countIns':function(){
//1、通过emit自定义一个事件count-change
this.$emit('count-change');
this.count++;
}
}
});
new Vue({
el:"#app",
data:{
items:[
{
title:"苹果",
id:"1"
},
{
title:"香蕉",
id:"2"
},
{
title:"芒果",
id:"3"
}
],
TotalCount:0
},
methods:{
totalchange:function(){
this.TotalCount++;
}
}
})
</script>
效果:
$emit详解
1、无参数(参考上述例子)
-
定义:
this.$emit('count-change');
指定(此处指定的是表达式):
<com-a v-for="item in items" :key="item.id" :item-title="item.title" @count-change="TotalCount++" ></com-a>
2、带参数,通过$event去接收参数
-
定义:
this.$emit('count-change',5);
-
指定(此处指定的是函数):
<com-a v-for="item in items" :key="item.id" :item-title="item.title" @count-change="totalchange($event)" ></com-a>
-
在父组件定义对应的响应函数totalchange
methods:{ // 3、在父组件定义触发事件对应的函数 totalchange:function(num){ this.TotalCount+= num; } }
效果:
非父子组件传值
分类
-
兄弟组件
-
完全无关的组件
兄弟组件传值
思路1:通过父组件进行数据中转
思路n....
如下图思路:
- 首先通过com-a传值给父组件data里的value接收
- 将父组件的value传给com-b组件里props里的val接收
<div id="app">
<com-a @count-change="value=$event"></com-a>
<com-b :val="value"></com-b>
</div>
new Vue({
el:"#app",
data:{
items:[
value:""
]
}
})
完整代码:
<div id="app">
<com-a @title-change="value=$event"></com-a>
<com-b :val="value"></com-b>
</div>
<script type="text/javascript">
Vue.component('ComA',{
template:`<div>
<h3>这是组件A的标题:{{title}}</h3>
<button type="button" @click="countIns">传值</button>
</div>`,
data(){
return {
title:"生日快乐"
}
},
methods:{
countIns(){
this.$emit('title-change',this.title);
}
}
});
Vue.component('ComB',{
props:['val'],
template:`<div>
<h3>这是组件B的标题:{{val}}</h3>
</div>`
});
new Vue({
el:"#app",
data:{
value:""
}
})
</script>
效果:
完全无关组件传值(EventBus)
定义
EventBus(事件总线),类似数据搬运工、邮递员的角色
- 一个独立的事件中心
- 用于管理不同组件间的传值操作。
形式
- 通过Vue实例来管理传值操作
- 通过注册事件、调用事件来实现数据传递
- 发送组件——触发bus事件,通过$emit去触发
接收组件——给bus注册对应事件,通过$on去注册接收函数
步骤
-
新建一个Eventbus.js,定义一个bus的实例
// 定义eventBus实例 var bus = new Vue();
-
在html里引入EventBus.js
<head> <meta charset="utf-8"> <title></title> <script src="vue.js" type="text/javascript" charset="utf-8"></script> <!-- 1、引入定义的eventbus --> <script src="EventBus.js" type="text/javascript" charset="utf-8"></script> </head>
-
组件里触发和注册
<div id="app"> <com-a :my-title="title"></com-a> <com-b></com-b> </div>
<script type="text/javascript"> // 传递组件A Vue.component('com-a',{ props:['myTitle'], template:`<div> <span>{{myTitle}}</span> <span>{{count}}</span> <button type="button" @click="countIns">+1</button> </div>`, data(){ return{ count:0 } }, methods:{ countIns(){ //2、传递者——定义触发事件 bus.$emit('count-change',1); this.count++; } } }); //接收组件B Vue.component('com-b',{ template:`<div> <span>totalCount:{{totalCount}}</span> </div>`, data(){ return { totalCount:0 } }, created() { //ES6的写法 // bus.$on('count-change',num=>{ // console.log(this.totalCount); // this.totalCount += num; // }); // 注意和上面ES6写法的区别,此处方法内的this是指的函数,不能通过this.totalCount取到值 var t =this; //3、接收者——通过$on获取值 bus.$on('count-change',function(num){ console.log(this); t.totalCount += num; }); } }); new Vue({ el:"#app", data:{ title:"苹果", id:1, totalCount:0 } }); </script>
效果: