一篇知乎的故事 - javascript技術貼


前言  

本文的發表源於知乎的一篇文章。文章鏈接如下:如果你想靠前端技術還房貸,你不能連這個都不會

前提

1. 本文是一個vue的小組件功能,你需要有vue的經驗,並且了解vue的組件。

2. 本文會貼出一個盜版的jQuery.queue函數,這個函數是之前讀jq源碼自己寫的,就是偷得jq,比不上jq強大,但是基本功能還是有的。

3. 本文不適合新手。

切入正文

上面是問題,我們來解讀一下需求:

1. 首先要有一個模塊,這個模塊包括一個input,兩個button

2. 模塊實現了點擊 A,發送urlA請求,並將input值改為請求返回的值,點擊B,雷同

3. 用戶依次點擊A、B,input首先需要改為urlA請求返回的值,再改為urlB返回的值。也就類似於同步請求。

代碼如下:

<div id="app">
    <my-component></my-component>
 </div>
<template id="tpl">
    <div>
      <input type="text" v-model="inputData" readonly="readonly">
      <p>

        <button @click="request1">按鈕A</button>
        <button @click="request2">按鈕B</button>
      </p>
    </div>
  </template>


<script src="https://unpkg.com/vue/dist/vue.js"></script>
//    resource.min.js  自己下載的
<script type="text/javascript" src="./resource.min.js"></script>

<script>
  Vue.use(VueResource)
  new Vue({
    el: '#app',
    components: {
        'my-component': {
          template: '#tpl',
          data: function () {
            return {
              inputData: '默認的',
              ajax2: null
            }
          },
          methods: {
            request1: function () {
              var url = '我的測試地址:睡眠2秒再返回值'
              this.$http.get(url).then(function(res)  {
                this.inputData = res.data
                this.ajax2()
              })
            },
            request2: function () {
              this.ajax2 = function () {
                var url = '我的測試地址:睡眠1秒返回值'
                this.$http.get(url).then(function(res)  {
                  this.inputData = res.data
                })
              }
            },
          },
        }
    }
  })
</script>

我定義了一個vue實例,在#app元素內有效。定義個組件,給這個組件一個inputData屬性存儲input框中的數據,定義一個ajax2屬性存儲點擊B按鈕時的發起請求的函數。我們在點擊A后返回值后,調用ajax2這個方法,這樣就實現了上面的需求,當然僅僅是實現了上面的需求而已,並且代碼看上去很難看,因為我們為了實現這個功能不得不在模型上加了個ajax2這個很雞肋的中間量,為了讓代碼更好看一些,功能更強一些,不防試一試用隊列來解決。

隊列的作用

我們不僅要實現上面這個簡單的例子,我們需要實現的效果更強壯: 

1. 連續交替點擊A、B按鈕,將返回值有順序的顯示到input上面

2. 每一次點擊都會產生一個ajax請求,但是不會立刻發起,會根據點擊順序依次請求。

3. 利用一個隊列對象來實現,使代碼變得更簡潔更美觀。

代碼如下:

  <div id="app">
    <my-component :q="q"></my-component>
  </div>
  <template id="tpl">
    <div>
      <input type="text" v-model="inputData" readonly="readonly">
      <p>
        <button @click="request('測試地址1:睡眠2秒')">按鈕A</button>
        <button @click="request('測試地址2:睡眠1秒')">按鈕B</button>
      </p>
    </div>
  </template>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <script type="text/javascript" src="./vue-resource.min.js"></script>
  <script type="text/javascript" src="http://git.oschina.net/xuazheng/myJquery/raw/master/queue/queue.js?dir=0&filepath=queue%2Fqueue.js&oid=b23c3bf7212ff41aad350bdb505a1afc59929ce6&sha=d0298a8907c9ed1cf25c176807fadbcd14c3e571"></script>
  <script type="text/javascript">
    Vue.use(VueResource)
    new Vue({
      el: '#app',
      data: {
        q: Queue()
      },
      components: {
        'my-component': {
          template: '#tpl',
          data: function () {
            return {
              inputData: '默認的'
            }
          },
          methods: {
            request: function (url) {
              this.q.queue('fx', function (next){
                this.$http.get(url).then(function(res)  {
                  this.inputData = res.data
                  next()
                })
              }.bind(this))
            }
          },
          props: ['q']
        }, 
      }
    })
  </script>

引入了我的queue,在vue實例上,創建一個q屬性存儲queue對象並傳遞給子組件。在子組件中,我們每次點擊一個按鈕,都會將一個ajax請求的函數添加到fx隊列中,在jquery中,fx類型的隊列存儲着動畫函數,可以處理異步函數隊列的有序執行。不傳遞這個值會默認fx類型,所以也可以直接在queue方法中傳遞一個方法就行。

隊列的代碼如下:

;function Queue() {

  // 數據緩存對象
  var cache = {};

  var queueList = {
    // type默認是fx,是動畫隊列
    queue: function(type,data) {
      var args = arguments;
      //沒有參數直接返回
      if(!args.length){
        return;
      }

      var q = null;
      // 只有一個參數並且是個函數
      if(args.length == 1 && typeof type === 'function') {
        data = type;
        type = 'fx';
      }

      q = cache[type] || [];

      // 添加緩存
      if( data instanceof Array) {
        q = data;
      }else {
        q.push(data)
      }
      cache[type] = q;

      //如果是動畫隊列並且沒有開始的動畫,執行第一個動畫函數
      if(type == 'fx' && q.toString().indexOf('inprogress') === -1) {
        queueList.dequeue()
      }

      return q;

    },
    dequeue: function(type) {
      var fn, queue;
        type = type || 'fx';
        queue = cache[type];
        if(queue.length == 0 ) {
          return;
        }

        fn = queue.shift();

        if( fn === 'inprogress' ) {
          fn = queue.shift();
        }
        if( fn ) {
          if(type === 'fx') {
            queue.unshift('inprogress');
          }
          fn.call(null,function() {
            queueList.dequeue(type);
          })
        } 
    },
    // 延遲使用setTimeout來實現
    delay: function(type,timeout) {
      if(!type) {
        return;
      }
      if(arguments.length == 1) {
        timeout = type;
        type = 'fx';
      }

      if(typeof timeout == 'number') {
        var q = cache[type];
        if(!q) {
          q = cache[type] =  [_delay];
        }else {
          q.push(_delay)
        }

      }
      function _delay() {
        setTimeout(queueList.dequeue, timeout);
      }

      return this;

    },
    get: function(type) {
      type = type || 'fx';
      return cache[type];
    }
  }


  return queueList;
}

這個就不解釋了,比起jquery源碼,這個代碼就顯得很簡單,jquery中做了大量的處理,然而博主並沒有那么厲害,只能簡單的寫了這點。有js基礎的應該看得懂,如果想學jq源碼,推薦 艾倫 Aaron 的博客園

感謝閱讀


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM