制造图片倾斜(tilt)结果

原文来自:

http://tympanus.net/codrops/2015/05/28/image-tilt-effect/

所谓的倾斜结果,我也不知怎样用言语形貌,那就直接看Demo啦,下面我们会对这个结果的完成道理逐渐剖析:
http://codepen.io/CodingMonkeyzh/pen/jPYNyr

文档组织

对一个图片增加该结果,起首,我们须要一个具有宽高的容器。DOM 组织异常简朴。

<div class="container">
  <img class="tilt-effect" src="http://placehold.it/500x300" alt="" />
</div>

上面这段组织经由剧本处置惩罚以后,会被替换成下面的组织:

<div class="container">
  <div class="tilt">
    <div class="tilt__back" style="background-image: url(http://placehold.it/500x300);"></div>
    <div class="tilt__front" style="opacity: 0.7; -webkit-transform: perspective(1000px) translate3d(0px, 0px, 0px) rotate3d(1, 1, 1, 0deg); transform: perspective(1000px) translate3d(0px, 0px, 0px) rotate3d(1, 1, 1, 0deg); background-image: url(http://placehold.it/500x300);"></div>
    <div class="tilt__front" style="opacity: 0.7; -webkit-transform: perspective(1000px) translate3d(0px, 0px, 0px) rotate3d(1, 1, 1, 0deg); transform: perspective(1000px) translate3d(0px, 0px, 0px) rotate3d(1, 1, 1, 0deg); background-image: url(http://placehold.it/500x300);"></div>
  </div>
</div>

剧本剖析

我们利用了filtfx.js这个插件对上面的图片举行处置惩罚, 来完成倾斜结果。我在本来的代码中加入了一些解释,来协助我们明白。下面我们对该插件的中心代码举行剖析。

function TiltFx(el, options) {
  this.el = el;
  this.options = extend({}, this.options);
  extend(this.options, options);
  this._init();
  this._initEvents();
}

这是组织函数,假如我们的文档中,加入了上面的插件,那末插件会遍历文档中具有tilt-effetimg元素,来挪用组织函数TiltFx()

function init() {
  // 遍历一切具有‘title-effect’类的img元素
  [].slice.call(document.querySelectorAll('img.tilt-effect')).forEach(function(img) {
    new TiltFx(img, JSON.parse(img.getAttribute('data-tilt-options')));
  });
}

TiltFx()具有一个原型属性,两个原型要领。原型属性设置了一些默许的参数用于挪用:

/**
 * 默许参数
 */
TiltFx.prototype.options = {
  extraImgs: 2, // 分外的辅佐图片数目
  opacity: 0.7,
  bgfixed: true, // 底图是不是牢固
  movement: {    // 这是一些用于挪动的参数
    perspective: 1000,
    translateX: -10,
    translateY: -10, 
    translateZ: 20,
    rotateX: 2,
    rotateY: 2,
    rotateZ: 0
  }
}

第一个原型要领是_init(),用于初始化DOM结点,天生我们的目的DOM结点:

TiltFx.prototype._init = function() {
  this.tiltWrapper = document.createElement('div');
  this.tiltWrapper.className = 'tilt';

  // main image element.
  this.tiltImgBack = document.createElement('div');
  this.tiltImgBack.className = 'tilt__back';
  this.tiltImgBack.style.backgroundImage = 'url(' + this.el.src + ')';
  this.tiltWrapper.appendChild(this.tiltImgBack);

  // image elements limit.
  if (this.options.extraImgs < 1) {
    this.options.extraImgs = 1;
  } else if (this.options.extraImgs > 5) {
    this.options.extraImgs = 5;
  }

  if (!this.options.movement.perspective) {
    this.options.movement.perspective = 0;
  }

  // add the extra image elements.
  this.imgElems = [];
  for (var i = 0; i < this.options.extraImgs; ++i) {
    var el = document.createElement('div');
    el.className = 'tilt__front';
    el.style.backgroundImage = 'url(' + this.el.src + ')';
    el.style.opacity = this.options.opacity;
    this.tiltWrapper.appendChild(el);
    this.imgElems.push(el);
  }

  if (!this.options.bgfixed) {
    this.imgElems.push(this.tiltImgBack);
    ++this.options.extraImgs;
  }

  // add it to the DOM and remove original img element.
  this.el.parentNode.insertBefore(this.tiltWrapper, this.el);
  this.el.parentNode.removeChild(this.el);

  // tiltWrapper properties: width/height/left/top
  this.view = {
    width: this.tiltWrapper.offsetWidth,
    height: this.tiltWrapper.offsetHeight
  };
};

别的一个原型体式格局是用于监听鼠标事宜之类的:

TiltFx.prototype._initEvents = function() {
  var self = this,
    moveOpts = self.options.movement;

  // mousemove event..
  this.tiltWrapper.addEventListener('mousemove', function(ev) {
    requestAnimationFrame(function() {
      // mouse position relative to the document.
      var mousepos = getMousePos(ev),
        // document scrolls.
        docScrolls = {
          left: document.body.scrollLeft + document.documentElement.scrollLeft,
          top: document.body.scrollTop + document.documentElement.scrollTop
        },
        bounds = self.tiltWrapper.getBoundingClientRect(),
        // mouse position relative to the main element (tiltWrapper).
        relmousepos = {
          x: mousepos.x - bounds.left - docScrolls.left,
          y: mousepos.y - bounds.top - docScrolls.top
        };

      // configure the movement for each image element.
      for (var i = 0, len = self.imgElems.length; i < len; ++i) {
        var el = self.imgElems[i],
          rotX = moveOpts.rotateX ? 2 * ((i + 1) * moveOpts.rotateX / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.rotateX / self.options.extraImgs) : 0,
          rotY = moveOpts.rotateY ? 2 * ((i + 1) * moveOpts.rotateY / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateY / self.options.extraImgs) : 0,
          rotZ = moveOpts.rotateZ ? 2 * ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) : 0,
          transX = moveOpts.translateX ? 2 * ((i + 1) * moveOpts.translateX / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.translateX / self.options.extraImgs) : 0,
          transY = moveOpts.translateY ? 2 * ((i + 1) * moveOpts.translateY / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateY / self.options.extraImgs) : 0,
          transZ = moveOpts.translateZ ? 2 * ((i + 1) * moveOpts.translateZ / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateZ / self.options.extraImgs) : 0;

        el.style.WebkitTransform = 'perspective(' + moveOpts.perspective + 'px) translate3d(' + transX + 'px,' + transY + 'px,' + transZ + 'px) rotate3d(1,0,0,' + rotX + 'deg) rotate3d(0,1,0,' + rotY + 'deg) rotate3d(0,0,1,' + rotZ + 'deg)';
        el.style.transform = 'perspective(' + moveOpts.perspective + 'px) translate3d(' + transX + 'px,' + transY + 'px,' + transZ + 'px) rotate3d(1,0,0,' + rotX + 'deg) rotate3d(0,1,0,' + rotY + 'deg) rotate3d(0,0,1,' + rotZ + 'deg)';
      }
    });
  });

  // reset all when mouse leaves the main wrapper.
  this.tiltWrapper.addEventListener('mouseleave', function(ev) {
    setTimeout(function() {
      for (var i = 0, len = self.imgElems.length; i < len; ++i) {
        var el = self.imgElems[i];
        el.style.WebkitTransform = 'perspective(' + moveOpts.perspective + 'px) translate3d(0,0,0) rotate3d(1,1,1,0deg)';
        el.style.transform = 'perspective(' + moveOpts.perspective + 'px) translate3d(0,0,0) rotate3d(1,1,1,0deg)';
      }
    }, 60);

  });

  // window resize
  window.addEventListener('resize', throttle(function(ev) {
    // recalculate tiltWrapper properties: width/height/left/top
    self.view = {
      width: self.tiltWrapper.offsetWidth,
      height: self.tiltWrapper.offsetHeight
    };
  }, 50));
};

我们能够看到,监听mousemove的事宜处置惩罚函数中的盘算比较复杂,症结的部份就是在这里:

        var el = self.imgElems[i],
          rotX = moveOpts.rotateX ? 2 * ((i + 1) * moveOpts.rotateX / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.rotateX / self.options.extraImgs) : 0,
          rotY = moveOpts.rotateY ? 2 * ((i + 1) * moveOpts.rotateY / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateY / self.options.extraImgs) : 0,
          rotZ = moveOpts.rotateZ ? 2 * ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.rotateZ / self.options.extraImgs) : 0,
          transX = moveOpts.translateX ? 2 * ((i + 1) * moveOpts.translateX / self.options.extraImgs) / self.view.width * relmousepos.x - ((i + 1) * moveOpts.translateX / self.options.extraImgs) : 0,
          transY = moveOpts.translateY ? 2 * ((i + 1) * moveOpts.translateY / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateY / self.options.extraImgs) : 0,
          transZ = moveOpts.translateZ ? 2 * ((i + 1) * moveOpts.translateZ / self.options.extraImgs) / self.view.height * relmousepos.y - ((i + 1) * moveOpts.translateZ / self.options.extraImgs) : 0;

        el.style.WebkitTransform = 'perspective(' + moveOpts.perspective + 'px) translate3d(' + transX + 'px,' + transY + 'px,' + transZ + 'px) rotate3d(1,0,0,' + rotX + 'deg) rotate3d(0,1,0,' + rotY + 'deg) rotate3d(0,0,1,' + rotZ + 'deg)';
        el.style.transform = 'perspective(' + moveOpts.perspective + 'px) translate3d(' + transX + 'px,' + transY + 'px,' + transZ + 'px) rotate3d(1,0,0,' + rotX + 'deg) rotate3d(0,1,0,' + rotY + 'deg) rotate3d(0,0,1,' + rotZ + 'deg)';

这里我们依据鼠标的位置,盘算出了各个图层对应的偏移量和扭转角度,然后对它们举行变更即可。
末了mouseleave以后,我们再把个个图层恢复到初始位置就好了。

Demo:http://codepen.io/CodingMonkeyzh/pen/jPYNyr

    原文作者:MockingBird
    原文地址: https://segmentfault.com/a/1190000002936381
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞