父组件向子组件传值
- 通过子组件的 props 选项承受父组件的传值
- props 内的数据能够在模板内间接应用
- 留神:props 不要与 data 存在同名属性,会产生笼罩问题
子组件设置形式
Vue.component('my-com',{props:['title'], // 父类中要绑定的属性
template:'<h>{{title}}</h>'
})
父组件设置形式
-
给自定义组件设置属性
<div id="app"> <my-com title="实例内容 1" ></my-com> // 动态属性设置, 无奈操作批改 <my-com :title="'实力内容 2'"></my-com> // 动静属性设置:表达式(个别不通过动静属性绑定动态值,无奈操作批改)<my-com :title="item.title"></my-com> // 动静属性设置:数据(父组件数据更新会使子组件同步更新)</div>
new Vue({ ... data:{item:{title:"实力内容 3"} }, components:{ "my-com":{props:["title"], template:` <div> <h3>{{title}}</h3> </div> ` } } })
Props 命名规定
- 倡议 prop 命名应用 camelCase,父组件绑定时应用 kebab-case。
为什么? - 子组件中,props 内如果用 kebab-case,如果 prop 作为属性应用不能加 ”-“, 如果 prop 为 ”my-title” 这种状况,应用时在插值内须要改成 ”{{myTitle}}” 解决
- 父组件中,属性是在 html 中书写的,html 的属性是不辨别大小写,因而 camelCase 会被辨认成 camelcase,可能并不是咱们想要的 camel-case 后果
子组件
Vue.component("my-com",{props:["myTitle"], // {myTitle:String} 写法也可
template:`
<div>
<h3>{{myTitle}}</h3>
<a :href="myTitle"></a> // 除了应用在插槽中, 在绑定动静属性中也能够
</div>
`
})
父组件
<div id="app">
<my-com my-title="实例内容 1" ></my-com>
<my-com :my-title="'实力内容 2'"></my-com>
<my-com :my-title="item.title"></my-com>
</div>
父传子的单向数据流
父子组件间的所有 prop 都是单向上行绑定的。意味着只能父向子传,不能反向影响(子影响父)
解释:
- 父组件的数据批改会主动绑定到子组件中,并更新子组件, 子组件的操作无奈反向影响父组件
-
如果子组件要解决 prop 数据,该当存储在 data 或 computed 中后操作
Vue.component("my-com",{props:['initialTitle'], template:'<h3> {{myTitle}} </h3>', data(){ return {myTitle:this.initialTitle // 把属性存下来,解决后放入插值中} } })
<div id="app"> <my-com :initial-title= "value"></my-com> </div> var vm = new Vue({ data:{value:'北京欢送你',}, }).$mount("#app")
- 组件也是 vue 实例,无论实例内的 属性怎么批改,myTitle 数据怎么变,都不会对父的数据产生影响
- 解决 props 数据形式,
this.myTitle = "其余内容"
- 间接批改 props 数据会产生正告
this.initialTitle = "其余内容"
,倡议用 data 或者 computed 代替间接批改(我没呈现)
- 留神,如果 prop 为数组或对象时,子组件操作将会影响到父组件的状态。(援用)
-
解决办法
-
存起来,拷贝到一个对象操作,
obj_:Object.assign({},this.obj)
-
对象不整体传入
<div id="app"> <p>{{obj.name}}</p> // 会受到影响 <my-com :initial-obj= "obj"></my-com> </div> var vm = new Vue({ data:{ obj:{ name:'mcgee', // 会受到影响 1 age:18 } }, }).$mount("#app")
Vue.component("my-com",{props:['initialObj'], template:` <div> <h3> {{myObj.name}}:{{myObj.age}}岁 </h3> <button @click="fn"> 按钮 </button> </div> `, data(){ return {myObj:this.initialObj} }, methods:{fn(){this.initialObj.name = "Jack" // 对象批改会影响父类 1 处的值} } })
-
子组件向父组件传值
- 子向父传值须要通过自定义事件实现
- 无奈通过 props 解决,通过自定义事件
- 父传子,子操作后想要传回父会有个问题。子组件什么时候处理完毕,什么时候批改了数据,什么时候将数据传给父组件无奈确定,因而通过事件触发
案例
商品为子组件,购物车为父组件,父组件须要统计商品个数,就须要在子组件个数变动时传值给父组件。
var vm = new Vue({
data:{
products:[{id:1,title:"茄子"},
{id:2,title:"辣椒"},
{id:3,title:"西红柿"}
],
totalCount:0
},
}).$mount("#app")
<div id="app">
<h3> 购物车 </h3>
<product-item
v-for='item in products'
:key="item.id"
:title='item.title'
></product-item>
<p> 总数为{{totalCount}}</p>
</div>
Vue.component('product-item',{props:['title'],
template:`
<div>
<span> 名称{{title}}, 数量{{count}}</span>
<button @click="addCount">+1</button>
</div>
`,
data(){return { count:0}
},
methods:{countIns(){this.count++;}
}
})
- 子组件数据变动时, 通过
$emit()
触发自定义事件。(实例的办法) -
自定义事件名称倡议应用 kebab-case, 在父组件中用
@
绑定驼峰
或者帕斯卡
,无奈辨认Vue.component('product-item',{ ... methods:{countIns(){this.$emit('count-change') // 触发,在父组件中监听 this.count++; } } })
父组件
<div id="app"> <product-item ... @count-change="totalCount++" // 事件监听,操作的时父的数据 ></product-item> <p> 总数为{{totalCount}}</p> </div>
自定义事件传值
Vue.component('product-item',{ ... methods:{countIns(){this.$emit('count-change',1) // 传参 this.count++; }, countIns5(){this.$emit('count-change',5) this.count+=5; } } })
-
父组件在监听事件时须要接管子组件传递的数据。
<div id="app"> <product-item ... @count-change="totalCount += $event" // 在标签中接管参数 ></product-item> <p> 总数为{{totalCount}}</p> </div>
或者
@count-change="onCountChange" new Vue({ ... methods:{onCountChange(productCount){ // 在办法中接管参数 this.totalCount += productCount } } })
非父子组件传值
- 非父子组件指的是兄弟组件或齐全无关的两个组件
内容概述
- 兄弟组件传值
- EventBus
- 其余传值形式
兄弟组件传值
- 兄弟组件能够通过父组件进行数据直达
-
例如 a,b 子组件传值,能够通过 a 子组件传给父组件,再由父组件传给 b 子组件
new Vue({ data:{value:"" // 用来数据直达的根实例数据} })
<div id="app"> <com-a @value-change="value = $event" ></com-a> // 子 a 向父传递数据 <com-b :value="value"></com-b> // 父向子 b 传数据 </div>
A 组件
Vue.components('ComA',{ template:` 组件 A 内容{{value}} <button @click="$emit('value-change',value)" > 发送 </button> `, data(){return { value: '实力内容'} } })
B 组件
Vue.components('ComB',{props:['value'] template:` 组件 B 内容{{value}} ` })
EventBus
问题
- 当组件嵌套关系简单时,依据组件关系传值会较为繁琐。
- 组件为了数据直达,data 中会存在许多与以后组件性能无关的数据。
解决
- EventBus(事件总线)是一个独立的事件核心,用于治理不同组件间的传值操作。(邮递员,直达解决)
-
EventBus 通过一个新的 Vue 实例来治理组件传值操作,组件通过给实例注册事件、调用事件来实现数据传递。
// EventBus.js var bus = new Vue() // 不须要配置,只做事件传值操作
-
发送数据的组件触发 bus 事件,接管的组件给 bus 注册对应事件。
<script src="EventBus.js"></script> // 引入 js Vue.component('product-item',{ ... methods:{countIns(){bus.$emit('count-change',1) // 用 bus 实例 代替 组件 product-item 实例 this.count++; } } })
-
给 bus 注册对应事件通过
$on()
操作。Vue.component('product-total',{ template:` <p>{{totalCount}}</p> `, data(){return { totalCount:0} }, created(){ // 实例创立实现后触发 countIns(){bus.$on('countChange',(productCount)=>{this.totalCount+=productCount // 留神下这里 this, 箭头函数}) } } })