1. 程式人生 > >八種響應式VUE動效遮罩轉場動畫開發

八種響應式VUE動效遮罩轉場動畫開發

簡介:使用前端技術,實現後臺管理介面的可供預覽視訊轉場特效,可以選擇資源後再選擇對應的特效元件進行轉場預覽,然後組合資料發向後端,在由後端推送到安卓端進行對應的視訊轉場切換。 

  1. 使用技術:vue 、stylus、jquery、svg(核心)、 javascript
  2. 目前包括八種轉場: 時鐘、百葉窗、扇形開啟、十字擴充套件、分割、覆蓋、棋盤推進、溶解
  3. 核心技術棧:原生javascript、svg中的 viewBox、preserveAspectRatio、path、clip-path、defs、use、rect、image
  4. 每個動畫具體核心實現:
  5. 時鐘動畫:( 1.sector.vue )
    1. 原理:圓的座標公式、transform座標移動、path路徑
    2. 核心程式碼:
    3. <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width='100%' height='100%' viewBox='0 0 300 200' class="svgBox">
      
        <!-- 定義外部遮罩 -->
        <clipPath id="clipPathDefinition" clipPathUnits="userSpaceOnUse" >
         <rect x='0' y='0' width='300' height='200'/>
        </clipPath>
      
        <!-- 定義扇形運動路徑 -->
        <defs>
         <path d="" stroke="#000" class="motionPath" transform="translate(150,100)" id="ring"></path>
        </defs>
      
        <!-- 定義遮罩 -->
        <clipPath id="1_SVGID_2_">
         <use xlink:href="#ring"  style="overflow:visible;"/>
        </clipPath>
      
        <!-- 背景圖片 -->
        <image xlink:href="http://img05.tooopen.com/images/20150521/tooopen_sy_125610923736.jpg" x="0" y="0" height="100%" width="100%" preserveAspectRatio="xMidYMid slice"/>  
      
        <!-- 要繪製的扇形 -->
        <g clip-path="url(#1_SVGID_2_)">
          <image xlink:href="" x="-150" y="-100" width="600" height="400" preserveAspectRatio="xMaxYMax meet" class="cp-img" />
        </g>
      
      </svg>
    4. 預覽效果:
  6. 百葉窗動畫:( 2.windows.vue )
    1. 原理:多個rect遮罩形狀運動
    2. 核心程式碼:
      <!-- 單個遮罩塊 -->
      <g>
        <defs>
          <rect id="2_SVGID_15_" y="120" width="300" height="40" class="svgRect" />
        </defs>
        <clipPath id="2_SVGID_16_">
          <use xlink:href="#2_SVGID_15_"  style="overflow:visible;"/>
        </clipPath>
        <g style="clip-path:url(#2_SVGID_16_);">
          <defs>
            <rect id="2_SVGID_17_" width="300" height="200"/>
          </defs>
          <clipPath id="2_SVGID_18_">
            <use xlink:href="#2_SVGID_17_"  style="overflow:visible;"/>
          </clipPath>
          <g transform="matrix(1 0 0 1 -3.814697e-06 0)" style="clip-path:url(#2_SVGID_18_);">
            <image style="overflow:visible;" width="1920" height="1080" :xlink:href="cimg"  transform="matrix(0.1958 0 0 0.2176 -53 -11)">
            </image>
          </g>
        </g>
      </g>
      methods:{
        initEvent(){
          var This = this;
      
          //2. 百葉窗
          $('.sbox-item-2').click(function(){
            console.log('motion 2');
            This.motion($(this),$(this).find('.svgRect'),$(this).find('.cp-img'));
          }); 
          
        },
        motion(wrapper,elem,img){
         var This = this,h = 40;
         img.attr('xlink:href',this.imgSrc);
         wrapper.addClass('sbox-item-active');
         cancelAnimationFrame(this.timer);
         
         fn();
      
         function fn(){
          
          This.timer = requestAnimationFrame(fn);
          This.$emit('getTimer',This.timer);
          h-=0.3;
          //h = parseInt(h);
      
          elem.each(function(index,ele){
            ele.setAttribute('height',h);
          });
      
          if(h < 0.5){
            h = 40;
          }
      
         }
        }
      }
    3. 預覽效果:
  7. 扇形開啟:( 3.sx.vue )
    1. 原理:兩個半圓形狀同時展開運動
    2. 核心程式碼:
      <!-- 結構 -->
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width='100%' height='100%' viewBox='0 0 300 200' class="svgBox">
      
        <!-- 定義外部遮罩 -->
        <clipPath id="clipPathDefinition" clipPathUnits="userSpaceOnUse" >
         <rect x='0' y='0' width='300' height='200'/>
        </clipPath>
        
        <!-- 定義扇形運動路徑 -->
        <defs>
         <path d="" stroke="#000" class="motionPath—1"  id="rings-1"></path>
         <path d="" stroke="#000" class="motionPath-2" id="rings-2"></path>
        </defs>
      
                              
        <!-- 定義遮罩 -->
        <clipPath id="3_SVGID_2_">
         <use xlink:href="#rings-1"  style="overflow:visible;"/>
         <use xlink:href="#rings-2"  style="overflow:visible;"/>
        </clipPath>
      
        <!-- 背景圖片 -->
        <image xlink:href="http://img05.tooopen.com/images/20150521/tooopen_sy_125610923736.jpg" x="0" y="0" height="100%" width="100%" preserveAspectRatio="xMidYMid slice"/>  
        
        <!-- 要繪製的扇形 -->
        <g clip-path="url(#3_SVGID_2_)">
          <image xlink:href="" x="-150" y="-100" width="600" height="400" preserveAspectRatio="xMaxYMax meet" class="cp-img" />
        </g>
        
       </svg>
      /* 行為 */
      sectorfn(wrapper,elem1,elem2,img){
      
        var This = this,r = 250,cx = 150,cy = 100,degrees = 0,rad = 0,srad = 0;
      
        img.attr('xlink:href',this.cimg);
        elem1.get(0).setAttribute('transform', 'translate('+150+','+100+')');
        elem2.get(0).setAttribute('transform', 'translate('+150+','+100+')');
        wrapper.addClass('sbox-item-active');
        cancelAnimationFrame(This.timer);
      
        fn();
        function fn(){
          This.timer = requestAnimationFrame(fn);
          This.$emit('getTimer',This.timer);
          
          degrees+=1;
      
          rad = degrees * (Math.PI / 180);
          srad = (degrees) * (Math.PI / 180);
          if(degrees > 180){
            degrees = 0;
          }
      
          var x1 = (Math.sin(rad) * r).toFixed(2);
          var y1 = -(Math.cos(rad) * r).toFixed(2);
      
          var x2 = -(Math.sin(srad) * r).toFixed(2);
          var y2 = -(Math.cos(srad) * r).toFixed(2);
      
          var lenghty1 = window.Number(degrees > 180);
          var lenghty2 = window.Number(degrees < 180);
      
          var descriptions1 = [ 'M', 0, -r, 'A', r, r, 0, lenghty1, 1, x1, y1, 'L',0,0,'Z'];
          var descriptions2 = [ 'M', 0, -r, 'A', r, r, 0, 0, 0, x2, y2, 'L',0,0,'Z'];
          
          elem1.attr('d', descriptions1.join(' '));
          elem2.attr('d', descriptions2.join(' '));
        }
      
      }
    3. 預覽效果:
  8. 十字擴充套件:( 4.shizi.vue )
    1. 原理:兩個rect遮罩width、height、x、y同時運動,保持位置居中
    2. 核心程式碼:
      <svg xmlns="http://www.w3.org/2000/svg" version="1.1" width='100%' height='100%' viewBox='0 0 300 200' class="svgBox">
      
        <!-- 定義外部遮罩 -->
        <clipPath id="clipPathDefinition" clipPathUnits="userSpaceOnUse" >
         <rect x='0' y='0' width='300' height='200'/>
        </clipPath>
        
        <!-- 定義扇形運動路徑 -->
        <defs>
         <rect x='0' y='0' width='300' height='200' id="rects-1"/>
         <rect x='0' y='0' width='300' height='200' id="rects-2"/>
        </defs>
        
        <!-- 定義遮罩 -->
        <clipPath id="4_SVGID_2_">
         <use xlink:href="#rects-1"  style="overflow:visible;"/>
         <use xlink:href="#rects-2"  style="overflow:visible;"/>
        </clipPath>
      
        <!-- 背景圖片 -->
        <image xlink:href="http://img05.tooopen.com/images/20150521/tooopen_sy_125610923736.jpg" x="0" y="0" height="100%" width="100%" preserveAspectRatio="xMidYMid slice"/>  
        
        <!-- 要繪製的扇形 -->
        <g clip-path="url(#4_SVGID_2_)">
          <image xlink:href="" x="0" y="0" width="300" height="200" preserveAspectRatio="xMaxYMax slice" class="cp-img" />
        </g>
        
       </svg>
    3. 預覽效果:
  9. 分割動畫:( 5.fenge.vue )
    1. 原理:橫向rect遮罩width、height、x、y同時運動,保持位置居中 (其結構與上類似)
    2. 核心程式碼:
      //分割動畫
      sectorfn(wrapper,elem1,img){
      
        var This = this,w = 300,x = 0,width = 300;
      
        img.attr('xlink:href',this.cimg);
        wrapper.addClass('sbox-item-active');
        cancelAnimationFrame(This.timer);
      
        fn();
        function fn(){
          This.timer = requestAnimationFrame(fn);
          This.$emit('getTimer',This.timer);
          
          w-=1.5;
          x = (width-w)/2;
      
          if(w <= 0){
            w = 300;
            x = 0;
          }
          
          if(w > 0){
            elem1.attr({x:x,'width':w});
          }
          
        }
      
      }
    3. 預覽效果:
  10. 覆蓋動畫:( 6.cover.vue )
    1. 原理:rect單個橫向移動
    2. 核心程式碼:(其結構行為與上類似)
    3. 預覽效果:
  11. 棋盤推進:( 7.chess.vue )
    1. 原理:DOM動畫、動態排列位置,每個位置的盒子背景圖合成一個完整的背景圖(也可以用svg中的pattern來做 ,但生成的標籤太多,沒有backgroud-image來得快)
    2. 核心程式碼:
      methods:{
        initEvent(){
          var This = this;
      
          $('.sbox-item-7').click(function(){
      
            This.sectorfn($(this),$(this).find('.cb-box'));
          });
          
        },
        initDraw(){
          
          var row = 8;
          var col = 5;
          var width = $('.chess-box').width();
          var height = $('.chess-box').height();
          var rw = Math.floor(width/6);
          var rh = Math.floor(height/col);
          var crw = Math.floor(width/row);
          var cstr = '';
          var rstr = '';
          var astr = '';
      
          for(var i=0;i<col;i++){
            var cstr = `<div class="cb-row-box" style="width:${rw*row}px;height:${rh}px;top:${rh*i}px;left:${ i%2==0 ? -parseInt(rw/2) : 0 }px;">`;
            rstr = '';
            for(var j=0;j<row;j++){
              rstr += `<div class="cb-box" style="width:${rw}px;height:${rh}px;left:${rw*j}px;top:0px; background-image:url('http://hiphotos.baidu.com/image/w=730;crop=0,0,730,405/sign=8630d99f963df8dca63d8d92fd2a11f9/0824ab18972bd407c305049572899e510eb3099c.jpg');background-size:${width*8/6}px ${height*8/6}px;background-position:${ i%2==0 ? -rw*j : -rw*j-parseInt(rw/2) }px ${-rh*i}px;" data-row="${i} "></div>`;
            }
            cstr = cstr + rstr + '</div>';
            astr += cstr;
          }
      
          $('#chess-box').html(astr);
      
        },
        //1. 互動
        sectorfn(wrapper,elem){
      
          var This = this,row = 8,col = 5,width = $('.chess-box').width(),rw = width/(row-2),w1 = 0,w2 = 0,count = 0;
          elem.each(function(index,ele){
            $(ele).css({
              'width': 0,
              'background-image': "url("+This.tiimg+")"
            });
          });
          wrapper.addClass('sbox-item-active');
          cancelAnimationFrame(This.timer);
      
          fn();
          function fn(){
            This.timer = requestAnimationFrame(fn);
            This.$emit('getTimer',This.timer);
            count+=0.5;
            if(count > 20){
              w2+=0.6;
            }
            w1+=0.6;
            
            elem.each(function(index,ele){
              if(ele.dataset.row % 2 == 0){
                 $(ele).css({
                   'width': w1
                 });
              }else{
                $(ele).css({
                   'width': w2
                 });
              }  
      
            });
      
            if(w1 > rw){
              w1 = rw;
            }
      
            if(w2 > rw){
              w2 = rw;
              cancelAnimationFrame(This.timer);
              return;
            }
            
          }
      
        }
      }
    3. 預覽效果:
  12. 溶解:( 8.diss.vue )
    1. 原理:同上棋盤推進、只是需要把每個box的位置讓在陣列中打亂後,逐個出現即可
    2. 核心程式碼:(其結構與行為和上面的棋盤推進效果類似)
      methods:{
        initEvent(){
          var This = this;
      
          $('.sbox-item-8').click(function(){
      
            This.sectorfn($(this),$(this).find('.cb-box'));
          });
          
        },
        initDraw(){
          
          var row = 8;
          var col = 7;
          var width = $('.diss-box').width();
          var height = $('.diss-box').height();
          var rw = Math.floor(width/6);
          var rh = Math.floor(height/col);
          console.log(rh)
          var crw = Math.floor(width/row);
          var cstr = '';
          var rstr = '';
          var astr = '';
          var cindex = 0;
      
          for(var i=0;i<col;i++){
            var cstr = `<div class="cb-row-box" style="width:${rw*row}px;height:${rh}px;top:${rh*i}px;left:${ i%2==0 ? -parseInt(rw/2) : 0 }px;">`;
            rstr = '';
            for(var j=0;j<row;j++){
              cindex++;
              rstr += `<div class="cb-box" style="width:${rw}px;height:${rh}px;left:${rw*j}px; top:0px; opacity:0; background-image:url('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1532844894449&di=2a046505cf28d75564baa61a9adc7d52&imgtype=0&src=http%3A%2F%2Fold.bz55.com%2Fuploads%2Fallimg%2F150422%2F139-1504221GZ3.jpg');background-size:${width*8/6}px ${height*8/6}px;background-position:${ i%2==0 ? -rw*j : -rw*j-parseInt(rw/2) }px ${-rh*i}px;" data-row="${i} data-index="${cindex}" ></div>`;
            }
            cstr = cstr + rstr + '</div>';
            astr += cstr;
          }
      
          $('#diss-box').html(astr);
      
        },
        //1. 互動
        sectorfn(wrapper,elem){
      
          var This = this,row = 8,col = 7,width = $('.chess-box').width(),rw = width/(row-2),w1 = 0,w2 = 0,count = 0,ci = 0,len = row*col,indexArr = [];
          
          //get 當前圖片
          elem.each(function(index,ele){
            $(ele).css({
              'background-image': "url("+This.tiimg+")",
              'opacity': 0,
              'transition': 'ease .5s'
            });
          });
          
          //打亂index陣列陣列順序
          for(var i=0;i<=len;i++){
            indexArr.push(i);
          }
          indexArr.sort(function(a,b){
            return Math.random()-0.5;
          });
      
          //新增點選後樣式
          wrapper.addClass('sbox-item-active');
          cancelAnimationFrame(This.timer);
      
          fn();
          function fn(){
            This.timer = requestAnimationFrame(fn);
            This.$emit('getTimer',This.timer);
            
            count+=0.5;
      
            if(count % 2 == 0){
              
              elem.eq(indexArr[ci]).css('opacity',1);
              elem.eq(indexArr[ci+1]).css('opacity',1);
      
              ci+=2;
            }
      
            if(ci > indexArr.length+3){
              cancelAnimationFrame(This.timer);
              return;
            }
            
          }
      
        }
      }
    3. 預覽效果:

14. 彈性佈局、結合viewBox和圖片的preserveAspectRatio屬性來滿足各尺寸相容性,後續需要結合其他元件進行圖片資源、動畫狀態等通訊

15. 完成!