带你初步了解模块化,立即执行函数,闭包和MVC在项目中的应用(一

2018-08-06  本文已影响0人  潘千千
前言:没事就去刷知乎,相信大家也会看到好多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 &amp; 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&amp;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的前提。

上一篇下一篇

猜你喜欢

热点阅读