Vue的组件传值
首先Vue我认为有几个最大的特点,
- 第一点数据驱动,无需手动操作dom。以及MVVM模式
- 第二点支持模块化开发
- vNode虚拟dom diff算法
vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么就需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式,并且在模块化开发时,一定是需要拆分的,也就是我们常用的路由以及组件等方式,所以衍生出了这个问题,如何进行组件之间的传值问题,又为什么必须要这么去做呢?
- 首先模块化开发,使用的是树形结构,必须要有一个根,根组件向下传递是很容易实现的事情,定义一个属性,然后在下级组件中使用props进行接收即可。
- 在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: '<p>星期{{day}}</p>'
}
const vm = new Vue({
el: '#app',
data: {
day: '五'
},
components: {
child
}
})
</script>
- 但是问题在于传递个子组件的值,子组件可以任意进行更改,而对于父组件来说,不仅仅只有一个子组件,这样就有可能破坏了其他子组件的引用关系,从而出现问题,并且最大的问题在于,它破坏了我们的树状结构,由下而上的更改我们父级的值,打破了规则,这是完全不能接受的。所以不能直接在子组件中去操作父组件传递过来的数据!!那么如果想要操作我们有两个取巧的方法,当然仍然遵守规则,子组件不可更改父组件内的数据。
- 第一个方法:在子组件中自己定义一个变量去保存父组件的数据,然后修改我们保存下来的变量的值达到效果
- 第二个方法: 使用computed来改变
- 可以将父组件传递的数据仅作为初始化数据,接下来的数据变化时使用改变数据
const child = {
props: ["titleValue","propValue","x","y","z"],
template:`
<div>{{title2}}</div>
`,
data(){
return {
/* 个人理解: 简单来说 我们将父级传递来的数据本地化,初始化
那么第一次使用的时候就是父级传递来的值,下次再改变时,也不会修改
父级传递值的内容
类似于 重新赋值
*/
title: this.titleValue, // 只被渲染一次
}
},
mounted () {
// 单向数据流 如果在这里改变父组件传递过来的值 父级props的更新会流动到子组件中,
// 但是反过来不行,这样会防止从子组件以外变更父级组件的状态,从而导致你的应用数据流难以理解
// 如果想要修改父组件传递过来的值,那么我们可以将这个值
setTimeout(()=>{
this.title="world"
},2000)
console.log(typeof this.propValue);
},
// 方法二: 我们通过computed 来改变
computed: {
title2(){
return this.title+"!!!";
}
},
}
父级向下传递数据 二
- 使用provide和inject依赖注入
- 总是成对出现
- 使用方法:使用provide在父组件中返回要传输的数据,使用inject在下级组件中进行注入数据
// 父组件
provide(){
return {
user:this.user,
}
},
// 子组件
inject:{
user:{
default:()=>{}
},
- 另外再说一个小知识点
const child3={
//如果写props验证 就可以使用传入数据在template中的标签内使用
//如果不写 会默认将传入数据 放在组件的"根"元素上 简单的理解 就是写在了标签上(一鱼两吃!) 做了一个活口
//inheritAttrs属性是 禁止Attribute的继承 也就是即便不写props也不会被继承
//但是有例外 只有stype和class仍然会被设置在标签上 其他即便是id也不会被设置
inheritAttrs: false,
template:`
<div></div>
`
}
子级向上传递数据
- 讲完了父组件向子组件传递,再来将子组件如何向父组件传递数据
- 子组件模版内容中用
$emit()定义自定义事件,$emit()方法至少有2个参数- 第一个参数为自定义的事件名称(不要和内置的事件重名,例如click、change等)abc
- 第二个参数为需要传递的数据(可选,如果传可以是任何格式的数据)
- …
- 子组件模版内容中用
-
父组件模板内容中的子组件占位标签上用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: `<button @click="$emit('anlarge-text',9)">点我给父组件字体加9px</button>`,
}
// 根组件(父)
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>
**非父子传递数据 **
- 先介绍一个Bus总线的方法
- 那么它能够做什么呢?它不仅可以进行非父子组件的数据传输,同样可以进行父子组件的数据传输,听起来非常好用,但是它会破坏规则,并且在大型项目开发时,会导致关系混乱,所以并没有想象中那么好用
EventBus
在Vue中通过单独的事件中心来管理非父子关系组件(兄弟)间的通信:

这里来讲一下什么是Bus总线,举个栗子:某情侣因为异地分居这时候没有办法直接见到彼此,所以就每天需要电话通信,男方就是组件A,女方就是组件B,事件中心就是运营商,当男方或者女方给对方打电话时,就会触发运营商的监听事件,发送消息给另外一方就实现了通信了。
核心步骤
- 那么它能够做什么呢?它不仅可以进行非父子组件的数据传输,同样可以进行父子组件的数据传输,听起来非常好用,但是它会破坏规则,并且在大型项目开发时,会导致关系混乱,所以并没有想象中那么好用
- 建立事件中心
-
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: `
<div>
<div>{{data}}</div>
<div><button @click='fn1'>点我让对方受到1点伤害</button></div>
</div>
`,
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: `
<div>
<div>{{data}}</div>
<div><button @click='fn2'>点我让对方受到2点伤害</button></div>
</div>
`,
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,可以很方便实现组件之间的参数传递。
本文围绕Vue组件传值展开。介绍了Vue数据驱动、支持模块化等特点,强调组件间数据通信的重要性。详细阐述了父子组件传值(父传子、子传父)的多种方法,如props、provide和inject、自定义事件等,还提及非父子组件传值的Bus总线法,最后指出Vuex可方便实现组件参数传递。
1367

被折叠的 条评论
为什么被折叠?



