dcloudio / uni-app

A cross-platform framework using Vue.js
https://uniapp.dcloud.io
Apache License 2.0
39.89k stars 3.62k forks source link

在小程序端,`v-if` 与 `v-slot:xxx` 表现异常 #4847

Open Skiyee opened 4 months ago

Skiyee commented 4 months ago
// content.vue
<template v-if="$slots.header">
  <div style="backgroundColor: red">
    <slot name="header">
    you can see this color
  </div>
</template>

// index.vue
<template v-if="false" #header>
  <view>
    Hello There
  </view>
</template>

H5端正确渲染,插槽正确消除 微信小程序端,插槽依旧可见

v-if 小于 v-slot 优先级

Skiyee commented 4 months ago

复现:Vue-Playground

Skiyee commented 4 months ago

https://github.com/dcloudio/uni-app/blob/a5e27eb636627891d51561fdbf16fa26aa56b03f/packages/uni-mp-compiler/src/transforms/vSlot.ts#L54

这段代码执行返回一个数组,但该数组是通过 findDir 扫描是否含有 slot 来判断的,但却忽略是否含有 v-if,导致产物 Prop 中的 u-s 传递是父文件内所有已使用 slot.

Skiyee commented 4 months ago

目前产物: image

理想产物: image

18148764734 commented 4 months ago

感谢反馈,目前对于这个v-if,v-slot的处理涉及到各种复杂情况,只能暂时先采用静态编译slot插槽的方案,无法在运行时动态的根据变量判断。

Skiyee commented 4 months ago

那有什么代替方案?我认为这种包裹 v-if 的写法是很常见的 @18148764734

taoyimin commented 3 months ago

还不支持吗?都没办法透传插槽了

zhshch9527 commented 1 month ago

底层组件:

<template>
  <view>
    <view>
      <slot name="header" v-if="hasSlot('header')">
      </slot>
      <view v-else>
        header
      </view>
    </view>
    <view>
      <slot name="footer"  v-if="hasSlot('footer')">
      </slot>
       <view v-else>
        footer
      </view>
    </view>
  </view>
</template>

<script>
  export default {
    name: "Demo1",
    props:{
      customSlots:{
        type:Object,
        default(){
          return {} ;
        }
      }
    },
    methods:{
      hasSlot(name){
        let customValue = this.customSlots[name] ;
        if(customValue === true || customValue === false){
          return customValue ;
        }
        return this.$slots[name] ;
      }
    }
  }
</script>

<style scoped>

</style>

中间组件:

<template>
  <demo2 :custom-slots="{header:!!$slots.header}">
    <template #header v-if="$slots.header">
      <slot name="header" title="header"/>
    </template>
  </demo2>
</template>

<script>
  import Demo2 from "./Demo2";
  export default {
    components:{Demo2},
    name: "Demo1"
  }
</script>

<style scoped>

</style>

这么特殊判断的