场景:需要直接拿到子组件的一个方法,并直接执行它
子组件:
import { defineComponent } from "vue"
const PropsType = {
age: {
type: Number,
required: true
}
} as const
const consoleLog = () => {
console.log("11111")
}
export default defineComponent({
props: PropsType,
setup(props) {
return () => {
return <div onClick={consoleLog}>{props.age}</div>
}
}
})
父组件:
import { ref } from "vue"
import Test from "./test"
export default defineComponent({
setup() {
const test = ref(null)
const trickMethods = (): void => {
//想要这在这里通过ref直接执行子组件的 consoleLog 方法
}
return () => {
return (
<div>
<Test ref={test} age={12} />
<div>
<h1 onClick={trickMethods}>Test Click</h1>
</div>
</div>
)
}
}
})
都搞过optionsApi的我们一定都知道,我们先要拿到这个实例对象。
那么我们可不可以通一个方法,来拿取这个对象的实例呢?
首先,我们重新改造一下这个ref
构建一个简单的declare文件,定义一个类型别名RefInstanceType
declare type RefInstanceType<T> = {
$: T
} | null
定义一个拥有consoleLog这个方法的接口
export interface ActionType {
consoleLog: () => void
}
然后将const test = ref(null)修改,现在的父组件是这样的:
import { ref } from "vue"
import { ActionType } from "./testTypes"
import Test from "./test"
export default defineComponent({
setup() {
//const test = ref(null)
const test = ref<RefInstanceType<ActionType>>(null)
const trickMethods = (): void => {
//想要这在这里通过ref直接执行子组件的 consoleLog 方法
}
return () => {
return (
<div>
<Test ref={test} age={12} />
<div>
<h1 onClick={trickMethods}>Test Click</h1>
</div>
</div>
)
}
}
})
这个时候,在理论上,我们已经可以拿到这个实例对象了,但是打印之后,我们发现这个实例对象是被proxy是包裹的
写了一个简单的方法
import { unref } from "vue"
export function getRef(origin: any) {
const unRefsType = unref(origin)
if (!unRefsType) {
throw new Error("you want to get ref is null!")
}
return unRefsType.$
}
这个时候,通过getRef(test)已经可以拿到这个实例了,此时的父组件:
import {ref } from "vue"
import Test from "./test"
import { ActionType } from "./testTypes"
import { getRef } from "@/utils/getRef"
export default defineComponent({
setup() {
const test = ref<RefInstanceType<ActionType>>(null)
const trickMethods = (): void => {
console.log(getRef(test))
}
return () => {
return (
<div>
<Test ref={test} age={12} />
<div>
<h1 onClick={trickMethods}>Test Click</h1>
</div>
</div>
)
}
}
})
但是,我们会发现 ,实例上并没有consoleLog这个方法……
我们可以通过getCurrentInstance这个API来访问内部组件实例
那么,我们就写一个方法,将子组件的方法绑定到由getCurrentInstance获取到的实例中
定义一个方法
import { getCurrentInstance } from "vue"
export function useFuncEmit(fn: (instance: any) => void):any {
const instance = getCurrentInstance()
if (instance) {
fn.call(null, instance)
}
}
然后在子组件中进行挂载
import { defineComponent } from "vue"
import { useFuncEmit } from "@/utils/vueHelper"
const PropsType = {
age: {
type: Number,
required: true
}
} as const
const consoleLog = () => {
console.log("11111")
}
export default defineComponent({
props: PropsType,
setup(props) {
return () => {
useFuncEmit(Instance => {
Instance.consoleLog = consoleLog
})
return <div onClick={consoleLog}>{props.age}</div>
}
}
})
此时父组件:
import {ref} from "vue"
import Test from "./test"
import { ActionType } from "./testTypes"
import { getRef } from "@/utils/getRef"
export default defineComponent({
setup() {
const test = ref<RefInstanceType<ActionType>>(null)
const trickMethods = (): void => {
getRef(test).consoleLog()
}
return () => {
return (
<div>
<Test ref={test} age={12} />
<div>
<h1 onClick={trickMethods}>Test Click</h1>
</div>
</div>
)
}
}
})