菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
0
0

Vue全家桶 - 前后端交互+接口调用方法(fetch、axios、async/await)

原创
05/13 14:22
阅读数 189

1. 前后端交互模式

前后端交互:前端页面通过工具调用后端接口,拿到数据库中的数据,然后在做前端页面的渲染。

什么是前端? 什么是后端? 什么是数据库?
图片.png

图片.png

1.1 前端调用后端接口的方式

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

1.2 URL地址格式

1.2.1.传统形式的URL

● 格式:schema://host:port/path?query#fragment
—1、schema:协议。例如http,https,ftp等
—2、host:域名或者IP地址
—3、port:端口,http默认端口80,可以省略
—4、@path:路径,例如/abc/a/b/c
—5、query:查询参数,例如uname=lisi&age=120
—6、fragment:锚点(哈希Hash),用于定位页面的某个位置

● 符合规则的URL
—1、http://www.lmonkey.com
—2、http://www.lmonkey.com/java/web
—3、http://www.lmonkey.com/java/web?flag=1
—4、http://www.lmonkey.com/java/web?flag=1#function

1.2.2.Restful形式的URL

● HTTP请求方式
—1、GET 查询
—2、POST 添加
—3、PUT 修改
—4、DELETE 删除

● 符合规则的URL地址
—1、http://www.hello.com/books GET
—2、http://www.hello.com/books POST
—3、http://www.hello.com/books/123 PUT
—4、http://www.hello.com/books/123 DELETE

2. Promise用法

2.1 异步调用

● 异步场景
① 定时任务
② Ajax
③ 事件函数

● 多次异步调用的依赖分析
多次异步调用的结果顺序不确定, 异步调用结果如果存在依赖需要嵌套,嵌套太多会形成回调地狱

回调地狱:一个异步请求套着一个异步请求,一个异步请求依赖于另一个的执行结果,使用回调的方式相互嵌套,代码可读性低、编写费劲、不方便后期维护

2.2 Promise概述

Promise :ES6引入的异步编程的新解决方案,语法是一个构造函数 ,用来封装异步操作并可以获取其成功或失败的结果. resolve和reject两个参数用于处理成功和失败两种情况,并通过p.then获取处理结果

Promise 中的异步体现在then和catch中,所以写在 Promise 中的代码是被当做同步任务立即执行的。

//手写一个promise模板
var promise = new Promise((resolve,reject) => {
    if (操作成功) {
        resolve(value)
    } else {
        reject(error)
    }
})
promise.then(function (value) {
    // success
},function (error) {
    // failure
})

Promise对象有三种状态:初始化pending 成功fulfilled 失败rejected
● Promise 就是一个对象,用来表示并传递异步操作的最终结果
● Promise {: PromiseResult} PromiseState:状态 PromiseResult:返回值
● Promise 最主要的交互方式:将回调函数传入 then 方法来获得最终结果或出错原因
● Promise 代码书写上的表现:以“链式调用”代替回调函数层层嵌套(回调地狱)p.then().then()

使用Promise主要有以下好处:
● 可以避免多层异步调用嵌套问题(回调地狱)
● Promise对象提供了简洁的API,使得控制异步操作更加容易

//02-Promise基本使用.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script type='text/javascript'>
    var p = new Promise( (resolve, reject) =>{
      //这里用于实现异步任务
      setTimeout(function () {
        var flag = true;
        if (flag) {
          //正常情况
          resolve('hello')
        } else {
          //异常情况
          reject('出错了')
        }
      }, 1000)
    });
 	p.then(function (value) {
        console.log(value);
      },
      function (error) {
        console.log(error);
      })
  </script>
</body>

</html>

2.3 基于Promise处理Ajax请求

2.3.1.Promise封装原生Ajax

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>

<body>
  <script type="text/javascript">
    function queryData(url) {
		return new Promise( (resolve, reject) =>{
        //原生请求
        //1.创建Ajax对象
        const xhr = new XMLHttpRequest();
        //2.初始化
        xhr.open('get', url);
        //3.发送请求
        xhr.send()
        //4.绑定事件,处理响应结果
        xhr.onreadystatechange = function () {
          //判断状态
          if (xhr.readyState == 4) {
            //判断响应状态码200-299
            if (xhr.status >= 200 && xhr.status <= 299) {
              //成功
              resolve(xhr.response)
            } else {
              //失败
              reject(xhr.status)
            }
          }
        }
      })
    };
    queryData('http://localhost:3000/data')
      .then(function (value) {
        console.log(value);
      }).then(function (error) {
        console.log(error);
      })
  </script>
</body>

</html>
//index.js
//引入express框架
const express = require('express')
//创建网站服务器
const app = express()
//引入接收post请求参数第三方包 `body-parser`。
const bodyParser = require('body-parser')
// 处理静态资源
//app.use 匹配所有的请求方式,可以直接传入请求处理函数,代表接收所有的请求。
app.use(express.static('public'))
// 处理参数
app.use(bodyParser.json());
// 配置body-parser模块
app.use(bodyParser.urlencoded({
  extended: false
}));

// 设置允许跨域访问该服务
app.all('*', function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
  res.header("Access-Control-Allow-Headers", "X-Requested-With");
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  res.header('Access-Control-Allow-Headers', 'mytoken');
  next();
});
// 路由
 //中间件示例
//app.get('请求路径', '处理函数') // 接收并处理get请求
//当客户端以get方式访问/data路由
app.get('/data', (req, res) => {
    //对客户端做出响应
  res.send('Hello World!')
})
app.get('/data1', (req, res) => {
  setTimeout(function () {
    res.send('Hello TOM!')
  }, 1000);
})
app.get('/data2', (req, res) => {
  res.send('Hello JERRY!')
})

// 启动监听
app.listen(3000, () => {
  console.log('服务器启动成功')
})

图片.png

图片.png

2.3.2.发送多个ajax请求并保证顺序

    queryData('http://localhost:3000/data')
      .then(function(data){
        console.log(data)
        return queryData('http://localhost:3000/data1');
      })
      .then(function(data){
        console.log(data);
        return queryData('http://localhost:3000/data2');
      })
      .then(function(data){
        console.log(data)
      });

图片.png

2.4 then参数中的函数返回值

2.4.1.返回Promise实例对象

返回的该实例对象会调用下一个then,得到上一步的处理结果

2.4.2.返回普通值

返回的普通值会直接传递给下一个then,通过then参数中函数的参数接收该值

queryData('http://localhost:3000/data')
      .then(function(data){
        return queryData('http://localhost:3000/data1');
      })
      .then(function(data){
      //返回Promise实例对象
        return new Promise(function(resolve, reject){
          setTimeout(function(){
            resolve(123);
          },1000)
        });
      })
	// 返回的该实例对象会调用下一个then
      .then(function(data){
        console.log(data)//123
      })
   queryData('http://localhost:3000/data')
      .then(function(data){
        return queryData('http://localhost:3000/data1');
      })
	  //返回普通值
      .then(function(data){
        return 'hello';
      })
      //回的普通值会直接传递给下一个then,通过then参数中函数的参数接收该值
      .then(function(data){
        console.log(data)//hello
      })

2.5 Promise常用的API

2.5.1.实例方法

● p.then()得到异步任务的正确结果
● p.catch()获取异常信息
● p.finally()成功与否都会执行

  //p.then()得到异步任务的正确结果
.then(function(data){
     console.log(data)
   })
//p.catch()获取异常信息
   .catch(function(data){
     console.log(data)
   })
//p.finally()成功与否都会执行
  .finally(function(){
     console.log('finished')
   });

2.5.2.对象方法

● Promise.all()并发处理多个异步任务,所有任务都执行完成才能得到结果
● Promise.race()并发处理多个异步任务,只要有一个任务完成就能得到结果

    Promise.all([p1, p2, p3]).then(function (result) {
      console.log(result)
    })
    Promise.race([p1, p2, p3]).then(function (result) {
      console.log(result)
    })

3. 接口调用-fetch用法

3.1 fetch概述

3.1.1.基本特性

● 更加简单的数据获取方式,功能更强大、更灵活,可以看做是ajax的升级版
● 基于Promise实现

3.1.2.语法结构

  //通过fetchAPI调用接口,通过then获取数据
fetch(url).then(fn2)
		    .then(fn3)
			...
            .catch(fn)

3.2 fetch的基本用法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>

  <body>
    <script type="text/javascript">
      fetch("http://localhost:3000/fdata")
        .then(function (data) {
          // text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后台返回的数据
          return data.text();
        })
        .then(function (data) {
          console.log(data);
        });
    </script>
  </body>
</html>
//路由
app.get('/fdata', (req, res) => {
  res.send('Hello Fetch!')
})

3.3 fetch请求参数

3.3.1.常用配置选项

● method(String):HTTP请求方法,默认为GET(GET,POST,PUT,DELETE增删改查)
● body(String):HTTP的请求参数
● headers(Object):HTTP的请求头,默认为{ }

fetch('/abc",{
	method:'get'
}).then(data=>(
return data.text();
1).then(ret=>{
//注意这里得到的才是最终的数据
console.log(ret);
};

3.3.2.GET请求方式的参数传递

    // GET参数传递-传统URL
   fetch('http://localhost:3000/books?id=123', {
       //默认为get可以不添加
       method: 'get'
     })
       .then(function(data){
         return data.text();
       }).then(function(data){
         console.log(data)
       });

    // GET参数传递-restful形式的URL 通过/传递参数
     fetch('http://localhost:3000/books/456', {
       method: 'get'
     })
       .then(function(data){
         return data.text();
       }).then(function(data){
         console.log(data)
       });
//路由
app.get('/books', (req, res) => {
    //req.query获取get 请求方式
  res.send('传统的URL传递参数!' + req.query.id)
})

//id为占位符,表示当前路由要接受一个id作为参数
//req.param适用于restful风格url中的参数的解析
app.get('/books/:id', (req, res) => {
  res.send('Restful形式的URL传递参数!' + req.params.id)
})

3.3.3.DELETE请求方式的参数传递

   // DELETE请求方式参数传递
    fetch('http://localhost:3000/books/789', {
      method: 'delete'
     })
      .then(function(data){
        return data.text();
       }).then(function(data){
         console.log(data)
      });
//路由
app.delete('/books/:id', (req, res) => {
  res.send('DELETE请求传递参数!' + req.params.id)
})

3.3.4.POST请求方式的参数传递

  // POST请求传参
     fetch('http://localhost:3000/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)
       });
   // POST请求传参
     fetch('http://localhost:3000/books', {
      method: 'post',
      //转换为JSON字符串
       body: JSON.stringify({
       uname: '张三',
         pwd: '456'
      }),
       headers: {
           //json格式数据
         'Content-Type': 'application/json'
       }
     })
       .then(function(data){
         return data.text();
       }).then(function(data){
        console.log(data)
       });
//路由
app.post('/books', (req, res) => {
  res.send('POST请求传递参数!' + req.body.uname + '---' + req.body.pwd)
})

3.3.5.PUT请求方式的参数传递

 //PUT请求传参 一般用于修改数据 /123为需要修改的数据
fetch('http://localhost:3000/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)
      });
//路由
app.put('/books/:id', (req, res) => {
  res.send('PUT请求传递参数!' + req.params.id + '---' + req.body.uname + '---' + req.body.pwd)
})

3.4 fetch响应结果

响应数据格式
● text():将返回体处理成字符串类型
● json():返回结果和JSON.parse(responseText)一样 对象类型

fetch('/abc' then(data=>{
	//return data text();
	return data.json();
}).then(data=>{
	console.log(data)
})

4. 接口调用-axios用法

4.1 axios概述

axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中(专用用于调用后台接口的库)

它具有以下特征:
● 支持浏览器和node.js
● 支持promise
● 能拦截请求和响应
● 自动转换JSON数据

4.2 axios的基本用法

    axios.get('http://localhost:3000/adata')
    .then(function(ret){
      // 注意data属性是固定的用法,用于获取后台的实际数据
      // console.log(ret.data)
      console.log(ret)
    })
//路由
app.get('/adata', (req, res) => {
  res.send('Hello axios!')
})

4.3 axios的常用API

● get:查询数据
● post:添加数据
● put:修改数据
● delete:删除数据

4.3.1.GET参数

● 通过URL传递参数
● 通过params选项传递参数

    // axios get请求传参
    //通过URL传递参数
	//下面两种都可以
     axios.get('http://localhost:3000/axios?id=123')
     .then(function(ret){
       console.log(ret.data)
     })
     axios.get('http://localhost:3000/axios/123')
     .then(function(ret){
       console.log(ret.data)
     })
     //通过params选项传递参数
     axios.get('http://localhost:3000/axios', {
       params: {
         id: 789
       }
     }).then(function(ret){
       console.log(ret.data)
     })
 	//路由
app.get('/axios', (req, res) => {
  res.send('axios get 传递参数' + req.query.id)
})
app.get('/axios/:id', (req, res) => {
  res.send('axios get (Restful) 传递参数' + req.params.id)
})

4.3.2.DELETE参数

● 参数传递方式与GET类似

4.3.3.POST参数

● 通过选项传递参数(默认传递的是json格式的数据)
● 通过URLSearchParams传递参数(application/x-www-form-urlencoded)

JSON样例:首先一个花括号{ },整个代表一个对象,同时里面是一种Key-Value的存储形式,它还有不同的数据类型来区分

   //通过选项传递参数
	axios.post('http://localhost:3000/axios', {
      uname: 'lisi',
      pwd: 123
    }).then(function(ret){
      console.log(ret.data)
    })
	//通过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)
    })
	//路由
	app.post('/axios', (req, res) => {
 	 res.send('axios post 传递参数' + req.body.uname + '---' + req.body.pwd)
	})

4.3.4.PUT传递参数

● 参数传递方式与POST类似

4.4 axios的响应结果

响应结果的主要属性
● data:实际响应回来的数据
● headers:响应头信息
● status:响应状态码
● statusText:响应状态信息

4.5 axios全局配置

● axios.defaults.timeout = 3000;//超时时间
● axios.defaults.baseURL='http://localhost:3000;//默认地址
● axios.defaults.headers[‘mytoken’] = ‘hello’; //设置请求头

 // 配置请求的基准URL地址
    axios.defaults.baseURL = 'http://localhost:3000/';
    // 配置请求头信息
    axios.defaults.headers['mytoken'] = 'hello';
    axios.get('axios-json')
      .then(function(ret){
      console.log(ret.data.uname)
    })
//路由
app.get('/axios-json', (req, res) => {
  res.json({
    uname: 'lisi',
    age: 12
  });
})

4.6 aixos拦截器

4.6.1.请求拦截器

在请求发出之前设置一些信息
图片.png

  //添加一个请求拦截器
  axios.interceptors.request.use(function(config) {
     //在请求发出之前进行一些信息设置
      return config;
    }, function(err){
    //处理响应的错误信息
      console.log(err)
    })

4.6.2.响应拦截器

在获取数据之前对数据做一些加工处理
图片.png

 //添加一个响应拦截器
axios.interceptors.response.use(function(res) {
       //在这里对返回的数据进行处理
      return res;
    }, function(err){
       //处理响应的错误信息
      console.log(err)
    })
//请求拦截器
axios.interceptors.request.use(function(config) {
      console.log(config.url)
      config.headers.mytoken = 'nihao';
      return config;
    }, function(err){
      console.log(err)
    })
//响应拦截器
    axios.interceptors.response.use(function(res) {
      // console.log(res)
      var data = res.data;
      return data;
    }, function(err){
      console.log(err)
    })
    axios.get('http://localhost:3000/adata')
     .then(function(data){
      console.log(data)
    })
//路由
app.get('/adata', (req, res) => {
  res.send('Hello axios!')
})

5. 接口调用-async和await用法

async和await两种语法结合可以让异步代码看起来像同步代码一样,简化异步函数的写法

async函数:
1.async函数的返回值为promise对象;
2.promise对象的结果由async函数执行的返回值决定
3.async 是Generator函数的语法糖,并对Generator函数进行了改进,是对 yield 的简单封装

    async function fn() {
      //1.如果返回结果是 非promise对象,状态为成功,返回值为对象成功值fulfilled
      return 123;
      //2.抛出错误
      throw "出错啦";
    }
    const result = fn();
    console.log(result); // Promise {<fulfilled>: 123} Promise {<rejected>: '出错啦'}
------------------------------------------------------------------
    async function fn() {
      //3.如果返回的promise对象,那么返回的最终结果就是Promise对象
      return new Promise((reslove, reject) => {
        //resolve('成功');
        reject('失败');
      })
    }
    const result = fn();
    console.log(result); //Promise {<rejected>: '失败'}
    // then方法来获得最终结果或出错原因
    result.then(
      (value) => {
        console.log(value);
      },
      (reason) => {
        console.log(reason); //失败
      }
    )

await表达式:
1.await必须写在aysnc函数中;
2.await后面的表达式一般为Promise对象;
3.await返回的是Promise成功的值;
4.await的Promise失败了,就会抛出异常,无法处理promise返回的reject对象,需要通过try…catch捕获处理.

    //async函数 + await表达式:异步函数
    async function fn() {
      //await 返回的promise成功值
      let result = await new Promise((resolve, reject) => {
      resolve('成功')
    });
      console.log(result); //成功
    }
    fn();

5.1 async/await的基本用法

● async/await是ES7引入的新语法,可以更加方便的进行异步操作
● async关键字用于函数上(async函数的返回值是Promise实例对象)
● await关键字用于async函数当中(await可以得到异步的结果)

async function queryData(id){
	const ret =await axios.get('/data');
	return ret;
}
queryData.then(ret=>{
	console.log(ret)
})
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
  </head>
  <body>
    <script type="text/javascript" src="js/axios.js"></script>
    <script type="text/javascript">
      async function queryData() {
        var ret = await new Promise(function (resolve, reject) {
          setTimeout(function () {
            resolve("nihao");
          }, 1000);
        });
        return ret;
      }
      queryData().then(function (data) {
        console.log(data);//nihao
      });
    </script>
  </body>
</html>

5.2 async/await处理多个异步请求

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <script type="text/javascript" src="js/axios.js"></script>
  <script type="text/javascript">
 // 配置请求的基准URL地址
    axios.defaults.baseURL = 'http://localhost:3000';
    async function queryData() {
      var info = await axios.get('async1');
      var ret = await axios.get('async2?info=' + info.data);
      return ret.data;
    }
    queryData().then(function(data){
      console.log(data)
    })
  </script>
</body>
</html>
//路由
app.get('/async1', (req, res) => {
  res.send('hello1')
})
app.get('/async2', (req, res) => {
  if (req.query.info == 'hello') {
    res.send('world')
  } else {
    res.send('error')
  }
})

图片.png

6. 基于后台接口重构图书管理案例

● 图书相关的操作基于后台接口数据进行操作
● 需要调用接口的功能点
① 图书列表数据加载 GET http://localhost:3000/books
② 添加图书 POST http://localhost:3000/books
③ 验证图书名称是否存在 GET http://localhost:3000/books/book/name
④ 编辑图书-根据ID查询图书信息 GET http://localhost:3000/books/:id
⑤ 编辑图书-提交图书信息 PUT http://localhost:3000/books/:id
⑥ 删除图书 DELETE http://localhost:3000/books/id

图书管理后台接口文档

    基准路径: http://localhost:3000/

获取图书列表数据

● 路径:books
● 请求参数:无
● 响应结果

[{
  "id": "4",
  "name": "红楼梦",
  "date": 2525609975000
}, {
  "name": "三国演义",
  "date": 2525609975000,
  "id": 5
}, {
  "name": "水浒传",
  "date": 2525609975000,
  "id": 6
}, {
  "name": "西游记",
  "date": 2525609975000,
  "id": 7
}]

添加图书-提交图书信息

● 路径:books
● 请求参数
—name : 图书名称
● 响应结果

{
    "status": 200  // (200表示成功;500表示失败)
}

编辑图书-根据ID查询图书信息

● 路径:books/:id
● 请求参数:无
● 响应结果

{
    "name":"西游记",
    "date":2525609975000,
    "id":7
}

编辑图书-提交图书信息

● 路径:books/:id
● 请求参数
—name : 图书名称
● 响应结果

{
    "status": 200  // (200表示成功;500表示失败)
}

删除图书信息

● 路径:books/:id
● 请求参数: 无
● 响应结果

{
    "status": 200  // (200表示成功;500表示失败)
}

验证图书名称是否存在

● 路径:books/book/:name
● 请求参数:无
● 响应结果

{
    "status": 1  // (1表示存在;2表示不存在)
}
{
    "status": 1  // (1表示存在;2表示不存在)
}
//引入express框架
const express = require('express');
//引入路径处理模块
const path = require('path');
//引入路由
const router = require('./router.js');
//引入post参数处理模块
const bodyParser = require('body-parser');
//创建网站服务器
const app = express();
// 启动静态资源服务
app.use(express.static('public'));
// 处理请求参数
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 为路由对象匹配请求路径   
app.use(router);
// 监听端口
app.listen(3000,()=>{
    console.log('服务器启动成功');
});
/*路由模块*/
const express = require('express');
//创建路由对象
const router = express.Router();
const service = require('./service.js');
// 查询图书列表
router.get('/books',service.getAllBooks);
// 添加图书(提交表单)
router.post('/books',service.addBook);
// 跳转到编辑图书信息页面
router.get('/books/:id',service.toEditBook);
// router.get('/toEditBook',service.toEditBook);
// 编辑图书提交表单
router.put('/books/:id',service.editBook);
// 删除图书信息
router.delete('/books/:id',service.deleteBook);
// 验证图书名称是否存在
router.get('/books/book/:name',service.checkName);

module.exports = router;
const data = require('./data.json');
const path = require('path');
const fs = require('fs');

// 自动生成图书编号(自增)
let maxBookCode = ()=>{
    let arr = [];
    data.forEach((item)=>{
        arr.push(item.id);
    });
    return Math.max.apply(null,arr);
}
// 把内存数据写入文件
let writeDataToFile = (res) => {
    fs.writeFile(path.join(__dirname,'data.json'),JSON.stringify(data,null,4),(err)=>{
        if(err){
            res.json({
                status: 500
            });
        }
        res.json({
            status: 200
        });
    });
}
// 验证图书名称是否存在
exports.checkName = (req,res) => {
    let name = req.params.name;
    let flag = false;
    data.some(item=>{
        if(name == item.name) {
            flag = true;
            return true;
        }
    })
    if(flag) {
        res.json({
            status: 1
        })
    }else{
        res.json({
            status: 2
        })
    }
}

// 获取图书列表数据
exports.getAllBooks = (req,res) => {
    res.json(data);
}

// 添加图书保存数据
exports.addBook = (req,res) => {
    // 获取表单数据
    let info = req.body;
    let book = {};
    for(let key in info){
        book[key] = info[key];
    }
    book.date = 2525609975000;
    book.id = maxBookCode() + 1;
    data.push(book);
    // 把内存中的数据写入文件
    writeDataToFile(res);
}
// 跳转编辑图书页面
exports.toEditBook = (req,res) => {
    let id = req.params.id;
    let book = {};
    data.some((item)=>{
        if(id == item.id){
            book = item;
            return true;
        }
    });
    res.json(book);
}
// 编辑图书更新数据
exports.editBook = (req,res) => {
    let info = req.body;
    info.id = req.params.id;
    data.some((item)=>{
        if(info.id == item.id){
            for(let key in info){
                item[key] = info[key];
            }
            return true;
        }
    });
    // 把内存中的数据写入文件
    writeDataToFile(res);
}
// 删除图书信息
exports.deleteBook = (req,res) => {
    let id = req.params.id;
    data.some((item,index)=>{
        if(id == item.id){
            // 删除数组的一项数据
            data.splice(index,1);
            return true;
        }
    });
    // 把内存中的数据写入文件
    writeDataToFile(res);
}
[
    {
        "id": "4",
        "name": "红楼梦",
        "date": 2525609975000
    },
    {
        "name": "三国演义",
        "date": 2525609975000,
        "id": 5
    },
    {
        "name": "水浒传",
        "date": 2525609975000,
        "id": 6
    },
    {
        "name": "西游记",
        "date": 2525609975000,
        "id": 7
    },
    {
        "name": "www",
        "date": 2525609975000,
        "id": "8"
    }
]
<!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('yyyy-MM-dd hh:mm:ss')}}</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:3000/";
      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", function (value, arg) {
        function dateFormat(date, format) {
          if (typeof date === "string") {
            var mts = date.match(/(\/Date\((\d+)\)\/)/);
            if (mts && mts.length >= 3) {
              date = parseInt(mts[2]);
            }
          }
          date = new Date(date);
          if (!date || date.toUTCString() == "Invalid Date") {
            return "";
          }
          var map = {
            M: date.getMonth() + 1, //月份
            d: date.getDate(), //日
            h: date.getHours(), //小时
            m: date.getMinutes(), //分
            s: date.getSeconds(), //秒
            q: Math.floor((date.getMonth() + 3) / 3), //季度
            S: date.getMilliseconds(), //毫秒
          };
          format = format.replace(/([yMdhmsqS])+/g, function (all, t) {
            var v = map[t];
            if (v !== undefined) {
              if (all.length > 1) {
                v = "0" + v;
                v = v.substr(v.length - 2);
              }
              return v;
            } else if (t === "y") {
              return (date.getFullYear() + "").substr(4 - all.length);
            }
            return all;
          });
          return format;
        }
        return dateFormat(value, arg);
      });
      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);
            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 flag = this.books.some(function(item){
            //   return item.name == val;
            // });
            var ret = await axios.get("/books/book/" + this.name);
            if (ret.status == 1) {
              // 图书名称存在
              this.submitFlag = true;
            } else {
              // 图书名称不存在
              this.submitFlag = false;
            }
          },
        },
        mounted: function () {
          // axios.get('books').then((data)=>{
          //   console.log(data.data)
          //   this.books = data.data;
          // })

          this.queryData();
        },
      });
    </script>
  </body>
</html>

发表评论

0/200
0 点赞
0 评论
收藏