本课程是华为消费者业务官网的仿站习作。
页面排版精美,照搬原站UI,一键导入HTML和CSS,还原度非常高,达到以假乱真的程度。
本课程重点是带领读者学习如何在众触低代码应用平台中嵌入JS代码,也有视频讲解。
赶紧用电脑浏览器访问开发版一睹为快吧!如果你是用手机浏览的,就只能访问浏览版了。
整个网站大量使用了滚动动画,使用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
。
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产品页做范例。
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)
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上
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)
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)
这里还用到了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日仿自华为消费者业务官网里的https://consumer.huawei.com/cn/tablets/matepad-pro-12-6,相关素材版权归属于原网站,本课程仅做教学用。
源站随着时间的推移可能会不断演变,而课程作品并不会一起跟着变化,所以作品跟你现在看到的源站不同是正常的。