7***@qq.com
7***@qq.com
  • 发布:2022-11-28 18:34
  • 更新:2024-03-27 18:18
  • 阅读:2136

关于在 renderjs 父子组件通信的的实现【有着一点自己的经验】

分类:uni-app

前言
最新在做的一个项目,需要同时实现 H5 和 APP 以及小程序三端,所以自然而然的选择了 uni-app,但是引用的库同时有着需要使用 dom API 和 worker 这两个痛点,寻寻觅觅,我找到了 renderjs

为啥选他
renderjs 首先能够支持使用 dom API,在一些三方库频繁操作 dom,你又不得不依赖这个库的时候,renderjs 会是一个不错的方案。

app 端不支持使用 worker, uni 文档上写着需要使用 renderjs 或者 webview,而 webview 往往会设计 webview 通信的问题,在 APP 端的 webview 通信想要不错的支持只能使用 nvue 来实现,而如果你是想要实现一个组件的话就会是 .nvue 组件,而 uni 官方说了 .nvue 组件只能在 .vue 页面中使用,这就带来了其他页面使用该组件的负担,及app的实现必须使用 .nvue,而同时维护 .vue 和 .nvue 文件是有着一定代价的(关于这里,只是单纯的我还没想好怎么处理这里的关系)。所以,我选择了 renderjs

问题
renderjs 在 h5 的表现和你正常开发一个 vue 组件没有什么区别,唯一要注意的点就是使用了不太建议在 vue2 + typeScript 的项目中去实现它,因为一旦使用 vue.extned() 的这个方法去定义组件就会导致 h5 渲染不正常(也可能是单纯的我是个菜逼)

而 renderjs 在 App端 的差异就比较大了,最重要的一点就是视图层和逻辑层的方法与变量不能互相通信,而另一方面,如果使用了 renderjs 作为子组件,在使用最经典的 props/emit 实现的父子间传值就会有点麻烦,就是本文的重点。

实现
首先,我们这个方案依赖于官方文档给的 echarts 的那个 demo。那个 demo 展示了在 app 端如何让视图层与逻辑层通信(即 renderjs 与原来的 script )。

上面两张图片就是官方文档给的 echarts 的那个 demo 外带一点小注解。
下面开始讲讲它作为子组件如何完成与父组件的双向通信。

父组件向子组件传值

  1. 首先,在逻辑层(原先的 script )中正常写 props 接收你父组件要传的值
  2. renderjs 监听该值的变动,随着变动修改自己的属性
<template>  
    <div>  
        <div :prop="test" :change:prop="renderModule.onUpdateTestChange" ></div>  
    </div>  
</template>  
<script lang="ts">  
export default {  
    props: {  
        test: {  
            type: String,  
            default: "",  
        },  
    },  
}  
</script>  
<script module="renderModule" lang="renderjs">  
export default {  
    data() {  
         return {  
                renderTest: '',  
         }  
    }  
    methods: {  
            onUpdateTestChange(newVal, oldVal, ownerInstance, instance) {  
                   this.renderTest = newVal; // 到这里,成功的获得了父组件传来的 test 值并保存在 renderjs 中的 renderTest 中。  
            }  
    }  
}  
</script>

但是,实际上有更快的方法。
在视图层与逻辑层能够访问统一个对象(文档上说的),该对象包含一个对象指向本组件,也就是说,可以直接通过该对象访问组件的所有属性和方法,实际上我只在视图层使用过(毕竟在逻辑层没必要=-=),他就是 this.$ownerInstance
所以在逻辑层想要访问 test 值,可以直接

this.$ownerInstance.$vm.test 

再啰嗦一句,这个 $vm 就是组件实例等价于每次正常写的那个 this,所以这样能够访问到就能够理解了。
不过有点奇怪的就是我写的 this.$ownerInstance.$vm.$emit 方法想要尝试触发父组件方法并没有成功,有可能是我写错了,具体原因还不明白,之后有结论了我再更新。

子组件向父组件传值

    methods: {  
            onUpdateTestChange(newVal, oldVal, ownerInstance, instance) {  
                   this.renderTest = newVal; // 到这里,成功的获得了父组件传来的 test 值并保存在 renderjs 中的 renderTest 中。  
            }  
    }

这个是刚才的代码,我再借用下。请注意下 ownerInstance 。
我再上面的图片有标注,这个很重要就是因为我们能够看到在点击触发逻辑层方法时,能够通过 ownerInstance.callMethod 触发普通 script 的方法,进而在普通 script 的那个方法下使用 this.$emit 触发父组件方法。但是这样就会有着必须点击才能触发父组件方法的限制,这不能够啊。这个时候可以将 ownerInstance 保存起来,之后想要调用方法的时候就不需要通过点击事件传来的 ownerInstance 才能触发逻辑层的方法了。

    methods: {  
            onUpdateTestChange(newVal, oldVal, ownerInstance, instance) {  
                   this.renderTest = newVal; // 到这里,成功的获得了父组件传来的 test 值并保存在 renderjs 中的 renderTest 中。  
                   if (!this.ownerInstance) this.ownerInstance = ownerInstance;// 这样就能保存了 ownerInstance  
            },  
            // 这个就是尝试  
            niceTry() {  
                    this.ownerInstance?.callMethod('%父组件的方法%',%要传给父组件的参数%);  
            }  
    }

另外再提一嘴,就是 this.$ownerInstance.callMethod 不成,小伙伴们可以自己试试,没准也是我搞错了。

至此,父子组件双向通信就算成了。不懂或是发现错误的小伙伴们可以直接评论,只要我还在做现在这个项目应该会满经常上 uni 这边逛逛的。

0 关注 分享

要回复文章请先登录注册

1***@qq.com

1***@qq.com

我的app中this.$ownerInstance.$vm拿不到值
2024-03-27 18:18
7***@qq.com

7***@qq.com

回复 aak12345 :
renderjs没有uni
2024-01-30 22:48
aak12345

aak12345

回复 8***@qq.com :
没有哦,我直接用uni.$on没报错。我是vue2的
2023-11-10 11:50
8***@qq.com

8***@qq.com

回复 aak12345 :
renderjs 添加$on 会提示not a function 你是如何实现的?
2023-11-10 10:12
aak12345

aak12345

https://uniapp.dcloud.net.cn/api/window/communication.html uni主动发消息给iframe,可以在renderjs里面添加uni.$on,然后在uni里面uni.$emit
2023-11-08 19:19
z***@163.com

z***@163.com

真机有效吗,我在虚拟机可以,本地跑真机也可以,就是打包后真机,不能触发change
2023-06-29 15:14
1***@163.com

1***@163.com

大佬好棒,解决了我的问题
2023-06-14 17:23