八种响应式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. 完成!

猜你喜欢

转载自blog.csdn.net/WU5229485/article/details/81270676
今日推荐