# Vue基础

# 前后端交互

# json-server基本使用

目的:模拟后台接口。

问题:前端需要依赖后台接口才能获取数据,但是我们前端开发的时候,后台一定写好了接口吗?

模拟接口:使用json-server这个基于nodejs的命令行工具,模拟后台接口,让前端可以继续进行开发。

npm i json-server -g --registry=https://registry.npm.taobao.org
  • 准备db.json文件
{
  "books": [
    {"id":1,"bookname":"西游记","createTime":"2010-10-10 10:10:10"}
  ]
}
  • 进入db.json文件所在目录,启动server服务
json-server db.json
  • 如果json-server服务启动了,我们通过 http://localhost:3000/books访问数组数据。

# 通过postman测试接口

目的:了解接口规则。

我们使用json-server启动的接口符合Restful接口定义的规则。

  • url路径中一般使用名词的复数
  • 请求的参数使用 /123 这种风格传递,而不使用 ?id=123这种风格
  • 严格区分请求方式
路径 请求方式 具体对应操作
/books GET 获取图书数组数据
/books/1 GET 获取当前图书数据
/books POST 添加图书(请求体传参)
/books/1 DELETE 删除图书
/books/1 PUT 修改图书(请求体传参) 完整修改:没有提交的数据修改为空
/books/1 PATCH 修改图书(请求体传参) 局部修改:没有提交的数据不做修改

# axios基本用法

# 基本介绍

  • 前端调用接口

    • 原始ajax
    • 基于jQuery的封装的ajax方法 $.ajax/$.get/$.post
    • axios (opens new window) 是一个js库,专门用于调用接口
  • axios的核心特性

    • 可以从浏览器端发送ajax请求
    • 可以从node.js环境发送请求
    • 支持 Promise API
    • 支持请求和响应拦截器
    • 可以转换请求和响应的数据
    • 支持请求的取消
    • 自动转换json格式数据
    • 可以更加安全的发送请求

# 基本用法

  • axios发送get请求
    • ret这个数据被axios包裹了一层属性data
// 基于axios发送请求
axios.get('http://localhost:3000/books').then(function (ret) {
    // ret这个数据被axios包裹了一层属性data
    console.log(ret.data)
})
  • axios发送post请求
// 参数一表示请求地址,参数二表示请求提交的参数
axios.post('http://localhost:3000/books', {
  bookname: '三国演义',
  createTime: '2010-10-10 10:10:12'
}).then(ret => {
  console.log(ret)
})
  • 基于通用的axios方法发送请求
// // 基于axios函数发送get请求
// axios({
//   method: 'get',
//   url: 'http://localhost:3000/books'
// }).then(ret => {
//   console.log(ret)
// })
// ----------------------------
const btn = document.getElementById('btn')
btn.onclick = function () {
  // 基于axios函数发送post请求
  axios({
    method: 'post',
    data: {
      bookname: '智能时代',
      createTime: '2010-10-10 10:10:22'
    },
    url: 'http://localhost:3000/books'
  }).then(ret => {
    console.log(ret)
  })
}
  • 设置请求的基准路径
// 配置axios的基准路径(这样统一配置后,再发送请求时可以省略这部分)
axios.defaults.baseURL = 'http://localhost:3000/'
axios.get('books').then(ret => {
  if (ret.data) {
    this.books = ret.data
  }
})

# 图书案例案例-接口版

# 图书列表功能

目标:实现图书列表渲染功能(调用接口实现)

  • 页面打开时自动触发接口调用
  • 接口获取数据成功后,更新data中的列表数据
// 配置axios的基准路径(这样统一配置后,再发送请求时可以省略这部分)
axios.defaults.baseURL = 'http://localhost:3000/'
methods: {
  // 调用接口获取图书列表数据
  loadBookList () {
    axios.get('books').then(ret => {
      if (ret.data) {
        this.books = ret.data
      }
    })
  }
},
mounted () {
  // 页面渲染完成后触发
  this.loadBookList()
}
  • 图书列表动态填充
<tr v-for='item in books' :key='item.id'>
  <td>{{item.id}}</td>
  <td>{{item.bookname}}</td>
  <td>{{item.createTime}}</td>
  <td>删除|修改</td>
</tr>

# 删除图书

目标:实现图书删除功能

1、绑定删除事件并传递id

2、调用接口进行删除

3、删除成功后刷新列表

// 实现图书删除
handleDelete (id) {
  // 删除操作一般需要确认
  if (confirm('确认要删除吗')) {
    axios.delete('books/' + id).then(ret => {
      if (ret.status === 200) {
        // 删除成功,重新渲染列表
        this.loadBookList()
      }
    })
  }
},

# 添加图书

目标:实现添加图书功能

  • 绑定按钮事件
  • 获取表单数据
  • 调用接口添加图书
  • 根据返回的状态刷新列表
  • 清空表单
// 实现添加图书
handleSubmit () {
  if (!this.bookname) {
      // 没有输入内容
      alert('请输入图书名称')
      return
  }
  // 调用接口添加图书
  const book = {
    bookname: this.bookname,
    createTime: new Date()
  }
  axios.post('books', book).then(ret => {
    if (ret.status === 201) {
      // 添加图书成功,刷新列表,清空表单
      this.loadBookList()
      this.bookname = ''
    }
  })
},

# 搜索图书

目标:掌握vue侦听器功能

侦听器应用场景:在需要监听某项数据的变化然后去,做异步操作或开销较大操作(逻辑非常复杂)。

补充:凡是以后需要监听数据的变化而去做一些事情,就可以使用侦听器。

  • 基本用法
new Vue({
  data: {
    msg: 'hi vuejs'
  },
  // 侦听器
  watch: {
    // key 是就是你想监听数据的 字段名称 
    // value 是函数,当数据变化的时候执行该函数
    msg: function(newMsg,oldMsg) {
      // newMsg 改变后的值
      // oldMsg 改变前的值
      // 做你自己的业务逻辑(官方建议:异步|复杂操作)
    }
  }
})
  • 基于侦听器实现搜索功能
<input v-model='keyword' type="text" class="form-control" style="width:200px;display: inline-block;" placeholder="请输入搜索关键字">
data: {
  // 品牌列表
  list: [],
  // 品牌名称
  bookname: '',
  // 搜索关键字
  keyword: ''
},
watch: {
  keyword (kw) {
  // 当输入关键字时,调用接口查询匹配的结果
  // json-server规定模糊匹配规则是在属性名称后添加 _like
  // axios.get('books?bookname_like=' + kw).then(ret => {
  //   if (ret.status === 200) {
  //     this.books = ret.data
  //   }
  // })
  // ------------------------------------
  axios.get('books', {
    // get传递参数另一种方式:通过params属性传递参数
    params: {
      bookname_like: kw
    }
  }).then(ret => {
    if (ret.status === 200) {
      // 数据变化,页面自动更新(数据的响应式)
      this.books = ret.data
    }
  })
}
},

# 搜索功能添加函数防抖

目标:限制接口调用的频率

执行流程:连续输入两个字符之间的时间间隔如果小于1s,那么不会触发接口调用

函数防抖:超过连续触发条件(输入一个字符)的时间间隔(一秒),才会触发一次任务(调用一次接口)

watch: {
    keyword (kw) {
      // 当输入关键字时,调用接口查询匹配的结果
      // json-server规定模糊匹配规则是在属性名称后添加 _like
      // axios.get('books?bookname_like=' + kw).then(ret => {
      //   if (ret.status === 200) {
      //     this.books = ret.data
      //   }
      // })
      // ------------------------------------
      // 1、keyword方法触发一次证明输入了一个字符
      // 2、如果连续两次输入字符的时间间隔小于一秒,那么会销毁上一个任务,再产生一个新的任务,并一直重复这个过程
      // 3、直到停止输入后,时间超过了1秒后,最后一次任务才会执行
      // 函数防抖:超过连续触发条件(输入一个字符)的时间间隔(一秒),才会触发一次任务(调用一次接口)
      clearTimeout(this.timer)
      this.timer = setTimeout(() => {
        axios.get('books', {
          // get传递参数另一种方式:通过params属性传递参数
          params: {
            bookname_like: kw
          }
        }).then(ret => {
          if (ret.status === 200) {
            // 数据变化,页面自动更新(数据的响应式)
            this.books = ret.data
          }
        })
      }, 1000)
    }
},

# 添加接口的加载提示功能

目标:掌握状态位的控制逻辑

data: {
  isLoading: true,
}
<tr v-show='isLoading'>
  <td colspan="4" style='text-align: center;'>正在加载...</td>
</tr>
// 调用接口获取图书列表数据
loadBookList () {
  // 显示加载状态
  this.loading = true
  axios.get('books').then(ret => {
    if (ret.data) {
      this.books = ret.data
      // 加载完成数据后,隐藏状态
      this.loading = false
    }
  })
}