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

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

作者: 潘千千 | 来源:发表于2018-08-06 16:24 被阅读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的前提。

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/sidgvftx.html