元素变为宽度0

时间:2016-03-30 02:03:20

标签: javascript css frameworks

我想我已经成功创建了一个滑块(请执行说出你对它的评论),我能够在我的项目中实现它。问题是,当我尝试嵌套滑块时。

嵌套滑块未完全显示。显示的唯一部分是标签。内容未显示。当我检查控制台时,它显示嵌套的simSliderOuterWrapper's宽度为0。

我做错了什么,我怎样才能使其完全正常运作?

Working one: JSFiddle

function simSlider(parentElem, config) {
  /* ----------------------------------- */
  /* -------- Variable Creation -------- */
  /* ----------------------------------- */
  var currentThis = this,
    personalID = parentElem.id,
    outerWrapper = document.createElement('div'),
    innerWrapper = document.createElement('div'),
    labelWrapper = document.createElement('div'),
    tabUnderliner = document.createElement('div'),
    content = parentElem.children,
    radiosArray = [],
    contentsHeight = [],
    contentWidth = parentElem.offsetWidth,
    selectedIndex = prevIndex = 0;


  /* ---------------------------------- */
  /* ------- Configure Settings ------- */
  /* ---------------------------------- */
  if (config === undefined) config = {};
  currentThis.config = {
    // Class Names
    outerWrapperClassName: config.outerWrapperClassName,
    innerWrapperClassName: config.innerWrapperClassName,
    labelWrapperClassName: config.labelWrapperClassName,
    labelsClassName: config.labelsClassName,
    tabUnderlinerClassName: config.tabUnderlinerClassName,

    // CSS Styles
    background: config.background || 'blue',
    tabUnderlinerColor: config.tabUnderlinerColor || 'orange',
    tabTitles: config.tabTitles,
    animation: config.animation || '0.7s cubic-bezier(0.45, 0.05, 0.55, 0.95)',

    // Callbacks
    beforeInit: config.beforeInit || emptyFunction,
    endInit: config.endInit || emptyFunction,

    beforeSlide: config.beforeSlide || emptyFunction,
    slide: config.slide || emptyFunction,
    endSlide: config.endSlide || emptyFunction
  };

  function emptyFunction() {}


  /* ------------------------------------------ */
  /* ----- Handle Slider Change/Animation ----- */
  /* ------------------------------------------ */
  function changeFunction(e) {
    selectedIndex = radiosArray.indexOf(e.target);
    currentThis.config.beforeSlide(selectedIndex, content[selectedIndex]);
    var amount = '-' + contentWidth + 'px';

    content[selectedIndex].style.width = contentWidth + 'px';

    if (selectedIndex < prevIndex) {
      innerWrapper.style.transform = 'translateX(' + amount + ')';
      amount = '0';
    }

    setTimeout(function() {
      innerWrapper.style.transition = 'transform ' + currentThis.config.animation;
      innerWrapper.style.transform = 'translateX(' + amount + ')';
      outerWrapper.style.height = contentsHeight[selectedIndex] + 'px';
      tabUnderliner.style.transform = 'translateX(' + (selectedIndex * 100) + '%)';
      currentThis.config.slide(selectedIndex, content[selectedIndex]);
    });
  }

  function transitionCallback(e) {
    // http://stackoverflow.com/q/36274519/4861207
    if (e.target !== innerWrapper) return;

    innerWrapper.style.transition = 'none';
    innerWrapper.style.transform = 'translateX(0)';
    content[prevIndex].style.width = 0;

    prevIndex = selectedIndex;
    currentThis.config.endSlide(selectedIndex, content[selectedIndex]);
  }


  /* ---------------------------------- */
  /* ------ Initialize simSlider ------ */
  /* ---------------------------------- */
  function initSimSlider() {
    // beforeInit Callback
    currentThis.config.beforeInit;

    // Move contents (slides) to 'innerWrapper'
    while (content.length) {
      contentsHeight.push(content[0].offsetHeight);

      content[0].style.width = 0;
      innerWrapper.appendChild(content[0]);
    }
    content = innerWrapper.children;

    // Create and Style Tabs
    for (var i = 0; i < content.length; i++) {
      var radio = document.createElement('input'),
        label = document.createElement('label');

      manipulateAttributes(radio, {
        type: 'radio',
        checked: i === 0,
        name: 'simSlider' + personalID,
        id: 'simSlider' + personalID + i,
        class: 'simSliderTab',
        style: {
          display: 'none'
        }
      });
      manipulateAttributes(label, {
        htmlFor: 'simSlider' + personalID + i,
        html: currentThis.config.tabTitles ? currentThis.config.tabTitles[i] : i,
        style: {
          display: 'inline-block',
          width: 'calc(100% / ' + content.length + ')'
        }
      });

      if (currentThis.config.labelsClassName) label.className = currentThis.config.labelsClassName;

      radio.addEventListener('change', changeFunction);

      radiosArray.push(radio);
      labelWrapper.appendChild(label);
      parentElem.appendChild(radio);
    }

    // Add eventListener
    if ('transition' in document.documentElement.style) innerWrapper.addEventListener('transitionend', transitionCallback);

    // Add CSS Style
    content[selectedIndex].style.width = contentWidth + 'px';
    tabUnderliner.style.transition = 'transform ' + currentThis.config.animation;

    manipulateAttributes(outerWrapper, {
      className: 'simSliderOuterWrapper',
      style: {
        width: contentWidth + 'px',
        height: contentsHeight[selectedIndex] + 'px',
        transition: 'height ' + currentThis.config.animation,
        background: currentThis.config.background,
        overflow: 'hidden'
      }
    });
    manipulateAttributes(innerWrapper, {
      className: 'simSliderInnerWrapper',
      style: {
        width: (contentWidth * 2) + 'px',
        display: 'flex'
      }
    });
    manipulateAttributes(labelWrapper, {
      className: 'simSliderLabelWrapper',
      style: {
        background: 'brown'
      }
    });
    manipulateAttributes(tabUnderliner, {
      className: 'simSliderTabUnderliner',
      style: {
        background: currentThis.config.tabUnderlinerColor,
        height: '3px',
        width: 'calc(100% / ' + content.length + ')'
      }
    });

    // Add Class Names
    if (currentThis.config.outerWrapperClassName) outerWrapper.className += ' ' + currentThis.config.outerWrapperClassName;
    if (currentThis.config.innerWrapperClassName) innerWrapper.className += ' ' + currentThis.config.innerWrapperClassName;
    if (currentThis.config.labelWrapperClassName) labelWrapper.className += ' ' + currentThis.config.labelWrapperClassName;
    if (currentThis.config.tabUnderlinerClassName) tabUnderliner.className += ' ' + currentThis.config.tabUnderlinerClassName;

    // Append Elements
    outerWrapper.appendChild(innerWrapper);
    parentElem.appendChild(labelWrapper);
    parentElem.appendChild(tabUnderliner);
    parentElem.appendChild(outerWrapper);

    // endInit Callback
    currentThis.config.endInit;
  }

  /* ---------------------------------- */
  /* -------- Inital Rendering -------- */
  /* ---------------------------------- */
  initSimSlider();



  function manipulateAttributes(element, attr) {
    function recursiveSet(at, set) {
      for (var prop in at) {
        /* check if object and not a dom node or array */
        if (typeof at[prop] == 'object' && at[prop].dataset == null && at[prop][0] == null) {
          recursiveSet(at[prop], set [prop]);
        } else if (prop == 'html') {
          element.innerHTML = at[prop];
        } else {
          set [prop] = at[prop];
        }
      }
    }
    recursiveSet(attr, element);
  }

  function hasClass(ele, cls) {
    return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
  }

  function addClass(ele, cls) {
    if (!hasClass(ele, cls)) ele.className += " " + cls;
  }
}

var mySlider = document.getElementById('mySlider'),
  slider = new simSlider(mySlider);
.tabGroup {
  width: 500px;
}
.menu {
  background-color: brown;
}
.content {} #rad1:checked ~ #outerWrapper > #innerWrapper > #first,
#rad2:checked ~ #outerWrapper > #innerWrapper > #second,
#rad3:checked ~ #outerWrapper > #innerWrapper > #third {} .simSliderTabUnderliner {} .simSliderOuterWrapper {
  background-color: blue;
}
#first {
  width: 500px;
  height: 386px;
}
#second {
  width: 300px;
  height: 600px;
  background-color: lightgreen;
}
#third {
  width: 500px;
  height: 500px;
}
img {
  max-width: 100%;
  max-height: 100%;
}
<div class="tabGroup">
  <div id="mySlider">
    <div class="content" id="first">
      <img src="http://www.hdwallpapery.com/static/images/creativity_water_spray_drops_flower_rose_desktop_images_TVIdSpG.jpg" />
    </div>
    <div class="content" id="second">
      <img src="http://www.hdwallpapery.com/static/images/images_1_JbTP6rz.jpg" />
    </div>
    <div class="content" id="third">
      <img src="https://www.planwallpaper.com/static/images/Winter-Tiger-Wild-Cat-Images.jpg" />
    </div>
  </div>
</div>

Not working one: Nested Slider JSFiddle

function simSlider(parentElem, config) {
  /* ----------------------------------- */
  /* -------- Variable Creation -------- */
  /* ----------------------------------- */
  var currentThis = this,
    personalID = parentElem.id,
    outerWrapper = document.createElement('div'),
    innerWrapper = document.createElement('div'),
    labelWrapper = document.createElement('div'),
    tabUnderliner = document.createElement('div'),
    content = parentElem.children,
    radiosArray = [],
    contentsHeight = [],
    contentWidth = parentElem.offsetWidth,
    selectedIndex = prevIndex = 0;


  /* ---------------------------------- */
  /* ------- Configure Settings ------- */
  /* ---------------------------------- */
  if (config === undefined) config = {};
  currentThis.config = {
    // Class Names
    outerWrapperClassName: config.outerWrapperClassName,
    innerWrapperClassName: config.innerWrapperClassName,
    labelWrapperClassName: config.labelWrapperClassName,
    labelsClassName: config.labelsClassName,
    tabUnderlinerClassName: config.tabUnderlinerClassName,

    // CSS Styles
    background: config.background || 'blue',
    tabUnderlinerColor: config.tabUnderlinerColor || 'orange',
    tabTitles: config.tabTitles,
    animation: config.animation || '0.7s cubic-bezier(0.45, 0.05, 0.55, 0.95)',

    // Callbacks
    beforeInit: config.beforeInit || emptyFunction,
    endInit: config.endInit || emptyFunction,

    beforeSlide: config.beforeSlide || emptyFunction,
    slide: config.slide || emptyFunction,
    endSlide: config.endSlide || emptyFunction
  };

  function emptyFunction() {}


  /* ------------------------------------------ */
  /* ----- Handle Slider Change/Animation ----- */
  /* ------------------------------------------ */
  function changeFunction(e) {
    selectedIndex = radiosArray.indexOf(e.target);
    currentThis.config.beforeSlide(selectedIndex, content[selectedIndex]);
    var amount = '-' + contentWidth + 'px';

    content[selectedIndex].style.width = contentWidth + 'px';

    if (selectedIndex < prevIndex) {
      innerWrapper.style.transform = 'translateX(' + amount + ')';
      amount = '0';
    }

    setTimeout(function() {
      innerWrapper.style.transition = 'transform ' + currentThis.config.animation;
      innerWrapper.style.transform = 'translateX(' + amount + ')';
      outerWrapper.style.height = contentsHeight[selectedIndex] + 'px';
      tabUnderliner.style.transform = 'translateX(' + (selectedIndex * 100) + '%)';
      currentThis.config.slide(selectedIndex, content[selectedIndex]);
    });
  }

  function transitionCallback(e) {
    // http://stackoverflow.com/q/36274519/4861207
    if (e.target !== innerWrapper) return;

    innerWrapper.style.transition = 'none';
    innerWrapper.style.transform = 'translateX(0)';
    content[prevIndex].style.width = 0;

    prevIndex = selectedIndex;
    currentThis.config.endSlide(selectedIndex, content[selectedIndex]);
  }


  /* ---------------------------------- */
  /* ------ Initialize simSlider ------ */
  /* ---------------------------------- */
  function initSimSlider() {
    // beforeInit Callback
    currentThis.config.beforeInit;

    // Move contents (slides) to 'innerWrapper'
    while (content.length) {
      contentsHeight.push(content[0].offsetHeight);

      content[0].style.width = 0;
      innerWrapper.appendChild(content[0]);
    }
    content = innerWrapper.children;

    // Create and Style Tabs
    for (var i = 0; i < content.length; i++) {
      var radio = document.createElement('input'),
        label = document.createElement('label');

      manipulateAttributes(radio, {
        type: 'radio',
        checked: i === 0,
        name: 'simSlider' + personalID,
        id: 'simSlider' + personalID + i,
        class: 'simSliderTab',
        style: {
          display: 'none'
        }
      });
      manipulateAttributes(label, {
        htmlFor: 'simSlider' + personalID + i,
        html: currentThis.config.tabTitles ? currentThis.config.tabTitles[i] : i,
        style: {
          display: 'inline-block',
          width: 'calc(100% / ' + content.length + ')'
        }
      });

      if (currentThis.config.labelsClassName) label.className = currentThis.config.labelsClassName;

      radio.addEventListener('change', changeFunction);

      radiosArray.push(radio);
      labelWrapper.appendChild(label);
      parentElem.appendChild(radio);
    }

    // Add eventListener
    if ('transition' in document.documentElement.style) innerWrapper.addEventListener('transitionend', transitionCallback);

    // Add CSS Style
    content[selectedIndex].style.width = contentWidth + 'px';
    tabUnderliner.style.transition = 'transform ' + currentThis.config.animation;

    manipulateAttributes(outerWrapper, {
      className: 'simSliderOuterWrapper',
      style: {
        width: contentWidth + 'px',
        height: contentsHeight[selectedIndex] + 'px',
        transition: 'height ' + currentThis.config.animation,
        background: currentThis.config.background,
        overflow: 'hidden'
      }
    });
    manipulateAttributes(innerWrapper, {
      className: 'simSliderInnerWrapper',
      style: {
        width: (contentWidth * 2) + 'px',
        display: 'flex'
      }
    });
    manipulateAttributes(labelWrapper, {
      className: 'simSliderLabelWrapper',
      style: {
        background: 'brown'
      }
    });
    manipulateAttributes(tabUnderliner, {
      className: 'simSliderTabUnderliner',
      style: {
        background: currentThis.config.tabUnderlinerColor,
        height: '3px',
        width: 'calc(100% / ' + content.length + ')'
      }
    });

    // Add Class Names
    if (currentThis.config.outerWrapperClassName) outerWrapper.className += ' ' + currentThis.config.outerWrapperClassName;
    if (currentThis.config.innerWrapperClassName) innerWrapper.className += ' ' + currentThis.config.innerWrapperClassName;
    if (currentThis.config.labelWrapperClassName) labelWrapper.className += ' ' + currentThis.config.labelWrapperClassName;
    if (currentThis.config.tabUnderlinerClassName) tabUnderliner.className += ' ' + currentThis.config.tabUnderlinerClassName;

    // Append Elements
    outerWrapper.appendChild(innerWrapper);
    parentElem.appendChild(labelWrapper);
    parentElem.appendChild(tabUnderliner);
    parentElem.appendChild(outerWrapper);

    // endInit Callback
    currentThis.config.endInit;
  }

  /* ---------------------------------- */
  /* -------- Inital Rendering -------- */
  /* ---------------------------------- */
  initSimSlider();



  function manipulateAttributes(element, attr) {
    function recursiveSet(at, set) {
      for (var prop in at) {
        /* check if object and not a dom node or array */
        if (typeof at[prop] == 'object' && at[prop].dataset == null && at[prop][0] == null) {
          recursiveSet(at[prop], set [prop]);
        } else if (prop == 'html') {
          element.innerHTML = at[prop];
        } else {
          set [prop] = at[prop];
        }
      }
    }
    recursiveSet(attr, element);
  }

  function hasClass(ele, cls) {
    return ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
  }

  function addClass(ele, cls) {
    if (!hasClass(ele, cls)) ele.className += " " + cls;
  }
}

var mySlider = document.getElementById('mySlider'),
  slider = new simSlider(mySlider);

var mySlider2 = document.getElementById('second'),
  slider2 = new simSlider(mySlider2);
#mySlider {
  width: 500px;
}
.menu {
  background-color: brown;
}
.simSliderOuterWrapper {
  background-color: blue;
}
#first {
  width: 500px;
  height: 386px;
}
#second {
  width: 500px;
  height: 600px;
  background-color: lightgreen;
}
#third {
  width: 500px;
  height: 500px;
}
#first2 {
  width: 500px;
  height: 500px;
}
#second2 {
  width: 500px;
  height: 600px;
  background-color: lightgreen;
}
#third2 {
  width: 500px;
  height: 700px;
}
img {
  max-width: 100%;
  max-height: 100%;
}
<div id="mySlider">
  <div class="content" id="first">
    <img src="http://www.hdwallpapery.com/static/images/creativity_water_spray_drops_flower_rose_desktop_images_TVIdSpG.jpg" />
  </div>
  <div class="content" id="second">
    <div id="first2">
      <img src="https://rfranksblog.files.wordpress.com/2013/02/keep-calm-and-find-the-syntax-error-copy.jpg" />
    </div>
    <div id="second2">
      <img src="http://aquinashub.co.uk/wp-content/uploads/2015/04/shutterstock_computer_programming.jpg" />
    </div>
    <div id="third2">
      <img src="http://datavizion.biz/wp-content/uploads/2011/04/23689689.jpg" />
    </div>
  </div>
  <div class="content" id="third">
    <img src="https://www.planwallpaper.com/static/images/Winter-Tiger-Wild-Cat-Images.jpg" />
  </div>
</div>

2 个答案:

答案 0 :(得分:1)

第二个滑块的宽度为0的原因,第一个滑块使所有子节点(恰好是嵌套滑块)的宽度为0.

然后,内部滑块获得其子宽度(如上所述)为0.因此第二个滑块中的所有内容的宽度均为0.

对此的解决方法(这不是一个完全修复,因为它会产生另一个问题,但它确实回答了文字问题),是先初始化第二个滑块然后再初始化外部滑块。像这样:

var mySlider2 = document.getElementById('second'),
  slider2 = new simSlider(mySlider2);

var mySlider = document.getElementById('mySlider'),
  slider = new simSlider(mySlider);

答案 1 :(得分:0)

我一直在玩这个。宽度问题发生在initSimSlider的第一次运行期间,即主要滑块mySlider。除content外,子content[0] DIV的宽度更改为零。 second DIV也是content[1] mySlider,宽度为零,因此offsetWidth变为零,用于设置second'的宽度儿童DIV。 (您可以通过将内滑块放在第一个位置,使其成为content[0]来演示此功能,而不会缩小为零。)

另一种解决方案是使用scrollWidth而不是offsetWidth,这将是父DIV中最宽子项的宽度。如果content DIV的宽度相等,则不应影响布局。这消除了对首先初始化simSlider的顺序的依赖性。

这是一个JSFiddle demo,其他一些调整。 HTH。