问题描述

最近在用 uni-app 开发前端页面时,原本只对 H5、微信小程序做兼容,一直没啥问题。今天在支付宝小程序上面跑了一下,发现兼容问题不少,比如说通过 ref 调用自定义组件中的方法时,发现无法通过 this.$refs 来获取子组件。部分代码如下:

子组件 child-component:

<template>
    <view></view>
</template>

<script>
    export default {
        methods: {
            init () {
            }
        }
    }
</script>

引入子组件的页面:

<template>
    <view>
        <button @tap="toShow">显示</button>
        <uni-popup ref="uni-popup" @tap.stop="" @change="popupChange">
            <child-component ref="child-component"/>
        </uni-popup>
    </view>
</template>

<script>
    import uniPopup from "@/uni-ui/components/uni-popup/uni-popup"
    import childComponent from '@/components/child-component'
    
    export default {
        components: {
            uniPopup,
            childComponent
        },
        methods: {
            toShow () {
                this.$refs['uni-popup'].open()
            },
            popupChange (result) {
                if (result.show) {
                    this.$refs['child-component'].init()
                }
            }
        }
    }
</script>

问题表现:
在支付宝小程序中运行后,会出现如下错误:

Uncaught TypeError: Cannot read property 'init' of undefined at *.js

根据字面意思就很容易知道问题所在,this.$refs['child-component'] 得到的是 null。

问题解决

由于 this.$refs['uni-popup'] 可以获取到,因此可以断定支付宝小程序中是可以使用 ref,并通过 this.$refs 来获取组件的。上面出现无法获取的问题,可能就是出在使用了子组件。

既然 this.$refs['uni-popup'] 不为空,那我们就看看它的值具体是怎样的:

如图,我们发现 this.$refs['uni-popup'] 中的 refs 存在我们要的子组件,因此我们可以直接通过 this.$refs['uni-popup'].$refs['child-component'] 获取子组件。改造下上面的代码后如下:

<template>
    <view>
        <button @tap="toShow">显示</button>
        <uni-popup ref="uni-popup" @tap.stop="" @change="popupChange">
            <child-component ref="child-component"/>
        </uni-popup>
    </view>
</template>

<script>
    import uniPopup from "@/uni-ui/components/uni-popup/uni-popup"
    import childComponent from '@/components/child-component'
    
    export default {
        components: {
            uniPopup,
            childComponent
        },
        methods: {
            toShow () {
                this.$refs['uni-popup'].open()
            },
            popupChange (result) {
                if (result.show) {
                    setTimeout(() => { // 该定时器防止子组件未渲染导致获取不到
                        if (this.$refs['child-component'] != null) {
                            this.$refs['child-component'].init()
                        } else {
                            this.$refs['uni-popup'].$refs['child-component'].init()
                        }
                    }, 200)
                }
            }
        }
    }
</script>

再次在支付宝小程序中运行,发现问题已解决了。