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>