乐趣区

关于vue.js:04Vue之前后端交互

接口调用形式

  • 原生 ajax
  • 基于 jQuery 的 ajax
  • fetch
  • axios

异步

  • JavaScript 的执行环境是「单线程」
  • 所谓单线程,是指 JS 引擎中负责解释和执行 JavaScript 代码的线程只有一个,也就是一次只能实现一项工作,这个工作执行完后能力执行下一个,它会「阻塞」其余工作。这个工作可称为主线程
  • 异步模式能够一起执行 多个工作
  • JS 中常见的异步调用

    • 定时任何
    • ajax
    • 事件函数

promise

  • 次要解决异步深层嵌套的问题
  • promise 提供了简洁的 API 使得异步操作更加容易
 
  <script type="text/javascript">
    /*
     1. Promise 根本应用
           咱们应用 new 来构建一个 Promise  Promise 的构造函数接管一个参数,是函数,并且传入两个参数:resolve,reject,别离示意异步操作执行胜利后的回调函数和异步操作执行失败后的回调函数
    */


    var p = new Promise(function(resolve, reject){
      //2. 这里用于实现异步工作  setTimeout
      setTimeout(function(){
        var flag = false;
        if(flag) {
          //3. 失常状况
          resolve('hello');
        }else{
          //4. 异常情况
          reject('出错了');
        }
      }, 100);
    });
    //  5 Promise 实例生成当前,能够用 then 办法指定 resolved 状态和 reject 状态的回调函数 
    //  在 then 办法中,你也能够间接 return 数据而不是 Promise 对象,在前面的 then 中就能够接管到数据了  
    p.then(function(data){console.log(data)
    },function(info){console.log(info)
    });
  </script>

基于 Promise 发送 Ajax 申请

 
  <script type="text/javascript">
    /*
      基于 Promise 发送 Ajax 申请
    */
    function queryData(url) {
     #   1.1 创立一个 Promise 实例
      var p = new Promise(function(resolve, reject){var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            # 1.2 解决失常的状况
            resolve(xhr.responseText);
          }else{
            # 1.3 解决异常情况
            reject('服务器谬误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
      return p;
    }
    # 留神:这里须要开启一个服务 
    # 在 then 办法中,你也能够间接 return 数据而不是 Promise 对象,在前面的 then 中就能够接管到数据了
    queryData('http://localhost:3000/data')
      .then(function(data){console.log(data)
        #  1.4 想要持续链式编程上来 须要 return  
        return queryData('http://localhost:3000/data1');
      })
      .then(function(data){console.log(data);
        return queryData('http://localhost:3000/data2');
      })
      .then(function(data){console.log(data)
      });
  </script>

服务器端
pip install

Flask==1.1.1
Flask-Cors==3.0.8
from flask import Flask, jsonify, request
from flask_cors import CORS

# 创立应用程序对象
app = Flask(__name__)
# pip install Flask-Cors
CORS(app)

@app.route('/data')
def hello():
    '''hello 申请'''
    # 间接返回字符串
    return 'Hello, data'
@app.route('/data1')
def hello1():
    '''hello 申请'''
    # 间接返回字符串
    return 'Hello, data1'
@app.route('/data2')
def hello2():
    '''hello 申请'''
    # 间接返回字符串
    return 'Hello, data2'

if __name__ == '__main__':
    # 以 debug 模式启动程序
    app.run(debug = True)

Promise 根本 API

实例办法

.then()
  • 失去异步工作正确的后果
.catch()
  • 获取异样信息
.finally()
  • 胜利与否都会执行(不是正式规范)
  
  <script type="text/javascript">
    /*
      Promise 罕用 API- 实例办法
    */
    // console.dir(Promise);
    function foo() {return new Promise(function(resolve, reject){setTimeout(function(){// resolve(123);
          reject('error');
        }, 100);
      })
    }
    // foo()
    //   .then(function(data){//     console.log(data)
    //   })
    //   .catch(function(data){//     console.log(data)
    //   })
    //   .finally(function(){//     console.log('finished')
    //   });

    // --------------------------
    // 两种写法是等效的
    foo()
      .then(function(data){
        # 失去异步工作正确的后果
        console.log(data)
      },function(data){
        # 获取异样信息
        console.log(data)
      })
      # 胜利与否都会执行(不是正式规范).finally(function(){console.log('finished')
      });
  </script>

静态方法

.all()
  • Promise.all办法承受一个数组作参数,数组中的对象(p1、p2、p3)均为 promise 实例(如果不是一个 promise,该项会被用 Promise.resolve 转换为一个 promise)。它的状态由这三个 promise 实例决定
.race()
  • Promise.race办法同样承受一个数组作参数。当 p1, p2, p3 中有一个实例的状态产生扭转(变为 fulfilledrejected),p 的状态就跟着扭转。并把第一个扭转状态的 promise 的返回值,传给 p 的回调函数

  <script type="text/javascript">
    /*
      Promise 罕用 API- 对象办法
    */
    // console.dir(Promise)
    function queryData(url) {return new Promise(function(resolve, reject){var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            // 解决失常的状况
            resolve(xhr.responseText);
          }else{
            // 解决异常情况
            reject('服务器谬误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
    }

    var p1 = queryData('http://localhost:3000/a1');
    var p2 = queryData('http://localhost:3000/a2');
    var p3 = queryData('http://localhost:3000/a3');
     Promise.all([p1,p2,p3]).then(function(result){//   all 中的参数  [p1,p2,p3]   和 返回的后果一 一对应["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
       console.log(result) //["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
     })
    Promise.race([p1,p2,p3]).then(function(result){// 因为 p1 执行较快,Promise 的 then()将取得后果 'P1'。p2,p3 仍在继续执行,但执行后果将被抛弃。console.log(result) // "HELLO TOM"
    })
  </script>

fetch

  • Fetch API 是新的 ajax 解决方案 Fetch 会返回 Promise
  • fetch 不是 ajax 的进一步封装,而是原生 js,没有应用 XMLHttpRequest 对象
  • fetch(url, options).then()
  <script type="text/javascript">
    /*
      Fetch API 根本用法
          fetch(url).then()
         第一个参数申请的门路   Fetch 会返回 Promise   所以咱们能够应用 then 拿到申请胜利的后果 
    */
    fetch('http://localhost:3000/fdata').then(function(data){// text()办法属于 fetchAPI 的一部分,它返回一个 Promise 实例对象,用于获取后盾返回的数据
      return data.text();}).then(function(data){
      //   在这个 then 外面咱们能拿到最终的数据  
      console.log(data);
    })
  </script>

fetch API 中的 HTTP 申请

  • fetch(url, options).then()
  • HTTP 协定,它给咱们提供了很多的办法,如 POST,GET,DELETE,UPDATE,PATCH 和 PUT

    • 默认的是 GET 申请
    • 须要在 options 对象中 指定对应的 method method: 申请应用的办法
    • post 和 一般 申请的时候 须要在 options 中 设置 申请头 headers 和 body
   <script type="text/javascript">
           /*
              Fetch API 调用接口传递参数
        */
    fetch('http://localhost:5000/books?id=123', {method: 'get'})
    .then(function(data) {return data.text();
    }).then(function(data) {console.log(data)
    });

    fetch('http://localhost:5000/books/456', {method: 'get'})
    .then(function(data) {return data.text();
    }).then(function(data) {console.log(data)
    });
    //
    fetch('http://localhost:5000/books/789', {method: 'delete'})
        .then(function(data) {return data.text();
        }).then(function(data) {console.log(data)
    });
    //
    fetch('http://localhost:5000/books', {
        method: 'post',
    body: 'uname=lisi&pwd=123',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    })
    .then(function(data) {return data.text();
    }).then(function(data) {console.log(data)
    });
    //
    fetch('http://localhost:5000/books_json', {
        method: 'post',
        body: JSON.stringify({
            uname: '张三',
            pwd: '456'
        }),
        headers: {'Content-Type': 'application/json'}
    })
        .then(function(data) {return data.text();
        }).then(function(data) {console.log(data)
    });
    //
    fetch('http://localhost:5000/books/123', {
        method: 'put',
        body: JSON.stringify({
            uname: '张三',
            pwd: '789'
        }),
        headers: {'Content-Type': 'application/json'}
    })
        .then(function(data) {return data.text();
        }).then(function(data) {console.log(data)
    });
    </script>

后盾代码:

from flask import Flask, jsonify, request
from flask_cors import CORS

# 创立应用程序对象
app = Flask(__name__)
# pip install Flask-Cors
CORS(app)

@app.route('/books',methods=["GET","POST"])
def hello():
    '''hello 申请'''
    # 间接返回字符串
    if request.method == 'GET':
        return request.args['id']
    elif request.method == 'POST':
        return request.form['uname']

@app.route('/books/<string:id>')
def hello1(id):
    '''hello 申请'''
    # 间接返回字符串
    return id
@app.route('/books/<string:id>',methods=["DELETE"])
def hello2(id):
    '''hello 申请'''
    # 间接返回字符串
    return id

@app.route('/books_json',methods=["POST"])
def books_json():
    '''hello 申请'''
    # 间接返回字符串
    if request.method == 'POST':
        return request.json

@app.route('/books/<string:id>',methods=["PUT"])
def books_put_json(id):
    '''hello 申请'''
    # 间接返回字符串
    return request.json

if __name__ == '__main__':
    # 以 debug 模式启动程序
    app.run(debug = True)

fetchAPI 中 响应格局

  • 用 fetch 来获取数据,如果响应失常返回,咱们首先看到的是一个 response 对象,其中包含返回的一堆原始字节,这些字节须要在收到后,须要咱们通过调用办法将其转换为相应格局的数据,比方 JSONBLOB 或者 TEXT 等等

    /*
      Fetch 响应后果的数据格式
    */
    fetch('http://localhost:3000/json').then(function(data){// return data.json();   //  将获取到的数据应用 json 转换对象
      return data.text(); //  //  将获取到的数据 转换成字符串}).then(function(data){// console.log(data.uname)
      // console.log(typeof data)
      var obj = JSON.parse(data);
      console.log(obj.uname,obj.age,obj.gender)
    })

axios

  • 基于 promise 用于浏览器和 node.js 的 http 客户端
  • 反对浏览器和 node.js
  • 反对 promise
  • 能拦挡申请和响应
  • 主动转换 JSON 数据
  • 能转换申请和响应数据

axios 根底用法

  • get 和 delete 申请传递参数

    • 通过传统的 url 以 ? 的模式传递参数
    • restful 模式传递参数
    • 通过 params 模式传递参数
  • post 和 put 申请传递参数

    • 通过选项传递参数
    • 通过 URLSearchParams 传递参数
    # 1. 发送 get 申请 
    axios.get('http://localhost:3000/adata').then(function(ret){ 
      #  拿到 ret 是一个对象      所有的对象都存在 ret 的 data 属性外面
      // 留神 data 属性是固定的用法,用于获取后盾的理论数据
      // console.log(ret.data)
      console.log(ret)
    })
    # 2.  get 申请传递参数
    # 2.1  通过传统的 url  以 ? 的模式传递参数
    axios.get('http://localhost:3000/axios?id=123').then(function(ret){console.log(ret.data)
    })
    # 2.2  restful 模式传递参数 
    axios.get('http://localhost:3000/axios/123').then(function(ret){console.log(ret.data)
    })
    # 2.3  通过 params  模式传递参数 
    axios.get('http://localhost:3000/axios', {
      params: {id: 789}
    }).then(function(ret){console.log(ret.data)
    })
    #3 axios delete 申请传参     传参的模式和 get 申请一样
    axios.delete('http://localhost:3000/axios', {
      params: {id: 111}
    }).then(function(ret){console.log(ret.data)
    })

    # 4  axios 的 post 申请
    # 4.1  通过选项传递参数
    axios.post('http://localhost:3000/axios', {
      uname: 'lisi',
      pwd: 123
    }).then(function(ret){console.log(ret.data)
    })
    # 4.2  通过 URLSearchParams  传递参数 
    var params = new URLSearchParams();
    params.append('uname', 'zhangsan');
    params.append('pwd', '111');
    axios.post('http://localhost:3000/axios', params).then(function(ret){console.log(ret.data)
    })

     #5  axios put 申请传参   和 post 申请一样 
    axios.put('http://localhost:3000/axios/123', {
      uname: 'lisi',
      pwd: 123
    }).then(function(ret){console.log(ret.data)
    })

axios 全局配置

#  配置公共的申请头 
axios.defaults.baseURL = 'https://api.example.com';
#  配置 超时工夫
axios.defaults.timeout = 2500;
#  配置公共的申请头
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
# 配置公共的 post 的 Content-Type
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

axios 拦截器

  • 申请拦截器

    • 申请拦截器的作用是在申请发送前进行一些操作

      • 例如在每个申请体里加上 token,对立做了解决如果当前要改也非常容易
  • 响应拦截器

    • 响应拦截器的作用是在接管到响应后进行一些操作

      • 例如在服务器返回登录状态生效,须要从新登录的时候,跳转到登录页
    # 1. 申请拦截器 
    axios.interceptors.request.use(function(config) {console.log(config.url)
      # 1.1  任何申请都会通过这一步   在发送申请之前做些什么   
      config.headers.mytoken = 'nihao';
      # 1.2  这里肯定要 return   否则配置不胜利  
      return config;
    }, function(err){
       #1.3 对申请谬误做点什么    
      console.log(err)
    })
    #2. 响应拦截器 
    axios.interceptors.response.use(function(res) {
      #2.1  在接管响应做些什么  
      var data = res.data;
      return data;
    }, function(err){
      #2.2 对响应谬误做点什么  
      console.log(err)
    })

async 和 await

  • async 作为一个关键字放到函数后面

    • 任何一个 async 函数都会隐式返回一个promise
  • await关键字只能在应用 async 定义的函数中应用

    • ​ await 前面能够间接跟一个 Promise 实例对象
    • ​ await 函数不能独自应用
  • async/await 让异步代码看起来、体现起来更像同步代码
     # 1.  async 根底用法
    # 1.1 async 作为一个关键字放到函数后面
    async function queryData() {
      # 1.2 await 关键字只能在应用 async 定义的函数中应用      await 前面能够间接跟一个 Promise 实例对象
      var ret = await new Promise(function(resolve, reject){setTimeout(function(){resolve('nihao')
        },1000);
      })
      // console.log(ret.data)
      return ret;
    }
    # 1.3 任何一个 async 函数都会隐式返回一个 promise   咱们能够应用 then 进行链式编程
    queryData().then(function(data){console.log(data)
    })

    #2.  async    函数解决多个异步函数
    axios.defaults.baseURL = 'http://localhost:3000';

    async function queryData() {
      # 2.1  增加 await 之后 以后的 await 返回后果之后才会执行前面的代码   
      
      var info = await axios.get('async1');
      #2.2  让异步代码看起来、体现起来更像同步代码
      var ret = await axios.get('async2?info=' + info.data);
      return ret.data;
    }

    queryData().then(function(data){console.log(data)
    })

图书列表案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" type="text/css" href="css/index.css">
</head>
<body>
  <div id="app">
    <div class="grid">
      <div>
        <h1> 图书治理 </h1>
        <div class="book">
          <div>
            <label for="id">
              编号:</label>
            <input type="text" id="id" v-model='id' disabled="false" v-focus>
            <label for="name">
              名称:</label>
            <input type="text" id="name" v-model='name'>
            <button @click='handle' :disabled="submitFlag"> 提交 </button>
          </div>
        </div>
      </div>
      <div class="total">
        <span> 图书总数:</span>
        <span>{{total}}</span>
      </div>
      <table>
        <thead>
          <tr>
            <th> 编号 </th>
            <th> 名称 </th>
            <th> 工夫 </th>
            <th> 操作 </th>
          </tr>
        </thead>
        <tbody>
          <tr :key='item.id' v-for='item in books'>
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.date | format}}</td>
            <td>
              <a href=""@click.prevent='toEdit(item.id)'> 批改 </a>
              <span>|</span>
              <a href=""@click.prevent='deleteBook(item.id)'> 删除 </a>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
  <script type="text/javascript" src="js/vue.js"></script>
  <script type="text/javascript" src="js/axios.js"></script>
  <script type="text/javascript">
    /*
      图书治理 - 增加图书
    */
    axios.defaults.baseURL = 'http://localhost:5000/';
    axios.interceptors.response.use(function(res){return res.data;}, function(error){console.log(error)
    });
    Vue.directive('focus', {inserted: function (el) {el.focus();
      }
    });

    Vue.filter('format',(dataStr) => {var time = new Date(dataStr);
        function timeAdd0(str) {if(str<10){str='0'+str;}
            return str
        }
        var y = time.getFullYear();
        var m = time.getMonth()+1;
        var d = time.getDate();
        var h = time.getHours();
        var mm = time.getMinutes();
        var s = time.getSeconds();
        return y+'-'+timeAdd0(m)+'-'+timeAdd0(d)+''+timeAdd0(h)+':'+timeAdd0(mm)+':'+timeAdd0(s);
    })


    var vm = new Vue({
      el: '#app',
      data: {
        flag: false,
        submitFlag: false,
        id: '',
        name: '',
        books: []},
      methods: {handle: async function(){if(this.flag) {
            // 编辑图书
            var ret = await axios.put('books/' + this.id, {name: this.name});
            if(ret.status == 200){
              // 从新加载列表数据
              this.queryData();}
            this.flag = false;
          }else{
            // 增加图书
            var ret = await axios.post('books', {name: this.name})
            if(ret.status == 200) {
              // 从新加载列表数据
              this.queryData();}
          }
          // 清空表单
          this.id = '';
          this.name = '';
        },
        toEdit: async function(id){
          // flag 状态位用于辨别编辑和增加操作
          this.flag = true;
          // 依据 id 查问出对应的图书信息
          var ret = await axios.get('books/' + id);
          this.id = ret.id;
          this.name = ret.name;
        },
        deleteBook: async function(id){
          // 删除图书
          var ret = await axios.delete('books/' + id);
           console.log(ret)
          if(ret.status == 200) {
            // 从新加载列表数据
            this.queryData();}
        },
        queryData: async function(){
          // 调用后盾接口获取图书列表数据
          // var ret = await axios.get('books');
          // this.books = ret.data;

          this.books = await axios.get('books');
        }
      },
      computed: {total: function(){
          // 计算图书的总数
          return this.books.length;
        }
      },
      watch: {name: async function(val) {
          // 验证图书名称是否曾经存在
          var ret = await axios.get('/books/book/' + this.name);
          // console.log(ret)
          if(ret.status == 1) {
            // 图书名称存在
            this.submitFlag = true;
          }else{
            // 图书名称不存在
            this.submitFlag = false;
          }
        }
      },
      mounted: function(){this.queryData();
      }
    });
  </script>
</body>
</html>

.grid {
  margin: auto;
  width: 530px;
  text-align: center;
}
.grid table {
  border-top: 1px solid #C2D89A;
  width: 100%;
  border-collapse: collapse;
}
.grid th,td {
  padding: 10;
  border: 1px dashed #F3DCAB;
  height: 35px;
  line-height: 35px;
}
.grid th {background-color: #F3DCAB;}
.grid .book {
  padding-bottom: 10px;
  padding-top: 5px;
  background-color: #F3DCAB;
}
.grid .total {
  height: 30px;
  line-height: 30px;
  background-color: #F3DCAB;
  border-top: 1px solid #C2D89A;
}

后盾代码:

# coding:utf-8
import time

from flask import Flask, jsonify, request
from flask_cors import CORS

bookdata = [
    {
        "id": 1,
        "name": "红楼梦",
        "date": 2525609975000
    },
    {
        "name": "三国演义",
        "date": 2525609975000,
        "id": 2
    },
    {
        "name": "水浒传",
        "date": 2525609975000,
        "id": 3
    },

    {
        "name": "西游记",
        "date": 2525609975000,
        "id": 4
    }
]
last_id = len(bookdata) + 1
# 创立应用程序对象
app = Flask(__name__)
# pip install Flask-Cors
CORS(app)
@app.route('/')
def hello():
    '''hello 申请'''
    # 间接返回字符串
    return 'Hello, Flask World!'

@app.route('/books', methods=["GET","POST"])
def books():
    global last_id
    if request.method == 'GET':
        # 间接返回字符串
        return jsonify(bookdata)
    elif request.method == 'POST':
        body = request.json
        print(body['name'])
        book = {}
        book['id'] = last_id
        book['name'] = body['name']
        book['date'] = int(time.time()*1000)
        bookdata.append(book)
        last_id+=1
        return jsonify({'status': 200})

@app.route('/books/book/<string:name>', methods=["GET"])
def check_bookname(name):
    print('check_bookname' + name)
    if name in [book['name'] for book in bookdata]:
        return jsonify({'status': 1})
    else:
        return jsonify({'status': 0})

@app.route('/books/book/', methods=["GET"])
def check_empty_bookname():
    print('check_empty_bookname')
    return jsonify({'status': 0})


@app.route('/books/<string:id>', methods=["GET","PUT","DELETE"])
def manage_bookinfo(id):
    global bookdata
    if request.method == 'GET':
        books = list(filter(lambda x: x['id'] == int(id), bookdata))
        return jsonify(books[0])
    elif request.method == 'PUT':
        body = request.json
        books = list(filter(lambda x: x['id'] == int(id), bookdata))
        book = books[0]
        book['name'] = body['name']
        return jsonify({'status': 200})
    elif request.method == 'DELETE':
        body = request.json
        books = list(filter(lambda x: x['id'] != int(id), bookdata))
        bookdata = books
        return jsonify({'status': 200})

if __name__ == '__main__':
    # 以 debug 模式启动程序
    app.run(debug = True)
退出移动版