【问题标题】:Vue.js, how to add/modify css class inside slot from parentVue.js,如何从父级插槽内添加/修改 CSS 类
【发布时间】:2017-12-01 03:37:16
【问题描述】:

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

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

请帮忙。

附:我是Vue的新手,如果我的结构有问题请见谅

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

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

【问题讨论】:

    标签: vue.js vuejs2 vue-component vuex


    【解决方案1】:

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

    【讨论】:

    • 那么,考虑到codepen的链接,我怎样才能真正实现这个概念。老实说,这对我来说不是很清楚。
    • @SmitRay 你在 Vue 中有当前版本的笔吗?您在哪里问如何将值传递给插槽?我假设您有一些事情可以问这个特定的问题。
    • 在槽中传递值不是问题。我需要的是在组件模板内的元素上添加一个 css 类。
    • @SmitRay 已更新。
    • 这太棒了。正是我需要的。如果可以的话,我会为这个解决方案投票 10 次。非常感谢兄弟。
    猜你喜欢
    • 2017-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 2021-02-27
    • 2017-05-05
    • 1970-01-01
    • 2015-05-20
    相关资源
    最近更新 更多