前言:没事就去刷知乎,相信大家也会看到好多BAT公司的面试题,反正我看了之后很是受挫,最近听了方方老师的课,发现模块化,立即执行函数,闭包和MVC在代码中的初步应用也就是那么回事,当然啦,只是初步应用,特此写下一篇文章,帮助加深理解和造福在前端这条泥巴路上跋涉的童鞋们,这里有一句话要提醒大家,这会是一篇很长的文章,但是不是很费脑,很轻松就能明白我的意图,一定要看下去哈,而且,这三篇文章是连着的,如果对于这几个概念一点也不懂的话,一定要三篇文章连着看。因为我本意是写一篇文章,结果没想到太长了,所以分成三篇来写,还有就是如果大家看了觉得对自己有帮助,麻烦给个赞吧,谢谢大家~~
关键词:模块化,立即执行函数,闭包和MVC~~......
正文:
一、模块化
大家现在先看如下这么长一串代码,这种代码就像是大部分的初级前端经常写的代码,不一定要看的明白,看个大概结构就行:
<!DOCTYPE html>
<html>
<head>
<title>潘潘的个人简历</title>
<script src="//at.alicdn.com/t/font_451045_32zbfqegtq3t0529.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.1.0/css/swiper.min.css">
<link rel="stylesheet" href="main.css">
</head>
<body>
<div id="topNavBar" class="topNavBar">
<div class="topNavBar-inner clearfix">
<a class="logo" href="#" alt="logo" style="float: left;">
<span class="rs">RS</span>
<span class="card">card</span>
</a>
<nav class="menu" style="float: right;">
<ul class="clearfix">
<li>
<a href="#siteAbout">关于</a>
</li>
<li>
<a href="#siteSkills">技能</a>
</li>
<li>
<a href="#siteWorks">作品</a>
<ul class="submenu">
<li>作品1</li>
<li>作品2</li>
<li>作品3</li>
</ul>
</li>
<li>
<a href="#">博客</a>
<ul class="submenu">
<li>博客1</li>
<li>博客2</li>
<li>博客3</li>
</ul>
</li>
<li>
<a href="#">日历</a>
</li>
<li>
<a href="#">联系方式</a>
</li>
<li>
<a href="#">其他</a>
</li>
</ul>
</nav>
</div>
</div>
<div class="banner">
<div class="mask"></div>
</div>
<main>
<div data-x id="siteAbout" class="userCard">
<div class="pictureAndText clearfix">
<div class="picture">
<img src="./img/avatar.jpg" width=299 height=347 alt="头像">
</div>
<div class="text">
<span class="welcome">Hello
<span class="triangle"></span>
</span>
<h1>潘潘</h1>
<p>前端开发工程师</p>
<hr>
<dl>
<dt>年龄</dt>
<dd>18</dd>
<dt>所在城市</dt>
<dd>北京</dd>
<dt>邮箱</dt>
<dd>潘潘@foxmail.com</dd>
<dt>手机</dt>
<dd>666666666666</dd>
</dl>
</div>
</div>
<footer class="media">
<a href="#">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-github"></use>
</svg>
</a>
<a href="#">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-Ankerwebicon-"></use>
</svg>
</a>
<a href="#">
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-weibo"></use>
</svg>
</a>
</footer>
</div>
<p class="downloadResume-wrapper">
<a class="downloadResume" href="./resume.pdf" target="_blank" download>下载 PDF 简历</a>
</p>
<p class="selfIntroduction">
潘潘, 资深前端工程师,
<br> 技能:前端开发,,Node.js 开发
</p>
</main>
<section data-x id="siteSkills" class="skills">
<h2>技能</h2>
<ol class="clearfix">
<li>
<h3>
HTML 5 & CSS 3
</h3>
<div class="progressBar">
<div class="progress" style="width: 10%;"></div>
</div>
</li>
<li>
<h3>
JavaScript
</h3>
<div class="progressBar">
<div class="progress" style="width: 20%"></div>
</div>
</li>
<li>
<h3>
jQuery
</h3>
<div class="progressBar">
<div class="progress" style="width: 30%"></div>
</div>
</li>
<li>
<h3>
Vue.js
</h3>
<div class="progressBar">
<div class="progress" style="width: 40%"></div>
</div>
</li>
<li>
<h3>
React.js
</h3>
<div class="progressBar">
<div class="progress" style="width: 50%"></div>
</div>
</li>
<li>
<h3>
Node.js
</h3>
<div class="progressBar">
<div class="progress" style="width: 60%"></div>
</div>
</li>
</ol>
</section>
<section data-x class="portfolio" id="siteWorks">
<h2>作品集</h2>
<nav>
<ol class="clearfix">
<li id="portfolio1">所有</li>
<li id="portfolio2">框架</li>
<li id="portfolio3">原生JS&CSS</li>
</ol>
<div id="portfolioBar" class="bar state-1">
<div class="bar-inner"></div>
</div>
</nav>
<script>
portfolio1.onclick= function(){
portfolioBar.className = 'bar state-1'
}
portfolio2.onclick= function(){
portfolioBar.className = 'bar state-2'
}
portfolio3.onclick= function(){
portfolioBar.className = 'bar state-3'
}
</script>
<div class="works" style="height: 597px;">
<div class="big" style="top: 0; left: 0;">
<img src="img/zw-findpsw.png" alt="作品1" width="300">
</div>
<div class="small" style="top: 0; left: 310px;">
<img src="img/zw-login.png" alt="作品2" width="300">
</div>
<div class="small" style="top: 0; left: 620px;">
<img src="img/zw-lucky.png" alt="作品3" width="300">
</div>
</div>
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.1.1/Tween.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.1.0/js/swiper.min.js"></script>
<script>
var mySwiper = new Swiper('.swiper-container',{
loop:true,
pagination:{
el:'.swiper-pagination'
},
navigation:{
nextEl:'.swiper-button-next',
prevEl:'.swiper-button-prev',
}
})
</script>
<script>
// 添加 offset 类
let specialTags = document.querySelectorAll('[data-x]')
for(let i =0;i<specialTags.length; i++){
specialTags[i].classList.add('offset')
}
findClosest()
window.onscroll = function(x){
if(window.scrollY > 0){
topNavBar.classList.add('sticky')
}else{
topNavBar.classList.remove('sticky')
}
findClosest()
}
function findClosest(){
let specialTags = document.querySelectorAll('[data-x]')
let minIndex = 0
for(let i =1;i<specialTags.length; i++){
if(Math.abs(specialTags[i].offsetTop - window.scrollY) < Math.abs(specialTags[minIndex].offsetTop - window.scrollY)){
minIndex = i
}
}
// minIndex 就是里窗口顶部最近的元素
specialTags[minIndex].classList.remove('offset')
let id = specialTags[minIndex].id
let a = document.querySelector('a[href="#'+ id + '"]')
let li = a.parentNode
let brothersAndMe = li.parentNode.children
for(let i=0; i<brothersAndMe.length; i++){
brothersAndMe[i].classList.remove('highlight')
}
li.classList.add('highlight')
}
let liTags = document.querySelectorAll('nav.menu > ul > li')
for(let i=0; i<liTags.length; i++){
liTags[i].onmouseenter = function(x){
x.currentTarget.classList.add('active')
}
liTags[i].onmouseleave = function(x){
x.currentTarget.classList.remove('active')
}
}
let aTags = document.querySelectorAll('nav.menu > ul > li > a')
function animate(time) {
requestAnimationFrame(animate);
TWEEN.update(time);
}
requestAnimationFrame(animate);
for(let i=0; i<aTags.length; i++){
aTags[i].onclick = function(x){
x.preventDefault()
let a = x.currentTarget
let href = a.getAttribute('href') //'#siteAbout'
let element = document.querySelector(href)
let top = element.offsetTop
let currentTop = window.scrollY
let targetTop = top - 80
let s = targetTop - currentTop // 路程
var coords = { y: currentTop}; // 起始位置
var t = Math.abs((s/100)*300) // 时间
if(t>500){ t = 500 }
var tween = new TWEEN.Tween(coords) // 起始位置
.to({ y: targetTop}, t) // 结束位置 和 时间
.easing(TWEEN.Easing.Cubic.InOut) // 缓动类型
.onUpdate(function() {
// coords.y 已经变了
window.scrollTo(0,coords.y) // 如何更新界面
})
.start(); // 开始缓动
}
}
</script>
</body>
</html>
其实,大家刚刚顺上面的代码的时候的想法,就像我们提交了项目,好久之后再来看代码的样子:
image.png
那其实模块化有一个功能就是整理我们的代码,让它看起来更简洁,更一目了然。大家看上图的swiper那一部分,是单独的一部分,好,那我们抽出一个js文件,把它单独放出来。
。。。。。.此处省略,太占地方了
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.1.1/Tween.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.1.0/js/swiper.min.js"></script>
<script src="js/init-swiper.js"></script>//--------------------------------------------------->这里是刚才swiper那一段代码的地方。
<script>
// 添加 offset 类
let specialTags = document.querySelectorAll('[data-x]')
for(let i =0;i<specialTags.length; i++){
specialTags[i].classList.add('offset')
}
。。。。。。此处省略,太长了,,,
init-swiper.js:
var mySwiper = new Swiper('.swiper-container',{
loop:true,
pagination:{
el:'.swiper-pagination'
},
navigation:{
nextEl:'.swiper-button-next',
prevEl:'.swiper-button-prev',
}
})
接下来,是swiper下面那一堆js的整理 ,先看这一部分,因为他们都有一个共同的specialTags ,经过细细回想,发现这些代码实现的是同一个效果:
let specialTags = document.querySelectorAll('[data-x]')
for(let i =0;i<specialTags.length; i++){
specialTags[i].classList.add('offset')
}
findClosestAndRemoveOffset()
window.onscroll = function(x){
if(window.scrollY > 0){//----------------------------------------------------------A区
topNavBar.classList.add('sticky')
}else{
topNavBar.classList.remove('sticky')
}//----------------------------------------------------------A区
findClosestAndRemoveOffset()//----------------------------------------------------------B行
}
function findClosestAndRemoveOffset(){
let specialTags = document.querySelectorAll('[data-x]')
let minIndex = 0
for(let i =1;i<specialTags.length; i++){
if(Math.abs(specialTags[i].offsetTop - window.scrollY) < Math.abs(specialTags[minIndex].offsetTop - window.scrollY)){
minIndex = i
}
}
// minIndex 就是里窗口顶部最近的元素
specialTags[minIndex].classList.remove('offset')
let id = specialTags[minIndex].id
let a = document.querySelector('a[href="#'+ id + '"]')
let li = a.parentNode
let brothersAndMe = li.parentNode.children
for(let i=0; i<brothersAndMe.length; i++){
brothersAndMe[i].classList.remove('highlight')
}
li.classList.add('highlight')
}
这里大家注意,看上方代码,A区代码和B行代码实现的不是一个功能,只不过是B行代码是需要在onscroll的情况下进行的。那我们把他分离开吧,毕竟不是一个功能的,这里考考大家,如果分离开,这样写可以吗?
let specialTags = document.querySelectorAll('[data-x]')
for(let i =0;i<specialTags.length; i++){
specialTags[i].classList.add('offset')
}
findClosestAndRemoveOffset()
window.onscroll = function(x){//----------------------------------------------------------第一个
findClosestAndRemoveOffset()
}
window.onscroll = function(x){//----------------------------------------------------------第二个
if(window.scrollY > 0){
topNavBar.classList.add('sticky')
}else{
topNavBar.classList.remove('sticky')
}
}
function findClosestAndRemoveOffset(){
let specialTags = document.querySelectorAll('[data-x]')
let minIndex = 0
for(let i =1;i<specialTags.length; i++){
if(Math.abs(specialTags[i].offsetTop - window.scrollY) < Math.abs(specialTags[minIndex].offsetTop - window.scrollY)){
minIndex = i
}
}
// minIndex 就是里窗口顶部最近的元素
specialTags[minIndex].classList.remove('offset')
let id = specialTags[minIndex].id
let a = document.querySelector('a[href="#'+ id + '"]')
let li = a.parentNode
let brothersAndMe = li.parentNode.children
for(let i=0; i<brothersAndMe.length; i++){
brothersAndMe[i].classList.remove('highlight')
}
li.classList.add('highlight')
}
这肯定是不对的呀,这样监听,是不能给它两次赋值的。那有什么办法呢?addEventListner帮助我们搞定他。addEventListner帮助我们把它放入到队列里面,直接赋值的话,那是会覆盖的。所以,更改后如下:
let specialTags = document.querySelectorAll('[data-x]')
for(let i =0;i<specialTags.length; i++){
specialTags[i].classList.add('offset')
}
findClosestAndRemoveOffset()
window.addEventListner('onscroll ',function(x){//----------------------------------------------------------A区
findClosestAndRemoveOffset()
})//----------------------------------------------------------A区
window.addEventListner('onscroll ',function(x){
if(window.scrollY > 0){
topNavBar.classList.add('sticky')
}else{
topNavBar.classList.remove('sticky')
}
})
function findClosestAndRemoveOffset(){
let specialTags = document.querySelectorAll('[data-x]')
let minIndex = 0
for(let i =1;i<specialTags.length; i++){
if(Math.abs(specialTags[i].offsetTop - window.scrollY) < Math.abs(specialTags[minIndex].offsetTop - window.scrollY)){
minIndex = i
}
}
// minIndex 就是里窗口顶部最近的元素
specialTags[minIndex].classList.remove('offset')
let id = specialTags[minIndex].id
let a = document.querySelector('a[href="#'+ id + '"]')
let li = a.parentNode
let brothersAndMe = li.parentNode.children
for(let i=0; i<brothersAndMe.length; i++){
brothersAndMe[i].classList.remove('highlight')
}
li.classList.add('highlight')
}
现在,我们很容易分辨A区是一个固定导航条的一个效果,所以,我们把它,也像swiper一样用一个js文件放进去,在引入到HTML里面来。
。。。。。.此处省略,太占地方了
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.1.1/Tween.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.1.0/js/swiper.min.js"></script>
<script src="js/init-swiper.js"></script>
<script src="js/auto-slide-up.js"></script>//------------------------------------------------>这里是刚才slideup那一段代码的地方。
<script>
window.addEventListner('onscroll ',function(x){//------------------------------------------------>A区
if(window.scrollY > 0){
topNavBar.classList.add('sticky')
}else{
topNavBar.classList.remove('sticky')
}
})//------------------------------------------------>A区
。。。。。。此处省略,太长了,,,
auto-slide-up.js:
let specialTags = document.querySelectorAll('[data-x]')
for(let i =0;i<specialTags.length; i++){
specialTags[i].classList.add('offset')
}
findClosestAndRemoveOffset()
window.addEventListner('onscroll ',function(x){
findClosestAndRemoveOffset()
})
function findClosestAndRemoveOffset(){
let specialTags = document.querySelectorAll('[data-x]')
let minIndex = 0
for(let i =1;i<specialTags.length; i++){
if(Math.abs(specialTags[i].offsetTop - window.scrollY) < Math.abs(specialTags[minIndex].offsetTop - window.scrollY)){
minIndex = i
}
}
// minIndex 就是里窗口顶部最近的元素
specialTags[minIndex].classList.remove('offset')
let id = specialTags[minIndex].id
let a = document.querySelector('a[href="#'+ id + '"]')
let li = a.parentNode
let brothersAndMe = li.parentNode.children
for(let i=0; i<brothersAndMe.length; i++){
brothersAndMe[i].classList.remove('highlight')
}
li.classList.add('highlight')
}
那现在的HTML里面还剩:
。。。。。.此处省略,太占地方了
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.1.1/Tween.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.1.0/js/swiper.min.js"></script>
<script src="js/init-swiper.js"></script>
<script src="js/auto-slide-up.js"></script>//------------------------------------------------>这里是刚才slideup那一段代码的地方。
<script>
window.addEventListner('onscroll ',function(x){//------------------------------------------------>A区
if(window.scrollY > 0){
topNavBar.classList.add('sticky')
}else{
topNavBar.classList.remove('sticky')
}
})//------------------------------------------------>A区
。。。。。。此处以后的js省略,太长了,,,
这个A区也是一个独立的效果,我们也给它单独建立一个js,那现在的HTML:
。。。。。.此处省略,太占地方了
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.1.1/Tween.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.1.0/js/swiper.min.js"></script>
<script src="js/init-swiper.js"></script>
<script src="js/auto-slide-up.js"></script>
<script src="js/sticky-topbar.js"></script>//------------------------------------------------>这里是刚才sticky那一段代码的地方。
<script>
let liTags = document.querySelectorAll('nav.menu > ul > li')
for(let i=0; i<liTags.length; i++){
liTags[i].onmouseenter = function(x){
x.currentTarget.classList.add('active')
}
liTags[i].onmouseleave = function(x){
x.currentTarget.classList.remove('active')
}
}
let aTags = document.querySelectorAll('nav.menu > ul > li > a')
function animate(time) {
requestAnimationFrame(animate);
TWEEN.update(time);
}
requestAnimationFrame(animate);
for(let i=0; i<aTags.length; i++){
aTags[i].onclick = function(x){
x.preventDefault()
let a = x.currentTarget
let href = a.getAttribute('href') //'#siteAbout'
let element = document.querySelector(href)
let top = element.offsetTop
let currentTop = window.scrollY
let targetTop = top - 80
let s = targetTop - currentTop // 路程
var coords = { y: currentTop}; // 起始位置
var t = Math.abs((s/100)*300) // 时间
if(t>500){ t = 500 }
var tween = new TWEEN.Tween(coords) // 起始位置
.to({ y: targetTop}, t) // 结束位置 和 时间
.easing(TWEEN.Easing.Cubic.InOut) // 缓动类型
.onUpdate(function() {
// coords.y 已经变了
window.scrollTo(0,coords.y) // 如何更新界面
})
.start(); // 开始缓动
}
}
</script>
剩下的代码都属于一个效果,就是平滑的导航,所以,依然如上面那样,提取,新建smoothly-navigationjs,在引入。所以,我们的HTML,就变成如下:
。。。。。.此处省略,太占地方了
<section class="message">
</section>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tween.js/17.1.1/Tween.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.1.0/js/swiper.min.js"></script>
<script src="//cdn1.lncld.net/static/js/3.5.0/av-min.js"></script>
<!-- 模块化 就是把一个功能放进一个块里,你可以认为一个块是一个div,也可以是一个文件 -->
<script src="js/init-swiper.js"></script>
<script src="js/auto-slide-up.js"></script>
<script src="js/sticky-topbar.js"></script>
<script src="js/smoothly-navigation.js"></script>
</body>
</html>
smoothly-navigation.js:
let liTags = document.querySelectorAll('nav.menu > ul > li')
for(let i=0; i<liTags.length; i++){
liTags[i].onmouseenter = function(x){
x.currentTarget.classList.add('active')
}
liTags[i].onmouseleave = function(x){
x.currentTarget.classList.remove('active')
}
}
let aTags = document.querySelectorAll('nav.menu > ul > li > a')
function animate(time) {
requestAnimationFrame(animate);
TWEEN.update(time);
}
requestAnimationFrame(animate);
for(let i=0; i<aTags.length; i++){
aTags[i].onclick = function(x){
x.preventDefault()
let a = x.currentTarget
let href = a.getAttribute('href') //'#siteAbout'
let element = document.querySelector(href)
let top = element.offsetTop
let currentTop = window.scrollY
let targetTop = top - 80
let s = targetTop - currentTop // 路程
var coords = { y: currentTop}; // 起始位置
var t = Math.abs((s/100)*300) // 时间
if(t>500){ t = 500 }
var tween = new TWEEN.Tween(coords) // 起始位置
.to({ y: targetTop}, t) // 结束位置 和 时间
.easing(TWEEN.Easing.Cubic.InOut) // 缓动类型
.onUpdate(function() {
// coords.y 已经变了
window.scrollTo(0,coords.y) // 如何更新界面
})
.start(); // 开始缓动
}
}
这样一整理,看起来是不是很整洁也很干净啦,比之前好太多了。而MVC的前提是有模块,所以,模块化是MVC的前提。
网友评论