【问题标题】:Accessing and modyfing slot's elements in Vue 3在 Vue 3 中访问和修改槽元素
【发布时间】:2021-06-30 20:51:19
【问题描述】:

我目前正在将基于 MQTT 的仪表板从 Vue 2 重写为 Vue 3,但无法解决一个问题。

仪表板有许多 Vue 组件,它们对特定的 MQTT 主题和值做出反应,以显示当前系统状态。其中之一是 mqtt-multi-state 组件,声明如下:

// status-page

<mqtt-multi-state subscribe-topic="home/env/sensor/wc/door/status" json-path="state">
  <div value="OPEN"><font-awesome-icon icon="door-open"/></div>
  <div value="CLOSED"><font-awesome-icon icon="door-closed"/></div>
</mqtt-multi-state>

它包含两个div 元素,具有系统传感器(门)可以具有的两种状态。这些元素被传递到default 插槽,默认通过css隐藏。

我想要实现的是基于它们每个中的value attr 与当前 MQTT 值的相等性来显示其中一个。因此,如果当前值为 OPEN 则显示第一个 div,当值为 CLOSED 时出现第二个。

// mqtt-multi-state

<template>
    <div class="mqtt-multi-state">
        <div>
            <slot></slot>
        </div>
    </div> 
</template>

<script>
export default {
  methods: {
    messageArrived(value){
      
      let states = this.$slots.default() // here are the two divs
 
      for(let i = 0;i < states.length;i++ ){
        if(states[i].props.value === value )
        {
          //states[i].elm.className = "state-active" <- Vue 2 solution using DOM with elm
          //states[i].props.class = "state-active"; <- Vue 3, doesn't work, not reactive?
        }
        else 
        {
          //states[i].props.class = "";
        }
      }
   }
 }
}
</script>

我知道,这种方法有点不同,但我真的很喜欢用这种方式在 HTML 中描述仪表板元素。在messsageArrive() 方法中,我正在迭代default 插槽子元素,如果值与当前value 道具匹配,我想通过添加state-active 类来显示此项目。但是这个解决方案不起作用。 VNode 已更改(在控制台中检查)。

在 Vue 2 中,我只是直接访问 DOM 元素并更改它的类,但在 Vue 3 中,我无法弄清楚如何从 VNode 到 DOM 节点。或者可能有其他/更好的方法来做到这一点?

【问题讨论】:

    标签: javascript vuejs3


    【解决方案1】:

    好吧,很多晚上​​后我才找到了这个解决方案。我没有将所有不同的状态放入默认槽中,而是创建了动态命名槽。

    不同的状态元素(在这种情况下是字体很棒的图标)转到每个插槽的模板元素。不幸的是,我无法将 mqtt 值传递给模板元素本身,因为它不存在于 mqtt-multi-state 父组件中。相反,我将 mqtt 值传递给模板的第一个子元素。可以是任意元素,divpfont-awesome-icon

    // status-page
    
    <mqtt-multi-state :state-count="2" subscribe-topic="home/env/sensor/wc/door/status" json-path="state">
      <template #0><font-awesome-icon value="OPEN" icon="door-open"/></template>
      <template #1><font-awesome-icon value="CLOSED" icon="door-closed"/></template>
    </mqtt-multi-state>
    

    还有一个 prop state-count 定义了不同状态的数量。注意道具名称前的冒号,所以字符串“2”是数字类型。

    mqtt-multi-state 组件变成这样:

    // mqtt-multi-state
    
    <template>
      <div class="mqtt-multi-state">
        <template v-for="(slot, index) in slots">
          <slot :name="index" v-if="slot" ></slot>
        </template>
      </div> 
    </template>
    
    <script>
    export default {
      data: function(){
        return {
          slots: []
        }
      },
      props: {
        stateCount: {
          default: 2,
          type: Number
        }
      },
      methods: {
        messageArrived(value){
          for(let i = 0; i < this.stateCount; i++ ) {
            this.slots[i] = this.$slots[i]?.()[0]?.props?.value === value
          } 
        }
      }
    }
    </script>
    

    messageArrived() 函数中,代码遍历所有槽并将槽的第一个子元素prop(名为value)与接收到的当前mqtt 值进行比较。如果值相等,则 this.slots[i] 数组值变为 true,并且 Vue 的 v-if 指令使相应的插槽可见,否则隐藏插槽。

    命名插槽名称由index 值创建,因此要使用this.$slot.slotNameRenderFunction() 获取它们的内容,我使用this.$slot[index]() 表示法调用函数0()1() 等(通过存储在变量)带有可选的链接运算符?. - 所以整个符号看起来有点奇怪:)。

    【讨论】:

      猜你喜欢
      • 2023-02-05
      • 2021-02-01
      • 1970-01-01
      • 2021-05-11
      • 2019-02-20
      • 1970-01-01
      • 2022-07-27
      • 1970-01-01
      • 2018-08-09
      相关资源
      最近更新 更多