微信小程序模拟ppt效果的公司介绍分步骤流程(主要使用Animation)。使用时间轴介绍以及swiper

思路:

参考抖音上滑下滑翻页实现介绍。
封装watch方法监听翻页并分步骤进入动画。
使用左滑右滑、渐变、计数、文本框打字输入动画。

Step1:

上滑下滑
//wxml
<view class="container container-fill">
 <view class="scroll-fullpage" bindtouchstart="scrollTouchstart" bindtouchmove="scrollTouchmove" bindtouchend="scrollTouchend" style="transform:translateY(-{{scrollindex*100}}%);margin-top: {{margintop}}px">
 <view class="section section01 {{scrollindex==0?'active':''}}" style="background: #3399FF;">
  <text class="section-maintitle">页面1</text>
  <text class="section-subtitle">我的页面”1</text>
 </view>
 <view class="section section02 {{scrollindex==1?'active':''}}" style="background: #00CC66;">
  <text class="section-maintitle">页面2</text>
  <text class="section-subtitle">我的页面”2</text>
 </view>
 <view class="section section03 {{scrollindex==2?'active':''}}" style="background: #33CCCC;">
  <text class="section-maintitle">页面3</text>
  <text class="section-subtitle">我的页面”3</text>
 </view>
 <view class="section section04 {{scrollindex==3?'active':''}}" style="background: #6699FF;">
  <text class="section-maintitle">页面4</text>
  <text class="section-subtitle">我的页面”4</text>
 </view>
 <view class="section section05 {{scrollindex==4?'active':''}}" style="background: #9966FF;">
  <text class="section-maintitle">无缝对接双创服5</text>
  <text class="section-subtitle">我的页面”5</text>
 </view>
 </view>
</view>
//js
Page({
 data: {
  scrollindex:0, //当前页面的索引值
  totalnum:5, //总共页面数
  starty:0, //开始的位置x
  endy:0, //结束的位置y
  critical: 100, //触发翻页的临界值
  margintop:0, //滑动下拉距离
 },
 onLoad: function () {
 },
 scrollTouchstart:function(e){
  let py = e.touches[0].pageY;
  this.setData({
   starty: py
  })
 },
 scrollTouchmove:function(e){
  let py = e.touches[0].pageY;
  let d = this.data;
  this.setData({
   endy: py,
  })
  //400判断翻页的边界
  if(py-d.starty<400 && py-d.starty>-400){  
   this.setData({
    margintop: py - d.starty
   })
  }
 },
 scrollTouchend:function(e){
  let d = this.data;
  if(d.endy-d.starty >400 && d.scrollindex>0){
   this.setData({
    scrollindex: d.scrollindex-1
   })
  }else if(d.endy-d.starty <-400 && d.scrollindex<this.data.totalnum-1){
   this.setData({
    scrollindex: d.scrollindex+1
   })
  }
  this.setData({
    starty:0,
    endy:0,
    margintop:0
  })
 },
})
//css
.container-fill{
 height: 100%;
 overflow: hidden;
}
.scroll-fullpage{
 height: 100vh;
 transition: all 0.3s;
}
.section{
 height: 100vh;
}
.section-maintitle{
 display: block;
 text-align: center;
 font-size: 50rpx;
 color: #fff;
 font-weight: bold;
 letter-spacing: 10rpx;
 padding-top: 140rpx;
}
.section-subtitle{
 display: block;
 text-align: center;
 font-size: 40rpx;
 color: #fff;
 font-weight: bold;
 letter-spacing: 10rpx;
}
.active .section-maintitle,
.active .section-subtitle{
 animation: mymove 0.8s;
}
@keyframes mymove{
 from {
 transform: translateY(-400rpx) scale(0.5) rotateY(90deg);
 }
 to {
 transform: translateY(0) scale(1) rotateY(0);
 }
}

Step2

//封装watch方法
function observe(obj, key, watchFun, deep, page) {
  let val = obj[key];

  if (val != null && typeof val === "object" && deep) {
    Object.keys(val).forEach((item) => {
      observe(val, item, watchFun, deep, page);
    });
  }

  Object.defineProperty(obj, key, {
    configurable: true,
    enumerable: true,
    set: function(value) {
      watchFun.call(page, value, val);
      val = value;

      if (deep) {
        observe(obj, key, watchFun, deep, page);
      }
    },
    get: function() {
      return val;
    }
  });
}

export function setWatcher(page) {
  let data = page.data;
  let watch = page.watch;

  Object.keys(watch).forEach((item) => {
    let targetData = data;
    let keys = item.split(".");

    for (let i = 0; i < keys.length - 1; i++) {
      targetData = targetData[keys[i]];
    }

    let targetKey = keys[keys.length - 1];

    let watchFun = watch[item].handler || watch[item];

    let deep = watch[item].deep;
    observe(targetData, targetKey, watchFun, deep, page);
  });
}

Step3

//监听翻页,以此触发动画特效
import * as watch from "../../utils/watch.js";
 watch:{
    scrollindex:function(newval,oldval){
          console.log(newval); // name改变时,调用该方法输出新值。
          if(newval===0){
          //第一页
            this.textpage()
          } else if (newval === 1){
          }
      }
  },

css3动画

// 不需要动作的动画使用css3动画:
/* 渐变-背景图 */
 @keyframes menuAwave {
  0% {
    opacity: 0;
  }
  10%{
    opacity: 0.1;
  }
  50%{
    opacity: 0.5;
  }
  100% {
    opacity: 1;
  }
}
 .active .bg1{
   animation: menuAwave 1s ; 
 }

js动画-计数器

/**
 * 数字滚动
 * 
 * @param {String} target   滚动对象
 * @param {Number} endVal   滚动结束时的数字
 * @param {Object} options  配置
 * @param {Object} context  微信小程序当前this对象
 * 
 * forked from https://github.com/inorganik/CountUp.js
 */
class WxCountUp {
  constructor(target = '', endVal = 0, options = {}, context = {}) {
    var _this = this
    this.target = target;
    this.endVal = endVal;
    this.options = options;
    this.context = context;
    this.version = '1.0.0';
    this.defaults = {
      startVal: 0,
      decimalPlaces: 0,
      duration: 1,
      useEasing: true,
      useGrouping: true,
      smartEasingThreshold: 999,
      smartEasingAmount: 333,
      separator: ',',
      decimal: '.',
      prefix: '',
      suffix: ''
    }
    this.finalEndVal = null;
    this.useEasing = true;
    this.countDown = false;
    this.error = '';
    this.startVal = 0;
    this.paused = true;
    this.count = function (timestamp) {
      if (!_this.startTime) {
          _this.startTime = timestamp;
      }
      var progress = timestamp - _this.startTime;
      _this.remaining = _this.duration - progress;
      // to ease or not to ease
      if (_this.useEasing) {
          if (_this.countDown) {
              _this.frameVal = _this.startVal - _this.easingFn(progress, 0, _this.startVal - _this.endVal, _this.duration);
          }
          else {
              _this.frameVal = _this.easingFn(progress, _this.startVal, _this.endVal - _this.startVal, _this.duration);
          }
      }
      else {
          if (_this.countDown) {
              _this.frameVal = _this.startVal - ((_this.startVal - _this.endVal) * (progress / _this.duration));
          }
          else {
              _this.frameVal = _this.startVal + (_this.endVal - _this.startVal) * (progress / _this.duration);
          }
      }
      // don't go past endVal since progress can exceed duration in the last frame
      if (_this.countDown) {
          _this.frameVal = (_this.frameVal < _this.endVal) ? _this.endVal : _this.frameVal;
      }
      else {
          _this.frameVal = (_this.frameVal > _this.endVal) ? _this.endVal : _this.frameVal;
      }
      // decimal
      _this.frameVal = Math.round(_this.frameVal * _this.decimalMult) / _this.decimalMult;
      // format and print value
      _this.printValue(_this.frameVal);
      // whether to continue
      if (progress < _this.duration) {
          _this.rAF = doAnimationFrame(_this.count);
      }
      else if (_this.finalEndVal !== null) {
          // smart easing
          _this.update(_this.finalEndVal);
      }
      else {
          if (_this.callback) {
              _this.callback();
          }
      }
    };
    // 默认格式和缓和函数
    this.formatNumber = function (num) {
        var neg = (num < 0) ? '-' : '';
        var result, x, x1, x2, x3;
        result = Math.abs(num).toFixed(_this.options.decimalPlaces);
        result += '';
        x = result.split('.');
        x1 = x[0];
        x2 = x.length > 1 ? _this.options.decimal + x[1] : '';
        if (_this.options.useGrouping) {
            x3 = '';
            for (var i = 0, len = x1.length; i < len; ++i) {
                if (i !== 0 && (i % 3) === 0) {
                    x3 = _this.options.separator + x3;
                }
                x3 = x1[len - i - 1] + x3;
            }
            x1 = x3;
        }
        // optional numeral substitution
        if (_this.options.numerals && _this.options.numerals.length) {
            x1 = x1.replace(/[0-9]/g, function (w) { return _this.options.numerals[+w]; });
            x2 = x2.replace(/[0-9]/g, function (w) { return _this.options.numerals[+w]; });
        }
        return neg + _this.options.prefix + x1 + x2 + _this.options.suffix;
    };
    this.easeOutExpo = function (t, b, c, d) {
      return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
    };
    this.options = __assign({}, this.defaults, options);
    this.formattingFn = (this.options.formattingFn) ? this.options.formattingFn : this.formatNumber;
    this.easingFn = (this.options.easingFn) ? this.options.easingFn : this.easeOutExpo;
    this.startVal = this.validateValue(this.options.startVal);
    this.frameVal = this.startVal;
    this.endVal = this.validateValue(endVal);
    this.options.decimalPlaces = Math.max(0 || this.options.decimalPlaces);
    this.decimalMult = Math.pow(10, this.options.decimalPlaces);
    this.resetDuration();
    this.options.separator = String(this.options.separator);
    this.useEasing = this.options.useEasing;
    if (this.options.separator === '') {
      this.options.useGrouping = false;
    }
    if (this.target && typeof target === 'string') {
      this.printValue(this.startVal);
    } else {
      this.error = '[CountUp] target is null or undefined';
    }
  }

  // 决定数字滚动的方向
  determineDirectionAndSmartEasing () {
    var end = (this.finalEndVal) ? this.finalEndVal : this.endVal;
    this.countDown = (this.startVal > end);
    var animateAmount = end - this.startVal;
    if (Math.abs(animateAmount) > this.options.smartEasingThreshold) {
        this.finalEndVal = end;
        var up = (this.countDown) ? 1 : -1;
        this.endVal = end + (up * this.options.smartEasingAmount);
        this.duration = this.duration / 2;
    }
    else {
        this.endVal = end;
        this.finalEndVal = null;
    }
    if (this.finalEndVal) {
        this.useEasing = false;
    }
    else {
        this.useEasing = this.options.useEasing;
    }
  }
  
  // 开始动画
  start (callback) {
    if (this.error || !this.context) {
      return;
    }
    this.callback = callback;
    if (this.duration > 0) {
      this.determineDirectionAndSmartEasing();
      this.paused = false;
      this.rAF = doAnimationFrame(this.count);
    } else {
      this.printValue(this.endVal);
    }
  }

  // 暂停/恢复动画
  pauseResume () {
    if (!this.paused) {
      abortAnimationFrame(this.rAF);
    } else {
      this.startTime = null;
      this.duration = this.remaining;
      this.startVal = this.frameVal;
      this.determineDirectionAndSmartEasing();
      this.rAF = doAnimationFrame(this.count);
    }
    this.paused = !this.paused;
  }

  // 重置为 startVal,以便动画可以再次运行
  reset () {
    abortAnimationFrame(this.rAF);
    this.paused = true;
    this.resetDuration();
    this.startVal = this.validateValue(this.options.startVal);
    this.frameVal = this.startVal;
    this.printValue(this.startVal);
  }

  // 通过一个新的 endVal 并开始动画
  update (newEndVal) {
    abortAnimationFrame(this.rAF);
    this.startTime = null;
    this.endVal = this.validateValue(newEndVal);
    if (this.endVal === this.frameVal) {
      return;
    }
    this.startVal = this.frameVal;
    if (!this.finalEndVal) {
      this.resetDuration();
    }
    this.determineDirectionAndSmartEasing();
    this.rAF = doAnimationFrame(this.count);
  }

  // 输出值
  printValue (val) {
    var result = this.formattingFn(val);
    var target = this.target
    this.context && this.context.setData({
      [target]: result
    })
  }

  // 是否数字类型
  ensureNumber (n) {
    return (typeof n === 'number' && !isNaN(n));
  }

  // 验证值的类型
  validateValue (value) {
    var newValue = Number(value);
    if (!this.ensureNumber(newValue)) {
      this.error = "[CountUp] invalid start or end value: " + value;
      return null;
    }
    else {
      return newValue;
    }
  }

  // 重置动画间隔
  resetDuration () {
    this.startTime = null;
    this.duration = Number(this.options.duration) * 1000;
    this.remaining = this.duration;
  }
}

/**
 * 复制对象
 */
var __assign = (this && this.__assign) || function () {
  __assign = Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
      s = arguments[i];
      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
          t[p] = s[p];
    }
    return t;
  };
  return __assign.apply(this, arguments);
};


/**
 * 代替 requestAnimationFrame 帧渲染
 * copy from https://www.dennic365.com/blog/?p=87
 */

var lastFrameTime = 0;
// 模拟 requestAnimationFrame
var doAnimationFrame = function (callback) {
    var currTime = new Date().getTime();
    var timeToCall = Math.max(0, 16 - (currTime - lastFrameTime));
    var id = setTimeout(function () { callback(currTime + timeToCall); }, timeToCall);
    lastFrameTime = currTime + timeToCall;
    return id;
};
// 模拟 cancelAnimationFrame
var abortAnimationFrame = function (id) {
    clearTimeout(id)
}

export default WxCountUp

//使用
import WxCountUp from './WxCountUp.js'
const numAdd = (val,context,name) =>{
  context[name] = wx.createAnimation();
  context.countUp = new WxCountUp(name, val, {
    startVal: 0 // 初始值
  }, context); 
  context.countUp.start(() => console.log('Complete!'));
}
setTimeout(() => {
  this.numAdd(20,this,'number20')
}, 3500);
//绑定wxml
 <view class="num">{{number20}}+</view>

文字逐字显示:

setTimeout(() => {
   var that=this
   if(!that.textTime){
     this.opcityicon2();
   //文字逐个显示
   var story = "文字123123123123123";
   var i = 0;
   that.textTime = setInterval(function () {
     var text = story.substring(0, i);
     i++;
     that.setData({
       text: text
     });
     if (text.length == story.length) {
       clearInterval(that.textTime);
       that.textTime='end'
     }
   }, 10)
   }
 }, 2500);

根据wx-animation封装动画方法

// 基础渐变
const timeLineOpactity = (context,name) =>{
  context[name] = wx.createAnimation();
  context[name].opacity(0.3).opacity(0.6).opacity(1).step()
}
使用//
  // 动画相关
  movex: function () {
    flash.timeLineOpactity(this,'animat')
    this.setData({animat: this.animat.export()})
  },
  //wxml
  <view style='opacity:0' animation="{{animat}}">渐变123</view>
  

时间轴

//wxml
<view class="box">
  <view wx:for="{{list}}" wx:key="index" class="one">
    <view class="onedot"></view>
    <view wx:if="{{index!=list.length-1}}" class="oneline"></view>
    <view class="onemain">
      <view class="onemaintitle">{{item.time}}</view>
      <view class="onemaincon">{{item.con}}</view>
    </view>
  </view>
</view>
//wxss
.box {
  padding: 30rpx;
}
.one {
  position: relative;
  padding-bottom: 40rpx;
}
.onedot {
  left: -2rpx;
  width: 24rpx;
  height: 24rpx;
  position: absolute;
  background-color: #67c23a;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1;
}
.oneline {
  position: absolute;
  left: 8rpx;
  height: 100%;
  border-left: 2px solid #e4e7ed;
}
.onemain {
  position: relative;
  padding-left: 56rpx;
  top: -6rpx;
}
.onemaintitle {
  margin-bottom: 16rpx;
  padding-top: 8rpx;
  color: #909399;
  line-height: 1;
  font-size: 26rpx;
}
.onemaincon {
  color: #303133;
}
//js
data: {
    list: [{
      time: "2021-02-02 10:30:30",
      con: "这是主要内容部分"
    },{
      time: "2021-02-02 10:30:30",
      con: "这是主要内容部分这是主要内容部分这是主要内容部分这是主要内容部分这是主要内容部分"
    },{
      time: "2021-02-02 10:30:30",
      con: "这是主要内容部分这是主要内容部分这是主要内容部分这是主要内容部分"
    }]
  },

使用swiper,中间放大,左右缩小效果

//wxml
<swiper class="swiper-block" previous-margin="90rpx" next-margin="90rpx" current="0" bindchange="swiperChange">
  <block wx:for="{{imgUrls}}" wx:index="{{index}}">
    <swiper-item class="swiper-item">
      <image mode="aspectFill" src="{{item}}" class="slide-image {{swiperIndex == index ? 'active' : ''}}"/>
    </swiper-item>
  </block>
</swiper>
//wxss
.swiper-block{
    height: 480rpx;
    width: 100%;
  }
.swiper-item{
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  overflow:unset;
}
.slide-image{
  height:320rpx;
  width: 520rpx;
  border-radius: 9rpx;
  box-shadow: 0px 0px 30rpx rgba(0, 0,0,.2);
  margin: 0rpx 30rpx;
  z-index: 1;
}
.active{
  transform: scale(1.14);
  transition:all .2s ease-in 0s;
  z-index: 20;
}.swiper-block{
  height: 480rpx;
  width: 100%;
}
.swiper-item{
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  overflow:unset;
}
.slide-image{
  height:320rpx;
  width: 520rpx;
  border-radius: 9rpx;
  box-shadow: 0px 0px 30rpx rgba(0, 0,0,.2);
  margin: 0rpx 30rpx;
  z-index: 1;
}
.active{
  transform: scale(1.14);
  transition:all .2s ease-in 0s;
  z-index: 20;
}
//js
data: {
    imgUrls: [
      'http://img.alicdn.com/tfs/TB1pYiNDEY1gK0jSZFCXXcwqXXa-420-420.png_200x200Q90.jpg',
      'http://img.alicdn.com/tfs/TB1pYiNDEY1gK0jSZFCXXcwqXXa-420-420.png_200x200Q90.jpg',
      'http://img.alicdn.com/tfs/TB1pYiNDEY1gK0jSZFCXXcwqXXa-420-420.png_200x200Q90.jpg'
      ],
    indicatorDots: false,
    autoplay: false,
    interval: 5000,
    duration: 1000,
    swiperIndex: 0,  // 第一次加载默认第一张图片选中
  },
  // 方法 
  swiperChange(e) {
    const that = this;
    that.setData({
      swiperIndex: e.detail.current,
    })
  },


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值