Как получить наследование атрибутов для слотов компонентов Vue? - PullRequest
0 голосов
/ 28 мая 2018

Я пишу компонент Vue, который принимает 2 слота:

<template>
  <div class="Component">
    <div class="Component-Label">
      <slot
        name="label"
        class="Component-LabelInner"
      />
    </div>
    <div class="Component-Input">
      <slot
        name="input"
        class="Component-InputInner"
      />
    </div>
  </div>
</template>


<style scoped>
.Component { ... }

.Component-Label { ... }

.Component-LabelInner { ... }

.Component-Input { ... }

.Component-InputInner { width: 100%; ... }
</style>

В целях макета мне абсолютно необходимо применить некоторые стили к элементам <slot> - те, которые имеют Component-LabelInner иComponent-InputInner классы.

(Точнее, мне нужно применить правило width: 100% к Component-InputInner, как обычно я пропущу там элемент <input> и хочу, чтобы все, что я пропущу, растянулосьв контейнер.)

Проблема в том, что после замены элементов <slot> содержимым, предоставленным в слоты, атрибут class не наследуется (кажется, что атрибуты не наследуются в слотах) и CSSселекторы для .Component-LabelInner и .Component-InputInner не работают.

Можете ли вы каким-то образом добавить классы CSS к элементу, которым заменяется <slot>?

1 Ответ

0 голосов
/ 28 мая 2018

Нельзя связать класс с тегом slot.Есть несколько решений для этого случая:

  1. С крючком Vue mounted (это работает, но выглядит как плохая практика):

Vue.component("slots-comp", {
  template: "#slotsCompTemplate",
  mounted() {
    // each slot is an array, because you can pass a set of nodes wrap them with template tag
    // I use only first VNode for example
    this.$slots.one && this.$slots.one[0].elm.classList.add("one");
    this.$slots.two && this.$slots.two[0].elm.classList.add("two");
  }
});

new Vue({
  el: "#app",
  data: {}
})
.one {
  color: red
}

.two {
  color: blue
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
   <slots-comp>
     <div slot="one">One</div>
     <div slot="two">Two</div>
   </slots-comp>
</div>

<script type="text/x-template" id="slotsCompTemplate">
  <div>
    <slot name="one"></slot>
    <slot name="two"></slot>
  </div>
</script>
Передача необходимых классов в качестве реквизита в область действия (это не полностью инкапсулированное решение):

Vue.component("slots-comp", {
  template: "#slotsCompTemplate",
  data() {
  	return {
      classes: {
      	one: ["one"],
        two: ["two"]
      }
    }
  }
});

new Vue({
  el: "#app",
  data: {}
})
.one {
  color: red
}

.two {
  color: blue
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
   <slots-comp>
     <div slot-scope="props" :class="props.classes.one" slot="one">One</div>
     <div slot-scope="props" :class="props.classes.two" slot="two">Two</div>
   </slots-comp>
</div>

<script type="text/x-template" id="slotsCompTemplate">
  <div>
    <slot :classes="classes" name="one"></slot>
    <slot :classes="classes" name="two"></slot>
  </div>
</script>

Добавить изменения в CSS для применения стилей ко всем внутренним элементам:

.Component-Input > * 
{
    /* my rules for child elements */
}

.Component-Label> * 
{
    /* my rules for child elements */
}

Или добавить элемент-обертку для слотов с классами Component-InputInner и т. Д. И добавить аналогичные стили для них.

Надеюсь, это поможет.

...