前言
Vue项目开发过程中,有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者是子组件访问根组件。梳理出如下请求方法:
- 父组件访问子组件:
$children
或者$refs
- 子组件访问父组件:
$parent
- 子组件访问根组件(通过
new Vue
创建的根Vue
实例):$root
父组件访问子组件
使用 $children
在父组件中使用 this.$children
拿到的是一个数组类型,它包含所有子组件实例。
<div id="app">
<cpn></cpn>
<cpn></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>
<h1>我是子组件</h1>
</div>
</template>
<script>
let vm = new Vue({
el: "#app",
data: {},
methods: {
btnClick() {
//1.拿到所有子组件,是一个数组
console.log(this.$children);
//2.拿到一个组件实例,可以直接访问子组件中的方法和 data 中的数据
this.$children[0].showMessage();
console.log(this.$children[0].name);
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: 'webchang'
}
},
methods: {
showMessage() {
console.log('我是子组件');
}
}
}
}
});
</script>
使用 $refs
使用$children
的缺陷如下:
通过 $children
访问子组件时,是一个数组类型,访问其中的子组件必须通过索引值。
但是当子组件过多,我们需要拿到其中一个时,往往不能确定它的索引值,甚至还可能会发生变化。
有时候,我们想明确获取其中一个特定的组件,这个时候就可以使用 $refs
$refs
的使用
通过设置子组件的ref
,父组件通过this.$refs.xxx.method_name(data)
调用子组件方法,data
参数可选。
$refs
和 ref
指令通常是一起使用的。
首先,我们在子组件上添加一个 ref
属性,相当于给某一个子组件绑定一个特定的ID
。
其次,this.$refs
拿到的是所有标有 ref
属性的子组件(如果一个子组件实例没有 ref
属性,通过这种方式是拿不到的),最后拿到的是一个对象,属性名是子组件实例的 ref
属性,属性值是该组件实例。
通过 this.$refs.ID
就可以访问到该组件。
示例代码如下:
<div id="app">
<cpn ref="child1"></cpn>
<cpn ref="child2"></cpn>
<!-- 这个子组件实例没有 ref 属性,通过 this.$refs 方式拿不到这个组件实例 -->
<cpn></cpn>
<button @click="btnClick">按钮</button>
</div>
<template id="cpn">
<div>
<h1>我是子组件</h1>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
data: {
message: "hello"
},
methods: {
btnClick() {
console.log(this.$refs)
console.log(this.$refs.child1)
console.log(this.$refs.child1.name)
this.$refs.child1.showMessage('父组件')
}
},
components: {
cpn: {
template: '#cpn',
data() {
return {
name: 'webchang'
}
},
methods: {
showMessage(value) {
console.log("子组件方法被调用,调用者:" + value)
}
}
}
}
});
</script>
子组件调用父组件方法
方法一:this.$parent.event
直接在子组件中通过this.$parent.event
来调用父组件的方法。示例代码如下:
父组件
<template>
<div>
<child></child>
</div>
</template>
<script>
import child from './components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod(value) {
console.log("父组件方法被调用,调用者:" + value)
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod()">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$parent.fatherMethod('子组件');
}
}
};
</script>
注意事项:
- 尽管在
Vue
开发中,我们允许通过$parent
来访问父组件,但是在真实开发中尽量不要这样做。 - 子组件应该尽量避免直接访问父组件的数据,因为这样代码耦合度太高了。
- 如果我们将子组件放在另外一个组件之内,很可能该父组件没有对应的属性,往往会引起问题。
- 另外,通过
$parent
直接修改父组件的状态,那么父组件中的状态将变得飘忽不定,很不利于调试和维护。
方法二: $emit
在子组件里用$emit
向父组件触发一个事件,父组件监听这个事件。
父组件
<template>
<div>
<child @fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('测试');
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod()">点击</button>
</div>
</template>
<script>
export default {
methods: {
childMethod() {
this.$emit('fatherMethod');
}
}
};
</script>
方法三:方法传参
父组件把方法传入子组件中,在子组件里直接调用这个方法。
父组件
<template>
<div>
<child :fatherMethod="fatherMethod"></child>
</div>
</template>
<script>
import child from '~/components/dam/child';
export default {
components: {
child
},
methods: {
fatherMethod() {
console.log('测试');
}
}
};
</script>
子组件
<template>
<div>
<button @click="childMethod()">点击</button>
</div>
</template>
<script>
export default {
props: {
fatherMethod: {
type: Function,
default: null
}
},
methods: {
childMethod() {
if (this.fatherMethod) {
this.fatherMethod();
}
}
}
};
</script>
子组件 更简便的写法
<template>
<div>
<button @click="fatherMethod()">点击</button>
</div>
</template>
<script>
export default {
props: {
fatherMethod: {
type: Function,
default: null
}
},
methods: {
}
};
</script>
其他调用方法
由于最终所有组件都会渲染成真实的Dom
元素,所以可以通过js
或jquery
,获取Dom
元素对象,通过模拟点击的方式触发元素绑定的方法,通过本地Cookie
、localStorage
或sessionStorage
做参数缓存,实现值传递。此方法不限于子父组件,只要组件位于同一页面都可使用,但因为不符合vue
规范,并非特殊情况不建议使用。
组件A:
<template>
<div>
<h1>我是组件A</h1>
<button id='btn' @click='methodA()'>点我</button>
</div>
</template>
<script>
export default {
methods: {
methodA() {
var parameter= localStorage.getItem('parameter');
console.log('我是组件A方法');
}
}
};
</script>
组件B:
<template>
<div>
<h1>我是组件B</h1>
<button @click='methodB(data)'>点我</button>
</div>
</template>
<script>
export default {
methods: {
methodB(data) {
localStorage.setItem('parameter',data);
$('#btn').click();//模拟按钮点击
console.log('模拟点击按钮,触发A组件方法');
}
}
};
</script>