高仿【华为消费者业务官网】和精彩动画剖析:练习在低代码平台中嵌入JS代码

121 阅读5分钟

本课程是华为消费者业务官网的仿站习作。
页面排版精美,照搬原站UI,一键导入HTML和CSS,还原度非常高,达到以假乱真的程度。
本课程重点是带领读者学习如何在众触低代码应用平台中嵌入JS代码,也有视频讲解

赶紧用电脑浏览器访问开发版一睹为快吧!如果你是用手机浏览的,就只能访问浏览版了。

全局初始化:$c.exp.init

整个网站大量使用了滚动动画,使用ScrollMagic侦探页面滚到特定位置来执行特定的动画,而GSAP是专业动画库,配合在一起相得益彰。所以要先加载这两个JS库和它们的合体:

load(["//z.zccdn.cn/vendor/gsap_3.4.0.js", "//z.zccdn.cn/vendor/ScrollMagic/ScrollMagic_2.0.7.js", "//z.zccdn.cn/vendor/ScrollMagic/ScrollMagic_gsap_2.0.7.js"])
$w.HW.Ctrl ? "" : $w.eval($c.js.init)

加载完了需要创建一个ScrollMagic的控制器(Controller),它还需要一些关于页面视窗的参数,比如宽高比(aspectRatio),是电脑屏还是手机屏(isPc),是横屏还是竖屏(isPortrait)等信息。我们把这些信息统一放到window.HW下,从众触表达式看来,就是$w.HW

原生JS代码:$c.js.init

window.HW ? "" : window.HW = {}
HW.aspectRatio = innerWidth / innerHeight
HW.isPc = innerWidth > 834 && HW.aspectRatio > 1
HW.isPortrait = window.matchMedia("(max-aspect-ratio: 1/1)").matches
HW.isFoldScene677 = innerWidth > 675 && innerWidth < 735
HW.navHeight = HW.isPc ? 76 : 96
HW.Ctrl = new ScrollMagic.Controller()

从上面可以看到,众触表达式$w.eval($c.js.init)是用window.eval函数执行$c.js.init字符串代码,这就是低代码里调用原生JS代码的一种方式。

每一段滚动相关的动画我们都用挂载组件封装一下,在挂载组件的挂载组件里执行相关的局部JS代码:$w.eval($js.x),在卸载事件销毁对象回收内存:$w.HW.Ctrl.destroy()

整个华为消费者业务官网都非常绚丽,使用到的技术也都类似,这里以matepad-pro-12-6产品页做范例。

动画一:wa-section-kv

var kvImgScale = (innerHeight - 76) / (0.27708334 * innerWidth);
var kvImgWidth1 = HW.isPc ? 0.9354166 * innerWidth : 0.56805556 * 5.7535 * innerWidth;
var kvImgWidth2 = HW.isPc ? 0.496875 * innerWidth : 0.56805556 * innerWidth;
var kvTopImgHeight = parseInt(getComputedStyle($('.wa-section-kv-top')).marginBottom.replace('px', '')) + parseInt(getComputedStyle($('.wa-section-kv-top')).paddingTop.replace('px', '')) + 0.06770833 * innerWidth;
var kvImgY = HW.isPc ? -kvTopImgHeight : -0.935 * innerWidth;
var kvImgX = HW.isPc ? -0.33 * innerWidth : -1.36 * innerWidth;
var kvImgX2 = HW.isPc ? -0.11 * innerWidth : -0.16 * innerWidth;
var kvTimeline = new TimelineMax()
  .add([
    TweenMax.fromTo('.kv-effect-img1', 2, {
      width: kvImgWidth1,
      x: kvImgX,
      y: kvImgY,
    }, {
      width: kvImgWidth2,
      x: kvImgX2,
      y: 0,
    })
  ])
  .add([
    TweenMax.to('.kv-effect-img1', 2, {
      x: '-50%',
      ease: Power2.easeOut,
      delay: 1,
    }),
    TweenMax.from('.kv-effect-img2', 2, {
      left: '54%',
      ease: Power2.easeOut,
      delay: 1,
    }),
    TweenMax.from('.kv-effect-img3', 2, {
      left: '55%',
      ease: Power2.easeOut,
      delay: 1,
    })
  ])
  .add([
    TweenMax.from('.kv-effect-img4', 2, {
      x: '-400%',
      ease: Power2.easeOut,
      delay: 1,
    })
  ])
  .add([
    TweenMax.from('.kv-effect-img5', 1.5, {
      autoAlpha: 0,
      delay: .5,
    }),
  ])
var kvScene = new ScrollMagic.Scene({
    triggerHook: 0,
    triggerElement: '.wa-section-kv-trigger',
    duration: '300%',
    offset: -76,
  })
  .setTween(kvTimeline)
  .addTo(HW.Ctrl)

wa-section4

const videoCover = function(wrap, duration) {
  section4Timeline = new TimelineMax()
    .add([
      TweenMax.to(wrap + ' .wa-section4-coverimg', 2, {
        scale: 4.5,
      }),
    ])
    .add([
      TweenMax.to(wrap + ' .wa-section4-coverimg', .01, {
        autoAlpha: 0,
      }),
    ], '-=0.2')
    .add([
      TweenMax.to(wrap + ' .wa-section-text', 2, {
        autoAlpha: 1,
        y: '-50%',
      }),
      TweenMax.to(wrap + ' .wa-section-text-bg', 2, {
        autoAlpha: .68,
      }),
    ], '+=1')
  new ScrollMagic.Scene({
      triggerHook: 0,
      triggerElement: wrap,
      duration,
    })
    .setTween(section4Timeline)
    .addTo(HW.Ctrl)
}

videoCover('.wa-section4', '150%');
videoCover('.wa-section7', '150%');
videoCover('.wa-section13', '150%');

此函数videoCover也同时作用在wa-section7和wa-section13上

wa-section7

wa-section13

wa-section5

var s5ImgHeight, section5ImgPosition2, section5ImgBottom;
var s5ImgContainerHeight = parseInt(getComputedStyle($('.wa-section5-img')).height.replace("px", ""));
var s5TextHeight = parseInt(getComputedStyle($('.wa-section5-text')).height.replace("px", ""));
if (HW.isPc) {
  s5ImgHeight = 0.3953125 * innerWidth;
  s5ImgTextDistance = 0.046354166 * innerWidth;
  section5ImgBottom = (s5ImgContainerHeight - s5ImgHeight) / 2;
  section5ImgPosition2 = -(s5TextHeight + s5ImgTextDistance) + section5ImgBottom;
} else {
  s5ImgHeight = 0.5486 * innerWidth;
  s5ImgTextDistance = 0.09444 * innerWidth;
  s5TextBottom = (-s5ImgContainerHeight + s5TextHeight) / 5;
  section5ImgPosition2 = s5ImgContainerHeight - s5ImgHeight - s5ImgTextDistance - s5TextHeight + s5TextBottom;
}
var section5ImgPosition1 = (s5ImgContainerHeight - s5ImgHeight) / 2;
var section5Timeline = new TimelineMax()
  .add([
    TweenMax.to('.wa-section5-img img', 2, {
      scale: 1,
      y: section5ImgPosition1,
    }),
  ])
  .add([
    TweenMax.to('.wa-section5-img img', 2, {
      y: section5ImgPosition2,
    })
  ])
var section5Scene = new ScrollMagic.Scene({
    triggerElement: '.wa-section5-trigger',
    triggerHook: 0,
    duration: '100%',
  })
  .setTween(section5Timeline)
  .addTo(HW.Ctrl)

wa-section10

var isPc = HW.isPc
var section10TimeLine = new TimelineMax({
  defaults: {
    duration: 1,
    ease: Power1.ease,
  },
}).to('.wa-section10-container', {
  scale: 1,
}).to('.wa-section10-pad-dark', {
  autoAlpha: 1,
}).to('.wa-section10-text-div1', {
  autoAlpha: 1,
}, '-=1').to('.wa-section10-pad-memo', {
  autoAlpha: 1,
}, '-=1').to('.wa-section10-pad-arrow', {
  autoAlpha: 1,
}, '-=1').to('.wa-section10-pad-arrow', {
  top: isPc ? '20.572917vw' : '30.1997vw',
  left: isPc ? '35.729167vw' : '52.0729vw',
}).to('.wa-section10-pad-memo-text', {
  autoAlpha: 1,
}).to('.wa-section10-pad-memo', {
  scale: 1.3,
}, '-=1').to('.wa-section10-pad-arrow', {
  top: isPc ? '17.03125vw' : '23.1997vw',
  autoAlpha: 0,
}).to('.wa-section10-pad-memo', {
  scale: 1,
}, '-=1').to('.wa-section10-pad-memo-text', {
  autoAlpha: 0,
}, '-=1').to('.wa-section10-pad-upcoming', {
  autoAlpha: 1,
}).to('.wa-section10-pad-arrow', {
  top: isPc ? '21.09375vw' : '30.3914vw',
  left: isPc ? '46.354167vw' : '66.8324vw',
}, '-=1').to('.wa-section10-pad-memo', {
  autoAlpha: 0,
}).to('.wa-section10-pad-arrow', {
  top: isPc ? '19.84375vw' : '28.3914vw',
  left: isPc ? '43.645833vw' : '63.8324vw',
  autoAlpha: 1,
}).to('.wa-section10-pad-arrow', {
  autoAlpha: 0,
}, '-=.5').to('.wa-section10-pad-arrow', .5, {
  autoAlpha: 1,
}).to('.wa-section10-pad-upcoming', {
  left: isPc ? '21.979167vw' : '31.9792vw',
}).to('.wa-section10-pad-upcoming-icon', {
  autoAlpha: 0,
}, '-=1').to('.wa-section10-pad-arrow', {
  left: isPc ? '43.90625vw' : '65.072917vw',
  autoAlpha: 0,
}, '-=1').to('.wa-section10-text-div1', {
  autoAlpha: 0,
}).to('.wa-section10-pad-dark', {
  'z-index': 5,
}).to('.wa-section10-pad-arrow', {
  top: isPc ? '34.270833vw' : '49.8vw',
  left: isPc ? '28.802083vw' : '41.8021vw',
}, '-=1').to('.wa-section10-text-div2', {
  autoAlpha: 1,
}).to('.wa-section10-pad-navbar', {
  autoAlpha: 1,
}, '-=1').to('.wa-section10-pad-file', {
  autoAlpha: 1,
}, '-=1').to('.wa-section10-pad-arrow', {
  autoAlpha: 1,
}).to('.wa-section10-pad-arrow', {
  top: isPc ? '32.083333vw' : '46.8vw',
  left: isPc ? '27.1875vw' : '39.21vw',
}).to('.wa-section10-pad-file-bg', {
  autoAlpha: 1,
}, '-=1').to('.wa-section10-pad-file', {
  scale: 1.15,
}, '-=1').to('.wa-section10-text-div2', {
  autoAlpha: 0,
}, '-=1').to('.wa-section10-text-div3', {
  autoAlpha: 1,
}, '-=1').to('.wa-section10-pad-file-pop', {
  autoAlpha: 1,
}).set({}, {}, '+=1').to('.wa-section10-pad-arrow', {
  top: isPc ? '25.78125vw' : '37.8vw',
}).to('.wa-section10-pad-arrow', {
  autoAlpha: 0,
}).to('.wa-section10-pad-arrow', {
  top: isPc ? '4.166667vw' : '7.1667vw',
  left: isPc ? '4.114583vw' : '6.1146vw',
}).to('.wa-section10-pad-browse', {
  autoAlpha: 1,
}).to('.wa-section10-text-div3', {
  autoAlpha: 0,
}, '-=1').to('.wa-section10-pad-arrow', {
  autoAlpha: 1,
}, '-=1').to('.wa-section10-pad-arrow', {
  top: isPc ? '3.020833vw' : '4.1667vw',
  left: isPc ? '6.354167vw' : '9.1146vw',
}).to('.wa-section10-pad-other', {
  autoAlpha: 1,
}).to('.wa-section10-text-div4', {
  autoAlpha: 1,
}).to('.wa-section10-pad-arrow', {
  autoAlpha: 0,
}, '-=1').to('.wa-section10-pad-other-cover', {
  autoAlpha: 1,
}, '+=.5').to('.wa-section10-pad-phone', {
  autoAlpha: 1,
}, '+=.5').to('.wa-section10-pad-other-cover', {
  autoAlpha: 0,
}, '+=1').to('.wa-section10-pad-phone', {
  autoAlpha: 0,
}, '-=1').to('.wa-section10-text-div4', {
  autoAlpha: 0,
}, '-=1').to('.wa-section10-pad-drak2', 2, {
  autoAlpha: 1,
}).to('.wa-section10-pad-fall img', 2, {
  y: 0,
}, '-=2').to('.wa-section10-text-div5', 2, {
  autoAlpha: 1,
}, '-=2')
var section10Scene = new ScrollMagic.Scene({
    triggerElement: '.wa-section10-wrapper',
    triggerHook: 0,
    duration: '700%',
  })
  .setTween(section10TimeLine)
  .addTo(HW.Ctrl)

wa-section11

这里还用到了Swiper插件,把它的JS和CSS库也加载进来

$c.exp.init.exc()
load("//z.zccdn.cn/vendor/swiper_6.5.8.js")
load("//z.zccdn.cn/vendor/swiper_6.5.8.css")
$w.eval($js.x)

$js.x

var section11Imgswiper = new Swiper('.wa-section11-img-wrapper .swiper-container', {
  effect: 'fade',
  allowTouchMove: false,
  fadeEffect: {
    crossFade: true,
  },
  scrollbar: {
    el: '.wa-section11 .swiper-scrollbar',
    hide: false,
  },
});
var section11Textswiper = new Swiper('.wa-section11-text-wrapper .swiper-container', {
  effect: 'fade',
  allowTouchMove: false,
  fadeEffect: {
    crossFade: true,
  },
});
section11Imgswiper.controller.control = section11Textswiper;
section11Textswiper.controller.control = section11Imgswiper;

function offsetTop(e) {
  let t = 0
  if (e) {
    do {
      if (!isNaN(e.offsetTop)) t += e.offsetTop
      e = e.offsetParent
    } while (e)
  }
  return t
}

$$('.wa-section11 .wa-section11-swiper-text p').forEach((a, i) => {
  let anmLength;
  switch (i) {
    case 0:
      anmLength = 0;
      break;
    case 1:
      anmLength = 1.35;
      break;
    case 2:
      anmLength = 4.02;
      break;
  }
  a.addEventListener('click', function() {
    var activeP = $('.wa-section11 .wa-section11-swiper-text p.active')
    if (activeP) activeP.classList.remove('active')
    a.classList.add('active')
    let topHeight = offsetTop($('.wa-section11')) + innerHeight * anmLength;
    window.scrollTo(0, topHeight)
  })
})


var isPc = HW.isPc
var s11Part1PenTop = isPc ? 0.09777 * innerWidth : 0.149045 * innerWidth;
var s11Part1PenLeft = isPc ? 0.551302 * innerWidth : 0.731944 * innerWidth;
var s11Part2ArrowB1 = isPc ? 0.07495625 * innerWidth : 0.09495625 * innerWidth;
var s11Part2Left1 = isPc ? 0.235464 * innerWidth : 0.335464 * innerWidth;
var s11Part2ArrowB2 = isPc ? 0.02495625 * innerWidth : 0.04495625 * innerWidth;
var s11Part2Left2 = 0.545464 * innerWidth;
var s11PartVideoWidth = isPc ? 0.271875 * innerWidth : 0.38055556 * innerWidth;
var s11Part3PhotoScale = isPc ? 2.4 : 2.62;
var section11Timeline = new TimelineMax()
  .add([
    TweenMax.to('.section11-pad-img-bg', 2, {
      alpha: 1,
    }),
    TweenMax.to('.section11-part1-pen', 2, {
      top: s11Part1PenTop,
      left: s11Part1PenLeft,
    }),
  ])
  .add([
    TweenMax.to('.section11-part2-arrow', 1, {
      bottom: s11Part2ArrowB1,
      left: s11Part2Left1,
    })
  ], '+=0.5')
  .add([
    TweenMax.to('.section11-part2-video', 1, {
      width: s11PartVideoWidth,
      x: 0,
      y: 0,
    }),
    TweenMax.to('.section11-part2-arrow', 1, {
      bottom: s11Part2ArrowB2,
      left: s11Part2Left2,
      autoAlpha: 0,
    }),
  ])
  .add([
    TweenMax.to('.section11-part2-text p', .5, {
      autoAlpha: 1,
    }),
    TweenMax.staggerTo('.section11-part2-text span', .2, {
      autoAlpha: 1,
      display: 'inline-block',
      delay: .5,
    }, 0.2),
  ])
  .add([
    TweenMax.to('.section11-part2-text p', .5, {
      autoAlpha: 0,
    }),
  ], '-=.55')
  .add([
    TweenMax.to('.section11-part3-arrow-container', 1, {
      top: isPc ? '38%' : '33%',
      left: '43%',
    })
  ], '+=0.5')
  .add([
    TweenMax.to('.section11-part3-arrow-container', .5, {
      top: '44.9309%',
      left: '53.6629%',
    }),
    TweenMax.to('.section11-part3-photo-container', .5, {
      top: '41.8489%',
      left: '52.3343%',
    }),
  ])
  .add([
    TweenMax.to('.section11-part3-photo-container', .2, {
      autoAlpha: 0,
    }),
    TweenMax.to('.section11-part3-arrow', .2, {
      autoAlpha: 0,
    }),
  ], '-=.25')
  .add([
    TweenMax.to('.section11-part3-arrow-container', .1, {
      left: '55%',
    }),
  ], '-=.1')
  .add([
    TweenMax.to('.section11-part3-hand', .1, {
      autoAlpha: 1,
    }),
    TweenMax.to('.section11-part3-arrow-container', 1, {
      top: '64%',
      left: '83%',
    }),
    TweenMax.to('.section11-part3-photo-bg', .4, {
      autoAlpha: 1,
    }),
  ], '-=.1')
  .add([
    TweenMax.to('.section11-part3-photo-container', 1, {
      top: '67.5%',
      left: '81%',
      autoAlpha: 0,
    }),
  ], '-=1')
  .add([
    TweenMax.to('.section11-part3-photo-container', 1, {
      autoAlpha: 1,
      scale: s11Part3PhotoScale,
    }),
    TweenMax.to('.section11-part3-hand', .5, {
      autoAlpha: 0,
    }),
  ])

var slide1 = $('.wa-section11 .swiper-slide:nth-child(1)')
var slide2 = $('.wa-section11 .swiper-slide:nth-child(2)')
var slide3 = $('.wa-section11 .swiper-slide:nth-child(3)')
var section11Scene = new ScrollMagic.Scene({
    triggerElement: '.wa-section11-trigger',
    triggerHook: 0,
    duration: '600%',
  })
  .on('progress', function(event) {
    var activeSlide = $('.wa-section11 .swiper-slide-active')
    var scrollbar = $('.wa-section11 .swiper-scrollbar-drag').style
    var activeText = $('.wa-section11 .wa-section11-swiper-text .active')
    if (activeSlide) activeSlide.classList.remove('swiper-slide-active')
    if (activeText) activeText.classList.remove('active')
    if (event.progress < 0.1869) {
      slide1.classList.add('swiper-slide-active')
      slide2.style.opacity = 0
      slide3.style.opacity = 0
      slide1.style.opacity = 1
      slide1.style["transition-duration"] = "300ms"
      scrollbar.transform = 'translate3d(0%, 0px, 0px)'
      $('.wa-section11 .wa-section11-swiper-text p:nth-child(1)').classList.add('active')
    } else if (event.progress < 0.636) {
      slide2.classList.add('swiper-slide-active')
      slide1.style.opacity = 0
      slide3.style.opacity = 0
      slide2.style.opacity = 1
      slide2.style["transition-duration"] = "1000ms"
      scrollbar.transform = 'translate3d(100%, 0px, 0px)'
      $('.wa-section11 .wa-section11-swiper-text p:nth-child(2)').classList.add('active')
    } else if (event.progress < 1) {
      slide2.classList.add('swiper-slide-active')
      slide1.style.opacity = 0
      slide2.style.opacity = 0
      slide3.style.opacity = 1
      slide3.style["transition-duration"] = "1000ms"
      scrollbar.transform = 'translate3d(200%, 0px, 0px)'
      $('.wa-section11 .wa-section11-swiper-text p:nth-child(3)').classList.add('active')
    }
  })
  .setTween(section11Timeline)
  .addTo(HW.Ctrl)

声明

本课程于2021年7月9日仿自华为消费者业务官网里的consumer.huawei.com/cn/tablets/…
源站随着时间的推移可能会不断演变,而课程作品并不会一起跟着变化,所以作品跟你现在看到的源站不同是正常的。