组件间的数据传递:props、$emit $on、eventBus、Vuex


数据传递的方式

  1. 父传子props;
  2. 基于发布订阅实现 $emit $on;
  3. eventBus;

父传子props

如何让子组件获取到父组件中的数据?
步骤:

  1. 把父组件的数据以动态属性的方式当在子组件的行间属性上;
  2. 在子组件中用props这个属性接收,(对象、数组)
  3. 在子组件中使用动态的属性名保持一致;
    props可以是数组,也可以是对象;
<body>
    <div id="app">
        <!--普通的行间属性的属性值就是一个字符串-->
        <!--动态属性取父组件中的数据-->
        <child v-bind:m="msg" :t="hh"></child>
    </div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let child = {
    data(){
        return{num:100}
    },
    props:["m","t"], //props中放的是动态属性的属性名
    template:'<div>{{m}}{{t}}</div>' //和props对应;
}
let vm = new Vue({
    el:'#app',
    data:{
        msg:'today',
        hh:0902
    },
    components:{ 
        child
    }
})
</script>   
</body>

child是vm的一个子组件;

props验证
可以为组件的 prop 指定验证要求;
为了定制 prop 的验证方式,可以为 props 中的值提供一个带有验证需求的对象;

<div id="app">
    <child :m="msg"></child>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let child = {
	data(){
		return {num:100,}
    },
    props:{
        m:{ //对象
	        //1.type:对传递过来的数据进行验证
            type:[Number,String],
            //2.required:必须传递的属性
            required:true,
            //3.default:默认值
            default:200,
            //4.validator:自定义验证函数
            validator(val){
                // 如果这个函数返回一个布尔值,如果是true,没有问题,如果是false,那么会抛出异常
                return [1,2,3].indexOf(val)!==-1;
            }
        }
    },
    template:"<div>{{m}}</div>"
}
let vm = new Vue({
    el:"#app",
    data:{
        msg:99,
        hh:"lalal"
    },
    components:{
        child
    }
});
</script>

注意:那些 prop 会在一个组件实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的。

vue的单向数据流
当父组件中数据发生改变,子组件数据会变吗?

如果子组件使用了父组件中的数据,当父组件通过某些方法发生更改时,更改了自己的数据时,那么子组件也会随着发生改变,父组件中的数据又流向了子组件,子组件发生了更改;这就是组件之间数据传递的单向数据流

<div id="app">
    {{num}}
    <button @click="add">加一</button>
    <son v-bind:t="num"></son>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let son = {
    data(){
        return {val:100}
    },
    props:["t"],
    template:"<div @click='fn'>{{t}}:{{val}}</div>",
    methods:{
        fn(){
            //this.t++ 不能在子组件中修改父组件中的属性值
            this.val=200;
        }
    },
    beforeUpdate(){
        console.log("子组件更新前")
    },
    updated(){
        console.log("子组件更新后")
    }
}
let vm = new Vue({
    el:"#app",
    data:{num:20},
    methods:{
        add(){this.num++}
    },
    components:{
        son
    },
    beforeUpdate(){
        console.log("父组件更新前")
    },
    updated(){
        console.log("父组件更新后")
    }
});
</script>

  1. 当父组件数据更新时,beforeUpdate(父)–>beforeUpdate(子)–>updated(子)—>updated(父)
  2. 如果子组件只改变自己的数据,那么不会让父组件中的更新钩子函数执行;
  3. 父组件中不能使用子组件中的数据;

发布订阅 $emit $on

子传父:在父组件中定义一个修改自己属性的方法,把这个方法以自定事件的方式绑定给子组件,子组件触发动作,从而触发了自定义的事件($emit);

  • 在vue中,子组件中不能直接修改父组件中的数据;
  • 在子组件中不能直接修改prop接收到的父组件中的属性;
  • props接收的数据最终也会放到当前的组件实例上;
<div id="app">
    {{money}}
    <!--订阅自定义事件的方法-->
    <son v-bind:m="money" @changemoney="change"></son>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let son = {
    data(){
        return {}
    },
    methods:{
	    //不能直接修改prop接收到的父组件中的属性;
		//fn(){this.m=2000;}
        f(){ //$emit : 发布自定义事件
            this.$emit("changemoney",3000);
        }
    },
    props:["m"],//props接收的数据最终也会放到当前的组件实例上;
    template:"<div>{{m}}<button @click='f'>多要点</button></div>"
}
let vm = new Vue({
    el:"#app",
    data:{
        money:200
    },
    methods:{
       change(val){// 可以接收参数,$emit的第二个参数会传给change的第一个参数;
           this.money=val;
       }
    },
    components:{
        son
    }
});
</script>

sync修饰符

<div id="app">
    {{money}}
    <!-- 第一种写法 -->
    <!-- <son v-bind:m="money" v-on:update:m="money=$event"></son> -->
    <!-- 第二种写法 -->
    <son v-bind:m.sync="money"></son>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let son = {
    data(){
        return {}
    },
    methods:{
        f(){this.$emit("update:m",3000);}
    },
    props:["m"],
    template:"<div>{{m}}<button @click='f'>多要点</button></div>"
}
let vm = new Vue({
    el:"#app",
    data:{money:200},
    components:{
        son
    }
});
</script>

事件车 eventBus

eventBus:把组件上的方法都通过$on订阅到eventBus上,当执行时,通过$emit派发;

<body>
<div id="app">
    <bro1></bro1>
    <bro2></bro2>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
    let eventBus = new Vue; //相当于第三方;
    let bro1 = {
        data(){return{color:'红色'}},
        created () {
            //把自己实例上的方法订阅了eventBus这个实例的changeG这个自定义的事件上
            eventBus.$on("changeG",this.changeGreen)
        },
        methods:{
            changeGreen(){this.color="绿色"},
            fn2(){eventBus.$emit("changeR")}
        },
        template:"<div>{{color}}<button @click='fn2'>变红</button></div>"
    };
    let bro2 = {
        data(){return{color:'绿色'}},
        created() {
            eventBus.$on("changeR",this.changeRed)
        },
        methods:{
            changeRed(){this.color="红色"},
            fn1(){
                //点击button时,触发eventBus的changeG 这个订阅的事件;那么就会执行哥哥组件的changeGreen 方法;
                eventBus.$emit("changeG");
            }
        },
        template:"<div>{{color}}<button @click='fn1'>变绿</button></div>"
    };
    let vm = new Vue({
        el:'#app',
        data:{msg:'hello'},
        components:{
            bro1,
            bro2
        }
    });
</script>
</body>

关于Vuex,知识点很多,接下来的几天会另外更新一篇博客;?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值