1.前言
组件传值 不管
vue
还是react
亦或某个框架都是重点记得有篇文章写了 ,其实有些情况 完全可以用
js
自带dataset
来传值哦
2. 引子
每个组件只能访问组件内部的 data数据源,要想访问其他组件就需要传值
<template> <div id="component_1"> <h1>子组件内容</h1> <p>{{ hour | hourToSecond }}</p> <p>{{ componentHour }}小时</p> <p>{{ componentMsg }}</p> <button @click="changeHour">子组件修改</button> </div> </template> <script> export default { props: ["hour", "msg"], data: function () { return { componentHour: 10, //组件的data函数中,可以使用props中的数据赋初始值 componentMsg: this.msg, }; }, methods: { changeHour(){ // 从父组件接收的传值是只读的,只能使用,不能修改。 // 也就是说vue中数据的传递是单向的,只能自上而下传递,子组件不能修改父组件的数据,这样保证了组件数据的安全性。这叫做vue组件的单向数据流。 console.log(">>>>",this.hour) this.componentHour++ } } }; </script> <style lang="less" scoped> </style>
子组件需要修改父组件数据可能是以下几个目的:
1.父组件传递的值不能直接使用,需要进一步加工:例如父组件传递的是一种单位(米),子组件需要显示另一种单位(千米),这种情况可以使用过滤器解决。
2.父组件传递的数据不能直接使用,需要进行一些计算,然后使用计算之后的结果,这种情况可以使用computed解决。
3.从父组件接受的值只是一个初始值,子组件需要把这个值赋值一份为自己所用。这种情况,需要在子组件的data定义一个变量取接受这个初始值,需要修改时就修改子组件data中的这个变量,而不是修改父组件传递的props。
3. 子组件 修改 父组件 数据
思考子组件 为什么不能修改 例如避免数据流混乱 难以管理
那父组件的数据 可以由父组件自己改变 ,咋改变呢写个函数 ,
好 那就在父组件写个 改变函数
这是父组件的 函数哦
changeCount(count) { this.totalPrice = this.price * count; },
接着分析 ,父组件可以通过 自己定义的修改函数 修改自己内部的数据
嘿嘿 如果 子组件可以调用 父组件的这个修改函数不就哦了
那问题来了怎么传 函数呢
js
里面 函数本身也是一种数据类型,那就按照正常的传法传嘛使用子组件的时候 绑定 属性 传值为函数的名字就可以
:cb="changeCount"
<p>单价:{{ price }}</p> <p>总价:{{ totalPrice }}</p> <Component-Emit :cb="changeCount"></Component-Emit> <hr />
子组件当然需要 接受下父组件的 传参嘛
props:["cb"] 少不了
子组件 内部 来个按钮 绑定自己的事件函数
在函数里面调用这个 cb就行了嘛 ,就当个正常的变量来使用
<template> <div id="component_2"> <span>商品数量</span> <button @click="add">{{ count }} +</button> </div> </template> <script> export default { props: ["cb"], data: function () { return { count:1, }; }, methods: { add(){ this.count++ // 方式一:使用父组件属性传值,得到函数 // 回调函 this.cb(this.count) } }, }; </script> <style scoped> </style>
这里其实 属性应该加个验证更好
props:{ cb:{ type:Function } }
以上就是用原有的 思想解决问题
重点是把 函数当做变量传给子组件 这种方法 非常常用哦
那
vue
难道自己没有解决方案嘛 ,当然有 ,一起玩下
4. 事件触发
这里默认你已经了解
emit
,其实不了解也无妨 ,能看懂 哈哈
我们采用倒推的方法来玩吧
先看我们下边的代码
写法类比回调函数 就是上面的写法
@get-count 其实也能猜出来 就是 自定义一个事件 事件名是
get-count
类似@click
嘛
<p>单价:{{ price }}</p> <p>总价:{{ totalPrice }}</p> <Component-Emit :cb="changeCount" @get-count="change"></Component-Emit> <hr />
change就是父组件的方法
methods:{ change(a, b) { this.totalPrice = this.price * a + b; },
那子组件怎么写呢
核心是
this.$emit("get-count",this.count,"¥")
参数1是事件名 和 父组件传参 绑定的保持一致
后续 可以根据需要 写很多参数
<template> <div id="component_2"> <span>商品数量</span> <button @click="add">{{ count }} +</button> <button @click="duce">{{ count }} +</button> </div> </template> <script> export default { props: ["cb"], data: function () { return { count:1, }; }, methods: { add(){ this.count++ // 方式一:使用父组件属性传值,得到函数 // 回调函 this.cb(this.count) }, duce(){ // 方式二: 发射事件:参数1:事件名 参数2及以上是要传递的参数 this.count -- this.$emit("get-count",this.count,"¥") } }, }; </script> <style scoped> </style>
5.简单写个 分页案例
简单的分页组件
<template> <div id="pageContainer"> <button @click="prevPage">上一页</button> <span>{{page}}</span> <button @click="nextPage">下一页</button> </div> </template> <script> export default { props: ["page","cb"], methods:{ prevPage(){ console.log("----") this.cb("prev") }, nextPage(){ // $emit方法只能给父组件发射事件,父组件的父组件不能接收到这个事件。 this.$emit("get-page","next") } } } </script> <style scoped> </style>
分页组件的使用
<p>父标签 获取到 page信息:{{ page }}</p> <Component-Page :page="page" :cb="changePage" @get-page="changePage" ></Component-Page>
6. 分页案例 v-model 实现
page.vue
<template> <div> <button @click="prevClick()">上一页</button> <span>当前页:{{value}}</span> <button @click="nextClick()">下一页</button> </div> </template> <script> // v-model = v-bind:value + v-on:input export default { // 这里必须用 value // 因为 v-model 指令 绑定的是 value属性 props:["value"], methods:{ prevClick(){ // 因为 v-model 绑定是 input事件 // 所以 emit 发射/方法调用 的必须是 input事件 this.$emit("input",this.value-1) }, nextClick(){ this.$emit("input",this.value+1) } } } </script>
App.vue使用
<Component-Model v-model="page1"></Component-Model>
本质 v-model
<!-- 本质 arguments[0] 子组件 $emit()方法的 事件参数 --> <Component-Model :value="page1" @input="page1 = arguments[0]" >本质</Component-Model>