稻壳dotcoo
稻壳dotcoo
  • 发布:2023-06-09 16:49
  • 更新:2023-09-27 11:59
  • 阅读:309

【报Bug】小程序中$attrs多层传递后, $emit不能触发事件.

分类:uni-app

产品分类: uniapp/小程序/微信

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: win10

HBuilderX类型: 正式

HBuilderX版本号: 3.8.4

第三方开发者工具版本号: 1.06.2306020

基础库版本号: 2.32.1

项目创建方式: HBuilderX

示例代码:
  • index.vue
<template>  
  <div>Index: <button @click="onShow">Show</button></div>  
  <ComA :show="show" @msg="onMsg"></ComA>  
</template>  

<script>  
import ComA from './ComA.vue';  
export default {  
  components: {  
    ComA,  
  },  
  data() {  
    return {  
      show: false,  
    };  
  },  
  methods: {  
    onShow() {  
      this.show = !this.show;  
    },  
    onMsg(msg) {  
      uni.showToast({ icon: 'none', title: 'index msg: ' + msg });  
    },  
  },  
};  
</script>
  • ComA.vue
<template>  
  <div>ComA: {{$attrs.show?true:false}} <button @click="$emit('msg', 'from ComA')">Msg</button></div>  
  <ComB v-bind="$attrs"></ComB>  
</template>  

<script>  
import ComB from './ComB.vue';  
export default {  
  components: {  
    ComB,  
  },  
  created() {  
    // 这里 H5 会打印出 onMsg 和 show 两个 key, 小程序只会打印出来 show 一个 key.  
    console.log('ComA', this.$attrs);  
  },  
}  
</script>
  • ComB.vue
<template>  
  <div>ComB: {{$attrs.show?true:false}} <button @click="$emit('msg', 'from ComB')">Msg</button></div>  
  <ComC v-bind="$attrs"></ComC>  
</template>  

<script>  
import ComC from './ComC.vue';  
export default {  
  components: {  
    ComC,  
  },  
  created() {  
    console.log('ComB', this.$attrs);  
  },  
}  
</script>
  • ComC.vue
<template>  
  <div>ComC: {{$attrs.show?true:false}} <button @click="$emit('msg', 'from ComC')">Msg</button></div>  
  <!-- <ComD v-bind="$attrs"></ComD> -->  
</template>  

<script>  
// import ComD from './ComD.vue';  
export default {  
  // components: {  
  //   ComD,  
  // },  
  created() {  
    console.log('ComC', this.$attrs);  
  },  
}  
</script>

操作步骤:

运行小程序开发者工具后,
点击第一个 Msg 按钮, 能正常触发 msg 事件,
点击第二个 Msg 按钮, 不能触发 msg 事件.

预期结果:

点击第一个 Msg 按钮, 能正常触发 msg 事件
点击第二个 Msg 按钮, 能正常触发 msg 事件.

实际结果:

点击第一个 Msg 按钮, 能正常触发 msg 事件
点击第二个 Msg 按钮, 不能触发 msg 事件.

bug描述:

https://ask.dcloud.net.cn/uploads/questions/20230609/249dff118568fae75786f6ec5c58a18e.png

小程序中$attrs多层传递后, $emit不能触发事件. H5和App是可以了.

index.vue 传递了事件 msg 给子组件 ComA
ComA 调用 $emit('msg', 'from ComA') 可以触发 msg 事件
ComA 通过 v-bind="$attrs" 传递属性给子组件 ComB
ComB 调用 $emit('msg', 'from ComB') 不能触发 msg 事件

再 ComA 的 created 生命周期事件中打印 $attrs, H5 中有个 onMsg 和 show 两个 key, 小程序中只有 show 一个 key.

具体参看附件代码.

2023-06-09 16:49 负责人:无 分享
已邀请:
稻壳dotcoo

稻壳dotcoo (作者) - 稻壳dotcoo

给 ComA 传递了一个 msg 事件, 但是在 ComA 组件选项中, 并没有声明 emits: ['msg'],

所以 msg 事件, 也就是 onMsg 方法, 应该包含在 $attrs 中,

编译后的小程序代码, pages/index/index.js 的 _sfc_render 函数 return 的数据应该包含 onMsg 方法,

也就是传递给 ComA 中 u-p 属性的数据.

稻壳dotcoo

稻壳dotcoo (作者) - 稻壳dotcoo

比对了下 h5 和 小程序的最终代码

稻壳dotcoo

稻壳dotcoo (作者) - 稻壳dotcoo

修复了, 但是有个缺点是, 拿不到vue文件里的emits, 不知道哪个事件是当前组件会触发的, 所以把所有事件都放在了$attrs里边.

D:\soft\HBuilderX\plugins\uniapp-cli-vite\node_modules\@dcloudio\uni-mp-compiler\dist\transforms>git diff transformComponent.js transformComponent-change.js  
diff --git a/transformComponent.js b/transformComponent-change.js  
index 87910ef..dcacb3b 100644  
--- a/transformComponent.js  
+++ b/transformComponent-change.js  
@@ -134,7 +134,7 @@ function rewriteBinding({ tag, props }, context) {  
             properties.push(createObjectProperty(name, (0, types_1.stringLiteral)(prop.value?.content || '')));  
         }  
         else if ((0, uni_cli_shared_1.isDirectiveNode)(prop)) {  
-            if (prop.name !== 'bind') {  
+            if (prop.name !== 'bind' && prop.name !== 'on') {^M  
                 continue;  
             }  
             const { arg, exp } = prop;  
@@ -147,6 +147,21 @@ function rewriteBinding({ tag, props }, context) {  
                     properties.push(spreadElement);  
                 }  
             }  
+            else if (prop.name === 'on') {^M  
+                if (exp.type !== 8) {^M  
+                    continue;^M  
+                }^M  
+                isIdProp = true;^M  
+                if (!isComponentProp(arg.content)) {^M  
+                    continue;^M  
+                }^M  
+                // @name="name"^M  
+                const valueExpr = (0, ast_1.parseExpr)((0, codegen_1.genExpr)(exp), context, exp);^M  
+                if (!valueExpr) {^M  
+                    continue;^M  
+                }^M  
+                properties.push(createObjectProperty('on'+arg.content.toUpperCase().substring(0, 1)+arg.content.substring(1), valueExpr));^M  
+            }^M  
             else if ((0, compiler_core_1.isStaticExp)(arg)) {  
                 isIdProp = arg.content === 'id';  
                 if (!isComponentProp(arg.content)) {  

D:\soft\HBuilderX\plugins\uniapp-cli-vite\node_modules\@dcloudio\uni-mp-compiler\dist\transforms>
前端xiao白

前端xiao白

事件透传丢失已经修复了吗?现在开发中仍然遇到这个问题,未使用 defineEmits 定义的事件在 $attrs 中不存在

  • 稻壳dotcoo (作者)

    没有! 估计用的人少, 官方也没啥兴趣修复.

    2023-09-27 16:23

要回复问题请先登录注册