首先Vue我认为有几个最大的特点,
vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么就需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式,并且在模块化开发时,一定是需要拆分的,也就是我们常用的路由以及组件等方式,所以衍生出了这个问题,如何进行组件之间的传值问题,又为什么必须要这么去做呢?
父级向下传递数据
<body>
<div id="app">
<child :day='day'></child>
</div>
</body>
<script src="./js/vue.js"></script>
<script type="text/javascript">
var child = {
// props形式一:数组形式
props: ['day'],
// props形式二:对象形式
props: {
day: {
default: '日',
type: String
}
},
template: '星期{{day}}
'
}
const vm = new Vue({
el: '#app',
data: {
day: '五'
},
components: {
child
}
})
</script>
const child = {
props: ["titleValue","propValue","x","y","z"],
template:`
{{title2}}
`,
data(){
return {
/* 个人理解: 简单来说 我们将父级传递来的数据本地化,初始化
那么第一次使用的时候就是父级传递来的值,下次再改变时,也不会修改
父级传递值的内容
类似于 重新赋值
*/
title: this.titleValue, // 只被渲染一次
}
},
mounted () {
// 单向数据流 如果在这里改变父组件传递过来的值 父级props的更新会流动到子组件中,
// 但是反过来不行,这样会防止从子组件以外变更父级组件的状态,从而导致你的应用数据流难以理解
// 如果想要修改父组件传递过来的值,那么我们可以将这个值
setTimeout(()=>{
this.title="world"
},2000)
console.log(typeof this.propValue);
},
// 方法二: 我们通过computed 来改变
computed: {
title2(){
return this.title+"!!!";
}
},
}
父级向下传递数据 二
// 父组件
provide(){
return {
user:this.user,
}
},
// 子组件
inject:{
user:{
default:()=>{}
},
const child3={
//如果写props验证 就可以使用传入数据在template中的标签内使用
//如果不写 会默认将传入数据 放在组件的"根"元素上 简单的理解 就是写在了标签上(一鱼两吃!) 做了一个活口
//inheritAttrs属性是 禁止Attribute的继承 也就是即便不写props也不会被继承
//但是有例外 只有stype和class仍然会被设置在标签上 其他即便是id也不会被设置
inheritAttrs: false,
template:`
`
}
子级向上传递数据
$emit()
定义自定义事件
,$emit()
方法至少有2个参数
父组件模板内容中的子组件占位标签上用v-on(或@)绑定子组件定义的自定义事件名,监听子组件的事件,实现通信
示例代码:每点击子组件按钮给父组件字体加9像素
<body>
<div id="app">
<child @anlarge-text='bigger'></child>
<p :style="{fontSize: fontSize + 'px'}">{{msg}}</p>
</div>
</body>
<script src="./js/vue.js"></script>
<script type="text/javascript">
// 子组件
var child = {
template: ``,
}
// 根组件(父)
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue',
fontSize: 12
},
components: {
child
},
methods: {
bigger: function (n){
this.fontSize += n
}
}
})
</script>
个人理解:在这个地方,并不是很难理解,拿案例来说,如果我想点击变大,那么父组件如何知道我进行了点击,那么就通过一个自定义事件,来将父子组件联系起来,当子组件进行点击事件触发了自定义事件并且传参,那么父组件同样可以接收到自定义事件的触发,从而触发他的事件处理函数,即子组件点击->自定义事件触发->父组件触发事件处理。 通过事件的方式将数据进行了传递。
子级向上传递数据 方法二
使用$parent.获取父组件对象,然后再获取数据对象
mounted() {
this.msg2=this.$children[0].msg
}
this.msg22 = this.$parent.msg2; 来获取
子级向上传递数据 方法三
父去取子的数据信息。
ref
属性被用来给元素或子组件注册引用信息,引用信息将会注册在父组件的 $refs
对象上。如果在普通的 DOM 元素上使用ref
属性,则引用指向的就是 DOM 元素;如果ref
属性用在子组件上,引用就指向子组件实例。
ref
放在标签上,拿到的是原生节点。ref
放在组件上 拿到的是组件实例ref
属性(会被注册到父组件的$refs
对象上)拿到组件/DOM对象,从而得到组件/DOM中的所有的信息,也包括值<!-- 普通DOM -->
<p ref="p">hello</p>
<!-- 子组件 -->
<child-comp ref="child"></child-comp>
<script>
new Vue({
el: '#app',
data: {
},
mounted: function(){
console.log(this.$refs.p);
console.log(this.$refs.child);
this.$refs.comp.msg = '123' // 修改值
}
})
</script>
**非父子传递数据 **
const eventBus = new Vue()
eventBus.$emit('自定义事件名',传递的数据)
eventBus.$on('自定义事件名'[,callback])
eventBus.$off('自定义事件名')
示例代码:实现回合制互相伤害
<body>
<div id="app">
<zj_one></zj_one>
<hr/>
<zj_two></zj_two>
<hr/>
<button @click='destoryBus'>炸掉事件中心</button>
</div>
</body>
<script src="./js/vue.js"></script>
<script type="text/javascript">
// 定义事件中心
const eventBus = new Vue()
Vue.component('zj_one',{
data: function(){
return {
data: 100
}
},
template: `
{{data}}
`,
methods:{
fn1: function(){
eventBus.$emit('zj2_event',1)
}
},
mounted:function(){
eventBus.$on('zj1_event',val => this.data -= val)
}
})
Vue.component('zj_two',{
data: function(){
return {
data: 100
}
},
template: `
{{data}}
`,
methods:{
fn2: function(){
eventBus.$emit('zj1_event',2)
}
},
mounted:function(){
eventBus.$on('zj2_event',val => this.data -= val)
}
})
new Vue({
el: '#app',
methods: {
destoryBus: function(){
// 销毁双方监听的事件
eventBus.$off('zj1_event')
eventBus.$off('zj2_event')
}
}
})
</script>
Vue 推出了一个状态管理工具 Vuex,可以很方便实现组件之间的参数传递。