Vue.js,如何从父级 add/modify css class inside slot

Vue.js, how to add/modify css class inside slot from parent

我一直在尝试破解这个简单的逻辑但失败了,我真的需要你的帮助。 那么我想要实现的是添加或修改插槽内的 class 名称。

// Parent component
<div class="col">
  <slider>
    <slide v-for="intro in compOpts.blockIntro">
      <block-intro :compOpts="{ props: { wrapper: true, bg: false } }">
        <p v-html="intro.title"></p>
        <div slot="content" v-html="intro.content" class="blockIntro__content"></div>
      </block-intro>
    </slide>
  </slider>
</div>

// Slider component
<div class="slider__container">
  <slot></slot>
</div>

// Slide component
<div>
 <slot></slot>
</div>

// BlockIntro component
<div class="col--h100" :class="{ 'bg--darkDark': compOpts.props.bg, 'col': !compOpts.props.wrapper }"> << --- Add visible class here from Slider component
<div class="col col__blockIntro" :class="{ 'col__blockIntro--spaced': compOpts.props.spaced }">
  <div class="col col__blockIntro__introQuote">
    <slot></slot>
  </div>
  <slot name="content"></slot>
</div>

<div class="col--h100" :class="{ 'bg--darkDark': compOpts.props.bg, 'col': !compOpts.props.wrapper }"> << --- Add visible class here from Slider component

组件层次结构

-> Slider
--> Slide
---> BlockIntro

我的 Slot 组件为我提供了 BlockIntro 组件模板,div.col--h100 是 Slider 中的 first/parent 子元素。现在,我正在尝试从 Slider 组件向 div.col--h100 添加一个可见的 class。我使用 $slots 安慰了 Vnode 但无法更改 $slots.$elm.className

中的值

请帮忙。

P.S。本人Vue新手,结构有误还望见谅

P.S。我想我无法清楚地解释自己。所以我期待实现的是在Vue2

中实现如下轮播

https://codepen.io/smitray/pen/qjXGZp

这是您链接到 Vue 的幻灯片的首次转换。请注意,我使用作用域槽来传递槽中包含的方法组件。希望您可以使用它来获得一些想法。

可以立即进行的一些改进

  • 使用 Vue 转换

console.clear()

const slideData = [
  {
    url:"https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/waterfall-free-stock-photo-244915.jpg",
    backgroundColor:"green"
  },
  {
    url:"https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/free-stock-photos-1.jpg",
    backgroundColor:"orange"
  },
  {
    url: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/snowy-winter-vignette-bokeh-night-snow-falling-free-stock-photo.jpg",
    backgroundColor: "red"
  }

]

Vue.component("slideshow",{
  template: `
    <div class="container">
      <ul id="slides">
        <slot name="slides" :register="registerSlide" :active="activeSlide">
          {{registerSlide}}
        </slot>
      </ul>
      <slot :pause="pause" 
            :play="playSlideshow" 
            :next="nextSlide"
            :prev="previousSlide"
            name="controls">
      </slot>
    </div>
  `,
  data(){
    return {
      slides:[],
      currentSlide: 0,
      playing: false,
      slideInterval: null,
      controls: null,
      activeSlide: null
    }
  },
  methods:{
    pause(){
      clearInterval(this.slideInterval)
    },
    registerSlide(slide){
      this.slides.push(slide)
    },
    goToSlide(n){
      this.currentSlide = (n+this.slides.length)%this.slides.length;
      this.activeSlide = this.slides[this.currentSlide]
    },
    nextSlide(){
      this.goToSlide(this.currentSlide+1);
    },
    previousSlide(){
      this.goToSlide(this.currentSlide-1);
    },
    playSlideshow(){
      this.playing = true;
      this.slideInterval = setInterval(this.nextSlide,2000);
    }

  },
  mounted(){
    if (this.slides.length > 0){
      this.activeSlide = this.slides[this.currentSlide]
      this.playSlideshow()
    }
  }
})

Vue.component("slide",{
  props:["slide", "register", "active"],
  template:`
    <li class="slide" :class="slideClass" :style="slideStyle"></li>
  `,
  data(){
    return {
      showing: false,
      isSlide: true
    }
  },
  computed:{
    slideClass(){
      return {
        showing: this.active === this,
      }
    },
    slideStyle(){
      return {
        'background-image': `url(${this.slide.url})`,
        'background-color': this.slide.backgroundColor     
      }
    }
  },
  mounted(){
    console.log(this.$props)
    this.register(this)
  }
})

Vue.component("slide-controls", {
  props:["pause", "play", "next", "prev"],
  template:`
  <div class="buttons" style="top: 10px; left: 10px">
    <button @click="prev" class="controls" id="previous">&lt;</button>
    <button @click="onPause" class="controls" id="pause">{{paused ? '&#9658;' : '&#10074;&#10074;'}}</button>
    <button @click="next" class="controls" id="next">&gt;</button>
  </div>
  `,
  data(){
    return {
      isControls: true,
      paused: false
    }
  },
  methods:{
    onPause(){
      this.paused = !this.paused
      if (this.paused)
        this.pause()
      else
        this.play()
    }
  }
})


new Vue({
  el: "#app",
  data:{
    slides: slideData,
  }
})
/*
essential styles:
these make the slideshow work
*/
#slides{
 position: relative;
 height: 300px;
 padding: 0px;
 margin: 0px;
 list-style-type: none;
}

.slide{
 position: absolute;
 left: 0px;
 top: 0px;
 width: 100%;
 height: 100%;
 opacity: 0;
 z-index: 1;

 -webkit-transition: opacity 1s;
 -moz-transition: opacity 1s;
 -o-transition: opacity 1s;
 transition: opacity 1s;
}

.showing{
 opacity: 1;
 z-index: 2;
}




/*
non-essential styles:
just for appearance; change whatever you want
*/

.slide{
 font-size: 40px;
 padding: 40px;
 box-sizing: border-box;
 background: #333;
 color: #fff;
  
  background-size: cover;
}



.controls{
  background: #333;
  color: #fff;
  border: none;
  padding: 20px 0px;
  font-size: 20px;
  cursor: pointer;
  border: 2px solid #fff;
  margin: 10px 0px 0px 10px;
  width: 70px;
}

.controls:hover,
.controls:focus{
  background: #eee;
  color: #333;
}

.container{
  position: relative;
}

.buttons{
  position: absolute;
  left: 0px;
  top: 0px;
  z-index: 10;
  font-size: 0px;
}
<script src="https://unpkg.com/vue@2.2.6/dist/vue.js"></script>
<div id="app">
  <slideshow>
    <template slot="slides" scope="props">
      <slide v-for="slide in slides" 
             :slide="slide"
             v-bind="props">
      </slide>
    </template>
    <template slot="controls" scope="props">
      <slide-controls v-bind="props"></slide-controls>
    </template>
  </slideshow>
</div>