ajax

問答

一、ajax 是什么胳蛮?有什么作用麸粮?

Ajax是Asynchronous JavaScript and XML的縮寫,通過new XMLHttpRequest創(chuàng)建對象酬滤,它是一個具有應(yīng)用程序接口的JavaScript對象签餐,能夠使用超文本傳輸協(xié)議連接1個服務(wù)器,是微軟在1999年IE5.0瀏覽器中率先提出的盯串。通過這個對象向服務(wù)器請求額外的數(shù)據(jù)氯檐,去獲取數(shù)據(jù),而無需卸載整個頁面体捏,帶來良好的用戶體驗冠摄。

二、前后端開發(fā)聯(lián)調(diào)需要注意哪些事情几缭?后端接口完成前如何 mock 數(shù)據(jù)河泳?(npm install -g server-mock)

  • 前后端聯(lián)調(diào)
    前后端聯(lián)調(diào)是一種真實業(yè)務(wù)數(shù)據(jù)和本地mock數(shù)據(jù)之間來回切換,以達到前后端分離架構(gòu)下的不同開發(fā)速度時數(shù)據(jù)交換的一種方式方法年栓。需要注意的有:
  • 數(shù)據(jù):需要約定好傳輸?shù)臄?shù)據(jù)以及類型拆挥。
  • 接口:確定接口名稱及請求和響應(yīng)的格式,請求的參數(shù)名稱韵洋、響應(yīng)的數(shù)據(jù)格式竿刁。
  • 后端接口完成前mock 數(shù)據(jù)
  • 可以搭建php本地服務(wù)器,php寫腳本提供臨時數(shù)據(jù)搪缨;
  • 也可使用Mock.js食拜,它能攔截ajax請求并根據(jù)請求中的內(nèi)容來隨機生成符合你要求的假數(shù)據(jù),模擬后端環(huán)境讓你完成對頁面和接口的測試副编。
  • 也可以安裝server-mock這樣的工具负甸,這樣不需要特地去寫一個后臺的處理頁面文件來訪問數(shù)據(jù)。

三痹届、點擊按鈕呻待,使用 ajax 獲取數(shù)據(jù),如何在數(shù)據(jù)到來之前防止重復(fù)點擊?

  • setTimeout + clearTimeout
    連續(xù)的點擊會把上一次點擊清除掉队腐,也就是ajax請求會在最后一次點擊后發(fā)出去蚕捉。
  • disable 按鈕。
  • 給一個flag狀態(tài)柴淘,用戶點擊后變?yōu)閒alse迫淹,在數(shù)據(jù)到來之前不再發(fā)送請求秘通,ajax成功后設(shè)為true。

代碼

一敛熬、封裝一個 ajax 函數(shù)肺稀,能通過如下方式調(diào)用。

function ajax(opts){
    // todo ...
}
document.querySelector('#btn').addEventListener('click', function(){
    ajax({
        url: 'getData.php',   //接口地址
        type: 'get',               // 類型应民, post 或者 get,
        data: {
            username: 'xiaoming',
            password: 'abcd1234'
        },
        success: function(ret){
            console.log(ret);       // {status: 0}
        },
        error: function(){
           console.log('出錯了')
        }
    })
});
function ajax(opts){
  var req = new XMLHttpRequest();
  req.onreadystatechange = function() {
    if(req.readyState == 4 && req.status == 200)
    {
      console.log(req.responseText)
      var json = JSON.parse(req.responseText);
      opts.success(json);
    }
    if(req.readyState == 4 && req.status == 404)
    {
      opts.error();
    }
  }; //事件監(jiān)聽函數(shù)
  var dataStr = '';
  for(var key in opts.data)
  {
    dataStr += key + '=' + opts.data[key] + '&';
  }
  dataStr = dataStr.substr(0, dataStr.length-1); // var re = /&$/g
  if (opts.type.toLowerCase() === 'post')
  {
    req.open(opts.type, opts.url, true);
    req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    req.send(dataStr);
  }
  if(opts.type.toLowerCase() === 'get')
  {
    req.open(opts.type, opts.url + '?' + dataStr, true);
    req.send();
  }
}
document.querySelector('#btn').addEventListener('click', function(){
    ajax({
        url: 'getData.php',   //接口地址
        type: 'get',               // 類型话原, post 或者 get,
        data: {
            username: 'xiaoming',
            password: 'abcd1234'
        },
        success: function(ret){
            console.log(ret);       // {status: 0}
        },
        error: function(){
           console.log('出錯了')
        }
    })
});

二、實現(xiàn)如下加載更多的功能诲锹。

效果如下: 加載更多
使用server mock工具實現(xiàn)繁仁。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>加載更多</title>
</head>
<style>
  *{
    margin: 0;
    padding: 0;
  }
  li{
    list-style: none;
    margin: 8px;
    padding: 4px;
    border: 1px solid #ccc;
    font-size: 25px;
    line-height: 50px;
    cursor: pointer;
  }
  li:hover{
    background: green;
  }
  .btn{
    cursor: pointer;
    padding: 5px;
    margin: 30px 0;
    font-size: 25px;
    line-height: 50px;
    color: purple;
    border: 1px solid red;
    background: #fff;
    outline:none;
  }
  p{
    text-align: center; // 按鈕居中
  }
</style>
<body>
  <ul class="wrap">
    <li>內(nèi)容1</li>
    <li>內(nèi)容2</li>
  </ul>
  <p><button class="btn">加載更多</button></p>

  <script type="text/javascript">
    var wrap = document.querySelector('.wrap');
    var btn = document.querySelector('.btn');
    var current = 3;
    var isLoading = false;
    btn.addEventListener('click', function() {
      if(isLoading)
      {
        return;
      }
      isLoading: true;
      btn.innerText = '正在加載,請稍后...';
      ajax({
        url: '/getMore',
        data: {
          start: current,
          len: 6
        },
        success: function(data) {
          isLoading = false;
          btn.innerText = '加載更多';
          if(data.status == 0)
          {
            getMore(data);
            current += 6;
          }else{
            alert('出錯啦')
          }

        },
        error: function() {
          onError();
        }
      });
    });
    function ajax(opts) {
      var req = new XMLHttpRequest();
      req.onreadystatechange = function () {
        if (req.readyState == 4 && req.status == 200)
        {
          var result = JSON.parse(req.responseText);
          opts.success(result);
        }
        if (req.readyState == 4 && req.status == 404)
        {
          opts.error();
        }
      };
      var filter = '';
      for(var key in opts.data)
      {
        filter += key + '=' + opts.data[key] + '&';
      }
      filter = filter.substr(0, filter.length-1);
      req.open('get', opts.url + '?' + filter, true);
      req.send();
    };
    function getMore(data) {
      var data = data.data;
      for (var i=0; i<data.length; i++)
      {
        var li = document.createElement('li');
        li.innerText = '內(nèi)容' + data[i];
        wrap.appendChild(li);
      }
    }
    function onError() {
      isLoading: false;
      btn.innerText = '加載更多';
      alert('系統(tǒng)異常');
    }
  </script>
</body>
</html>

router.js

app.get('/getMore', function(req, res) {
    // var start = req.query.start,
    //      len = req.query.len;
    var data = [];
    for(var i=0; i<req.query.len; i++)
    {
        data.push(req.query.start++);
    }
    res.send({
        status: 0,
        data: data,
    })
})
請求接收的數(shù)據(jù)
加載更多

三、實現(xiàn)注冊表單驗證功能

效果如下:表單注冊

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>注冊驗證</title>
  <style>
    form{
      font-size: 20px;
    }
    fieldset label {
      float:left;
      width:120px;
      text-align:right;
      padding:4px;
      margin:1px;
    }
    fieldset div {
      clear:left;
      margin:20px 0;
    }
    input{
      height: 35px;
    }
    .help{
      color: #bbb;
    }
    .submit{
      margin-left: 205px;
    }
    .borderRed{
      border: 1px solid red;
    }
  </style>
</head>
<body>
    <h1>注冊</h1>
    <form id="register" action="" method="post" >
      <fieldset>
        <div>
          <label>用戶名:</label>
          <input class="username" type="text" name="username" placeholder="用戶名(hunger被注冊過)">
          <span class="help usernameWarning">只能是字母归园、數(shù)字改备、下劃線,3-10個字符</span>
        </div>
        <div>
          <label>密碼:</label>
          <input class="password" type="password" name="pwd">
          <span class="help pwdWarning">大寫字母蔓倍、小寫、數(shù)字盐捷、下劃線最少兩種偶翅,6-15個字符</span>
        </div>
        <div>
          <label>再輸一次:</label>
          <input class="passwordAgain" type="password" name="pwdAgain" placeholder="再輸入一次密碼">
          <span class="help pwdAgainWarning"></span>
        </div>
        <input class="submit" type="submit" value="注冊"><br/>
      </fieldset>
    </form>
    <script>
      var register = document.querySelector('#register');
      var password = null;
      var submit = document.querySelector('.submit');
      var warning = {
        userExist: "用戶名已經(jīng)存在",
        usernameformatError: "輸入的用戶名格式不正確,請重新填寫碉渡!",
        usernameAvailable: "用戶名可用",
        passwordFormatError: "輸入的密碼格式不正確聚谁,請重新設(shè)置!",
        passwordAvailable: "密碼可用",
        passwordDifferent: "兩次輸入的密碼不一致滞诺!",
      };
      register.addEventListener('focusout', function(e){
        // var className = e.target.className;
        var value = e.target.value;
        var name = e.target.name;
        var className = e.target.className;
        switch(name){
          case 'username':
            checkUser(e, value, className);
            break;
          case 'pwd':
            checkPassword(e, value, className);
            break;
          case 'pwdAgain':
            checkPasswordAgain(e, value, className, password);
            break;
        }
      })
      submit.addEventListener('click', function(e){
        e.preventDefault();
        console.log(document.getElementsByClassName('borderRed'));
        if(document.getElementsByClassName('borderRed').length == 0)
        {
          enroll();
        }
      })
      // 驗證用戶名是否輸入合法
      function checkUser(e, value, className) {
        console.log(e);

        var reg = /^\w{3,10}$/g;
        if(value == "hunger")
        {
          document.querySelector('.usernameWarning').innerText = warning.userExist;
          e.target.className = addClass(className, 'borderRed');
          return false;
        }
        if(!reg.test(value))
        {
          document.querySelector('.usernameWarning').innerText = warning.usernameformatError;
          console.log(document.querySelector('.usernameWarning'));
          console.log(document.getElementsByClassName('username')[0]);
          e.target.className = addClass(className, 'borderRed');
          console.log(className);
          return false;
        }
        if(hasClass(className, 'borderRed'))
        {
          e.target.className = removeClass(className, 'borderRed');
        }
        document.querySelector('.usernameWarning').innerText = warning.usernameAvailable;
        return true;
      }

      // 驗證密碼是否合法  (/\w{,6}|\w{20,}/g).test(value)
      function checkPassword(e, value, className) {
        password = value;
        if((value.length < 6) || (value.length > 15) || ((/[^\w]/g).test(value)) || ((/^[a-z]+$|^[A-Z]+$|^[0-9]+$|^[_]+$/).test(value)))
        {
          document.querySelector('.pwdWarning').innerText = warning.passwordFormatError;
          e.target.className = addClass(className, 'borderRed');
          return false;
        }
        if(hasClass(className, 'borderRed'))
        {
          e.target.className = removeClass(className, 'borderRed');
        }
        document.querySelector('.pwdWarning').innerText = warning.passwordAvailable;
        return true;
      }

      // 兩次密碼是否輸入一致
      function checkPasswordAgain(e, value, className, password) {
        if(value != password)
        {
          console.log(document.querySelector('.passwordAgain'));
          document.querySelector('.pwdAgainWarning').innerText = warning.passwordDifferent;
          e.target.className = addClass(className, 'borderRed');
          return false;
        }
        if(hasClass(className, 'borderRed'))
        {
          e.target.className = removeClass(className, 'borderRed');
        }
        document.querySelector('.pwdAgainWarning').innerText = '';
        return true;
      }

      // 發(fā)送數(shù)據(jù)
      function enroll() {
        ajax({
          url: '/register',
          type: 'post',
          data: {
            username: document.querySelector('.username').value,
            password: document.querySelector('.password').value,
          },
          success: function(list) {
            alert(list.msg);
          },
          error: function() {
            alert("出錯啦");
          }
        })
      }

      function ajax(opts) {
        var req = new XMLHttpRequest();
        req.onreadystatechange = function() {
          if(req.readyState == 4 && req.status == 200)
          {
            var json = JSON.parse(req.responseText);
            opts.success(json);
          }
          if(req.readyState == 4 && req.status == 404)
          {
            opts.error();
          }
        }
        var dataStr = '';
        for (var key in opts.data)
        {
          dataStr += key + '=' + opts.data[key] + '&';
        }
        dataStr = dataStr.substr(0, dataStr.length-1);
        req.open(opts.type, opts.url, true);
        req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        req.send(dataStr);
      }

      function hasClass(className, cls) {
        var reg = new RegExp('(\\s|^)' + cls + '(\\b|$)', 'g');
        return reg.test(className)
      }
      function addClass(className, cls) {
        if (!hasClass(className, cls)) {
          return className += ' ' + cls;
        }
        return className; // 不要忘記return
      }
      function removeClass(className, cls) {
        if (hasClass(className, cls)) {
          var reg = new RegExp('(\\s|^)' + cls + '(\\b|$)', 'g');
          return className = className.replace(reg, '').replace(/\s{2,}/g, ' ');
        }
        return className; // 不要忘記return
     }

    </script>
</body>
</html>

router.js

// 注冊
app.post('/register', function(req, res) {
    // var start = req.query.start,
    //      len = req.query.len;
    res.send({
        status: 0,
        msg: "恭喜你形导,注冊成功!",
    })
})
請求接受的數(shù)據(jù)

注冊
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末习霹,一起剝皮案震驚了整個濱河市朵耕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淋叶,老刑警劉巖阎曹,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異煞檩,居然都是意外死亡处嫌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門斟湃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熏迹,“玉大人,你說我怎么就攤上這事凝赛∽担” “怎么了坛缕?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長友存。 經(jīng)常有香客問我祷膳,道長,這世上最難降的妖魔是什么屡立? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任直晨,我火速辦了婚禮,結(jié)果婚禮上膨俐,老公的妹妹穿的比我還像新娘勇皇。我一直安慰自己,他們只是感情好焚刺,可當(dāng)我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布敛摘。 她就那樣靜靜地躺著,像睡著了一般乳愉。 火紅的嫁衣襯著肌膚如雪兄淫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天蔓姚,我揣著相機與錄音捕虽,去河邊找鬼。 笑死坡脐,一個胖子當(dāng)著我的面吹牛泄私,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播备闲,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼晌端,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了恬砂?” 一聲冷哼從身側(cè)響起咧纠,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎觉既,沒想到半個月后惧盹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡瞪讼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年钧椰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片符欠。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡嫡霞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出希柿,到底是詐尸還是另有隱情诊沪,我是刑警寧澤养筒,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站端姚,受9級特大地震影響晕粪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜渐裸,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一巫湘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧昏鹃,春花似錦尚氛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至载迄,卻和暖如春讯柔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背护昧。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工磷杏, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人捏卓。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像慈格,于是被迫代替她去往敵國和親怠晴。 傳聞我的和親對象是個殘疾皇子饺谬,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,612評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 瀏覽器與服務(wù)器之間频丘,采用HTTP協(xié)議通信。用戶在瀏覽器地址欄鍵入一個網(wǎng)址膜廊,或者通過網(wǎng)頁表單向服務(wù)器提交內(nèi)容选泻,這時瀏...
    徐國軍_plus閱讀 362評論 0 4
  • AJAX 原生js操作ajax 1.創(chuàng)建XMLHttpRequest對象 var xhr = new XMLHtt...
    碧玉含香閱讀 3,186評論 0 7
  • 關(guān)鍵詞:Ajax 1. Ajax 是什么冲粤?有什么作用? Ajax 全稱“Asynchronous Javascri...
    NathanYangcn閱讀 315評論 0 0
  • 問答 1. ajax 是什么页眯?有什么作用梯捕? Ajax是Asynchronous JavaScript and XM...
    Maggie_77閱讀 399評論 0 0
  • 1. ajax 是什么?有什么作用窝撵? Ajax(['eid??ks])是Asynchronous JavaScri...
    曉風(fēng)殘月1994閱讀 374評論 0 0