Vue.js,如何从父级添加/修改插槽内的css类

时间:2017-06-27 22:55:08

标签: vue.js vuejs2 vue-component vuex

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

// 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中的第一个/父子元素。现在我正在尝试将一个可见类添加到div.col - 来自Slider组件的h100。我使用$ slots安装了Vnode,但无法更改$ slots中的值。$ elm.className

请帮忙。

P.S。我是Vue的新手,所以如果我的结构不对,请原谅我

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

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

1 个答案:

答案 0 :(得分:3)

这是您链接到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>