前端与移动开发----Vue---- json-server-安装及基本使用,axios基本使用,侦听器

目标:

  • 从模拟接口处获取数据
  • 掌握axios的使用

理解写接口

在开发过程中,经常会遇到后端接口滞后的情况:前端页面写完了,后端的接口没有就绪(意味着前端没有数据可用),此时,我们就可以自己先准备接口(接口的功能是真的,数据是假的)。

有两种方式:

- 自己写
  - nodejs写接口(利用express框架)
  - 采用现成的工具json-server生成接口
- 第三方的公开的mock api工具 (非常多)
  - https://www.fastmock.site/#/

mock: 假的,

json-server-安装及基本使用

参考:教程

官网: npm

作用

能json-server快速地根据已有json文件,生成接口

json ----json-server-----> 接口

在这里插入图片描述

使用步骤

全局安装json-server

以前安装过的全局包:nodemon,nrm

它是依赖于nodejs的第三方包,它是一个独立的工具,并不限于某个项目,可以全局安装。

npm i json-server -g

如果是mac本,可能需要加sudo,即:sudo npm i json-server -g

准备空文件夹

在任意目录下,准备一个空文件夹,取名mock-server(可改成其它名字)

创建json文件

在文件夹中新建一个名为db.json文件(可改其它名称,注意名字是是英文

在这里插入图片描述

初始化结构

在db.json文件中,按json格式的要求,去定义一个对象:

  • 键值对格式
  • 双引号括起来
{
    
    
  "assets": [
	    {
    
     "id": 1, "name": "外套", "price": 99 },
	    {
    
     "id": 2, "name": "裤子", "price": 34 },
	    {
    
     "id": 3, "name": "鞋", "price": 25.4 },
	    {
    
     "id": 4, "name": "头发", "price": 19900 }
	]
}

启动接口服务

根据上面创建的db.json自动地生成接口。

进入到上一步创建的文件夹下,

此文件夹下,打开命令行窗口,输入命令json-server db.json (json-server后有空格)

在这里插入图片描述

如果没有错误,则运行结果如下:在这里插入图片描述

测试

在浏览器中访问上面地址

在这里插入图片描述

注意:

  • 产生的接口地址中的assets是与db.json中的属性名是对应的。
  • db.json的内容必须是json格式。
  • 属性名 —> 接口的地址
  • 属性值 —> 接口返回数据 (数组|对象)

原理图

在这里插入图片描述

注意

  • 小黑窗不要关!
  • 小黑窗上不要用鼠标选中任何内容!

json-server-RESTful接口

json-server提供的接口是符合RESTful接口规范的。

问题导入

在写接口时,每个程序员都有自己的写法:取不同的名字,例如:实现添加资产

A同学: localhost:3000/addAsset | delAsset

B同学: localhost:3000/insertAsset | deleteAsset

C同学: localhost:3000/tjzj | sczj

RESTful接口

针对上述问题,提出一套约定:

RESTful接口的规范是通过

  • 请求方式来决定操作类别(添加,删除,修改,查询)
  • 用名词来表示要操作的目标

测试

以上面启动的服务为例:一旦服务启动成功,就会自动生成如下接口地址。

接口地址 请求方式 操作类型
/assets GET 获取全部数据
/assets/1 GET 获取单个数据
/assets POST 添加操作 {name,price}
/assets/1 DELETE 删除操作
/assets/1 PUT 完整修改{name,price}
/assets/1 PATCH 局部修改{name}

以上接口规则,就是restful规则。

json-server提供的就是符合restful规则的接口。

json-server-postman测试

postman是用来测试后端给的接口是否正常工作。

类似的工具还有:apipost, postwoman

使用postmant来测试json-server提供的接口。

获取全部数据 - 列表

GET: http://localhost:3000/assets

在这里插入图片描述

获取单个数据 - 详情

以id为查询依据

GET: http://localhost:3000/assets/1

在这里插入图片描述

根据条件查询数据

json-server服务器提供了条件查询的功能

格式: ? 字段**_like**=值

在这里插入图片描述

头这个关键字前后,不要加引号!

添加操作

以json格式传递参数,id会自动增加

POST:http://localhost:3000/assets/

{"name": "电脑", "price": 6880}

在这里插入图片描述

另一个操作示例:

在这里插入图片描述

删除操作

以id为查询依据

DELETE: http://localhost:3000/assets/1

上面的地址中,1就表示要删除的数据的id。

完整修改

以json格式传递参数

PUT: http://localhost:3000/assets/3

要求必须传入一个完整的对象(如果这一条记录中有100个属性,则要传入100个属性),因为它会整体覆盖这条数据。

局部修改

以json格式传递参数

PATCH: http://localhost:3000/assets/3

只需要传入要更改的字段(要修改哪个属性就传入哪个属性 )。

axios基本使用

我们发ajax请求接口,有如下方式:

  • 原生的。纯手写:XMLHttpRequest…
  • . a j a x ( ) 。 j q u e r y 中 的 a j a x ( .ajax()。jquery中的ajax( .ajax()jqueryajax.get, $.post …)
  • axios。它是一个专业的,只发ajax请求的工具。它可以在nodejs中和浏览器使用。

下载并使用

axios是一个js库,是前端通用的工具,专门用来发ajax。要想使用,就要先下载。

下载地址:https://unpkg.com/axios/dist/axios.min.js

文档地址:http://www.axios-js.com/docs/

格式

完整写法

axios({
    
    
    // 请求方式 get|post|put|patch|delete  大小写不区分
    method: 'get',
    // 路径上传参在url后进行拼接
    url: 'http://localhost:3000/brands/1',
    // ?后键值对传参
    params: {
    
    },
    // 请求体传参
    data: {
    
    },
    // 请求头传参
    headers: {
    
    }
}).then(res=>{
    
    
    console.log('成功')
}).catch(err=>{
    
    
    console.log('失败')
})

简写格式

对于比较简单的接口调用,可以采用简写格式:

格式:

axios.请求方式(url, .......).then().catch()

示例:

// get类型的 参数要放在写params中
axios.get(url,params: {
    
    }).then(res=>{
    
    console.log('成功')})
.catch(err=>{
    
    
    console.log('失败')
})
// post类型 直接写参数
axios.post(url,{
    
    }).then(res=>{
    
    console.log('成功')})
.catch(err=>{
    
    
    console.log('失败')
})

示例

通过json-server启动接口服务器,然后再写axios代码来进行调用测试

查询

<!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 src="https://cdn.bootcdn.net/ajax/libs/axios/0.20.0/axios.min.js"></script>
  <script>

    // console.log(axios)
    // 格式:
    // axios({
     
     
    //     // 请求方式 get|post|put|patch|delete  大小写不区分
    //     method: 'GET',
    //     // 路径上传参在url后进行拼接
    //     url: 'http://localhost:3000/brands/1',
    //     // ?后键值对传参
    //     params: {},
    //     // 请求体传参
    //     data: {},
    //     // 请求头传参
    //     headers: {}
    // }).then(res=>{
     
     
    //     console.log('成功')
    //     console.log(res)
    // }).catch(err=>{
     
     
    //     console.log('失败')
    //     console.log(err)

    // })

    // 1. 测试添加新资产
    // axios({
     
     
    //   method: 'POST',
    //   url: 'http://localhost:3000/assets',
    //   data: {
     
     
    //     name: '测试axios',
    //     price: 1
    //   }
    // }).then(res => {
     
     
    //   console.log('成功')
    //   console.log(res.data);
    // }).catch(err => {
     
     
    //   console.log('失败')
    //   console.log(err)
    // })

    // 2. 测试获取所有的资产
    // axios({
     
     
    //   method: 'get',
    //   url: 'http://localhost:3000/assets'
    // }).then(res => {
     
     
    //   console.log('成功')
    //   console.log(res.data);
    // }).catch(err => {
     
     
    //   console.log('失败')
    //   console.log(err)
    // })

    // 3. 测试 根据关键字查询
    // axios({
     
     
    //   method: 'get',
    //   url: 'http://localhost:3000/assets?name_like=测'
    // }).then(res => {
     
     
    //   console.log('成功')
    //   console.log(res.data);
    // }).catch(err => {
     
     
    //   console.log('失败')
    //   console.log(err)
    // })

    // 4. 测试 删除
    let id = 2
    axios({
     
     
      method: 'DELETE',
      url: 'http://localhost:3000/assets/' + id
    }).then(res => {
     
     
      console.log('删除成功')
      console.log(res.data);
    }).catch(err => {
     
     
      console.log('失败')
      console.log(err)
    })


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

添加

    // 2. 添加
    // 除去get请求外,函数的第二个参数都是请求体传参,是对象类型。
    axios.post('http://localhost:3000/assets',{
    
    name:"宝马",price:500000}).then(res=>{
    
    
      console.log('成功')
    })

删除

    // 3. 删除
    axios.delete('http://localhost:3000/assets/2').then(res=>{
    
    
      console.log('成功')
    })

修改

    // 4. 修改 完整
    // axios.put('http://localhost:3000/assets/3',{name:"长安奔奔",price:36000}).then(res=>{
    
    
    //   console.log('成功')
    // })
    // 5. 修改 局部
    axios.patch('http://localhost:3000/assets/3',{
    
    name:"奔奔"}).then(res=>{
    
    
      console.log('成功')
    })

总结:不同方式的参数怎么传递给后台。

案例-资产列表-目标说明

目标:

  • 用json-server启动后端接口服务器;
  • axios发请求
  • 用vue管理视图
    • v-for
    • 计算属性算总价
    • v-if 显示空数据的情况
    • 过滤器处理价格

案例-资产列表-渲染列表

目标:在给定的静态页的基础上,通过引入vue对列表数据进行渲染

准备静态页面

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <div id="app">
    <div class="container">
      <!-- 搜索 -->
      <form class="form-inline" style="padding: 20px 0">
        <input type="text" class="form-control" placeholder="输入关键字进行搜索">
      </form>
      <!-- 表格 -->
      <table class="table table-bordered table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>资产名称</th>
            <th>创建时间</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>1</td>
            <td>xxx</td>
            <td>xxxx</td>
            <td><a href="#">删除</a></td>
          </tr>
        </tbody>
      </table>
      <!-- 添加资产 -->
      <form class="form-inline">
        <input type="text" class="form-control" placeholder="资产名称">
        &nbsp;&nbsp;&nbsp;&nbsp;
        <button class="btn btn-primary">添加资产</button>
      </form>
    </div>
  </div>
</body>

</html>

创建vue实例,实现列表渲染

实现渲染列表,大致步骤:

  • 在data配置项中,声明一个列表数据list,先设置一些假数据。
  • 在模板当中根据list和数据中的字符段进行渲染
    • 使用v-for指令
    • 注意处理无数据的情况。

对应代码如下

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <div id="app">
    <div class="container">
      <!-- 搜索 -->
      <form class="form-inline" style="padding: 20px 0">
        <input type="text" class="form-control" placeholder="输入关键字进行搜索">
      </form>
      <!-- 表格 -->
      <table class="table table-bordered table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>资产名称</th>
            <th>价格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          
          <tr v-for="(item, idx) in list">
            <td>{
   
   {idx}}</td>
            <td>{
   
   {item.name}}</td>
            <td>{
   
   {item.price}}</td>
            <td><a href="#">删除</a></td>
          </tr>
          
          <tr v-if="list.length==0">
            <td colspan="4">没有数据</td>
          </tr>
        </tbody>
      </table>
      <!-- 添加资产 -->
      <form class="form-inline">
        <input type="text" class="form-control" placeholder="资产名称">
        <input type="text" class="form-control" placeholder="价格">
        &nbsp;&nbsp;&nbsp;&nbsp;
        <button class="btn btn-primary">添加资产</button>
      </form>
    </div>
  </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 

<script>

  // [{id:1,name:'t',price:1}]
  // 1. 引用vue,把本地的数据渲染到页面上

  new Vue({
     
     
    el: '#app',
    data: {
     
     
      list: [
        {
     
     id:1,name:'商品1',price:1}
      ]
    }
  })
</script>

</html>

案例-资产列表-ajax请求真数据

准备接口服务器

  • 按前面的介绍的json-server的使用方式,把json服务器启动;

  • 用postman提前做好接口测试;

在created配置项中发ajax请求

现在一切就绪,只需在某个时间点,向后台接口发请求,拿回数据,给list重新赋值即可

以前:window.onload = function(){} 默认渲染,页面加载完成之后

或者:$(function(){}) 默认渲染,页面文章加载完成之后

在vue中,需要默认渲染,vue实例初始化完毕后,发请求获取数据进行渲染。

vue提供一个配置选项created, 类型是函数,它会vue实例化后在被自动执行。

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>


// 它是一个配置项,它是一个函数。它会在vue实例创建完成后, 被自动调用一次(只调用一次)
    // 我们可以在这里,去发 ajax请求
    created () {
    
    
      console.log('created....')
      // 1. 发ajax请求,获取全部的数据
      // 2. 把数据保存到data中的对应的数据项list中
      axios({
    
    
        method: 'GET',
        url: 'http://localhost:3000/assets'
      }).then(res => {
    
    
        console.log(res.data)
        // 数据变化了,视图也自动变化
        this.list = res.data
      })
    }

总结:一般在created函数中获取页面需要的初始化数据。

案例-资产管理-删除资产

目标

点击页面上的删除按钮,把对应的数据删除掉。

步骤

  1. 给a标签绑定点击事件(注意阻止默认行为)

  2. 定义处理函数,给函数传入资产ID

  3. 在函数中

    • 弹出确认框提示

    • 点击确认框之后,发删除请求

    • 如果成功之后,更新列表(移除删除的行)

代码

<tbody>
          
  <tr v-for="(item, idx) in list">
    <td>{
    
    {
    
    idx}}</td>
		<td>{
    
    {
    
    item.name}}</td>
		<td>{
    
    {
    
    item.price}}</td>
		<td><a href="#" @click.prevent="hDelete(item.id)">删除</a></td>
  </tr>

	<tr v-if="list.length==0">
  <td colspan="4">没有数据</td>
</tr>
</tbody>

<script>
  // [{id:1,name:'t',price:1}]
  // 1. 引用vue,把本地的数据渲染到页面上
  // 2. ajax请求数据
  // 3. 删除 (用户确认)
    // (1)点击事件
    //  (2) 获取当前要删除的资产的id
    // (3)调用接口,发请求
    //  (4) 删除成功之后,要重新请求数据,以更新页面
  new Vue({
    
    
    el: '#app',
    data: {
    
    
      list: [
        // {id:1,name:'商品1',price:1}
      ]
    },
    computed: {
    
    
      // xx () {
    
    
      //   console.log(this.xxxx)
      // }
    },
    // 它是一个配置项,它是一个函数。它会在vue实例创建完成后, 被自动调用一次(只调用一次)
    // 我们可以在这里,去发 ajax请求
    created () {
    
    
      console.log('created....')
      this.loadData()
    },
    methods: {
    
    
      loadData () {
    
    
        // 1. 发ajax请求,获取全部的数据
        // 2. 把数据保存到data中的对应的数据项list中
        axios({
    
    
          method: 'GET',
          url: 'http://localhost:3000/assets'
        }).then(res => {
    
    
          console.log(res.data)
          // 数据变化了,视图也自动变化
          this.list = res.data
        })
      },
      hDelete (id) {
    
    

        if(!window.confirm('你确定要删除吗?')) {
    
    
          return
        }
        // alert(id)
        // 调用接口,发请求
        axios({
    
    
          method: 'DELETE',
          url: 'http://localhost:3000/assets/' + id
        }).then(res => {
    
    
          // 重新请求数据
          this.loadData()
        })
      }
    }
  })
</script>

注意:

  • 代码要封装。获取数据这个操作用到了多次,需要封装成成函数。
  • 关于的函数的名字:loadDatahDel 如果一个函数是需要用户交互(点击事件,hover…)才会被执行的,就会在前面加 ‘h == handler’;如果不是,则不要加h。
  • 在函数的内部要访问其它的属性或者数据,要在前面加this

案例-资产管理-添加资产

目标

在点击页面上的添加时,可以实现添加新资产的功能

步骤

  1. 双向数据绑定,输入资产的表单元素
  2. 绑定表单的提交事件,阻止默认行为
  3. 在methods中定义一个事件函数,在函数中:
    • 组织需要提交给后台的数据,{name,price},id后台不需要,自动自增。
    • 提交数据前,对name进行校验
    • 发起添加请求,如果成功,重新获取后台列表数据即可。
    • 之前输入的内容清空

在案例中落地的代码:

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>
  <div id="app">
    <div class="container">
      <!-- 搜索 -->
      <form class="form-inline" style="padding: 20px 0">
        <input type="text" class="form-control" placeholder="输入关键字进行搜索">
      </form>
      <!-- 表格 -->
      <table class="table table-bordered table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>资产名称</th>
            <th>价格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          
          <tr v-for="(item, idx) in list">
            <td>{
   
   {idx}}</td>
            <td>{
   
   {item.name}}</td>
            <td>{
   
   {item.price}}</td>
            <td><a href="#" @click.prevent="hDelete(item.id)">删除</a></td>
          </tr>
          
          <tr v-if="list.length==0">
            <td colspan="4">没有数据</td>
          </tr>
        </tbody>
      </table>
      <!-- 添加资产
      
        向后端接口中传入数据时,建议按接口文档中的要求去取变量名。
      -->
      <form class="form-inline">
        <input type="text" v-model.trim="asset.name" class="form-control" placeholder="资产名称">
        <input type="text" v-model.number="asset.price" class="form-control" placeholder="价格">
        &nbsp;&nbsp;&nbsp;&nbsp;
        <button class="btn btn-primary" @click.prevent="hAdd">添加资产</button>
      </form>
    </div>
  </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
  // [{id:1,name:'t',price:1}]
  // 1. 引用vue,把本地的数据渲染到页面上
  // 2. ajax请求数据
  // 3. 删除 (用户确认)
    // (1)点击事件
    //  (2) 获取当前要删除的资产的id
    // (3)调用接口,发请求
    //  (4) 删除成功之后,要重新请求数据,以更新页面
  new Vue({
     
     
    el: '#app',
    data: {
     
     
      list: [
        // {id:1,name:'商品1',price:1}
      ],
      asset: {
     
     
        name: '',
        price: ''
      }
    },
    computed: {
     
     
      // xx () {
     
     
      //   console.log(this.xxxx)
      // }
    },
    // 它是一个配置项,它是一个函数。它会在vue实例创建完成后, 被自动调用一次(只调用一次)
    // 我们可以在这里,去发 ajax请求
    created () {
     
     
      console.log('created....')
      this.loadData()
    },
    methods: {
     
     
      // 用户点击了添加按钮 
      hAdd () {
     
     
        console.log(this.asset)
        // 1. 解构赋值
        const {
     
      name, price } = this.asset
        
        // 2. if (用户的输入不合法,提示一下用户
        if (name === '') {
     
     
          alert('名字不能为空')
          return
        }

        if (price <= 0) {
     
     
          alert('价格不能是负数')
          return
        }
        // 3. 发请求
        axios({
     
     
          method: 'POST',
          url: 'http://localhost:3000/assets',
          data:{
     
     
            name: name,
            price: price
          }
        }).then(res => {
     
     
          console.log('添加成功')
          // 1. 重新请求数据
          this.loadData()
          // 2. 清空表单数据
          this.asset.name = ''
          this.asset.price = ''
        })
      },
      loadData () {
     
     
        // 1. 发ajax请求,获取全部的数据
        // 2. 把数据保存到data中的对应的数据项list中
        axios({
     
     
          method: 'GET',
          url: 'http://localhost:3000/assets'
        }).then(res => {
     
     
          console.log(res.data)
          // 数据变化了,视图也自动变化
          this.list = res.data
        })
      },
      hDelete (id) {
     
     

        if(!window.confirm('你确定要删除吗?')) {
     
     
          return
        }
        // alert(id)
        // 调用接口,发请求
        axios({
     
     
          method: 'DELETE',
          url: 'http://localhost:3000/assets/' + id
        }).then(res => {
     
     
          // 重新请求数据
          this.loadData()
        })
      }
    }

    
  })
</script>

</html>

要点:

  • 根据接口中字段的要求来定data中的数据项叫什么名字

  • 如果数据项之间有关联 ,可以把它们统一加在一个对象中

案例-资产管理-搜索资产

目标

在搜索框中输入内容,获得以此为关键字的搜索结果。

思路

  1. 双向绑定 搜索框 这样可以获取到输入的关键字(keyword)数据。

  2. 实时进行搜索,筛选出列表需要的数据。

    监听到输入内容的改变,根据输入的内容向后台发请求(有异步操作),响应成功后才可拿到列表数据。

  3. 监听keyword数据的变化,vue提供了侦听器,可以监听任何数据(this能够访问的数据)的变化。

难点:如何得知key数据变化?

侦听器

功能

对数据项进行侦听:当数据变化时,立即被感知到,调用函数(在函数内就可以做任意业务)。

格式

new Vue({
    
    
  // .....
  watch: {
    
    
    // 属性名: 就是你要监听的数据项
    // 属性值:一个函数,当这要监听的数据项变化时,要执行的函数。
    // 它会自动传入新值和旧值
    // 正常使用this
    // 第一个参数是更新后的值,第二个参数是更新前的值
    属性名1: function(新值,旧值) {
    
    
  		// 你要做什么.....
		},
    属性名2: function(新值,旧值) {
    
    
  		// 你要做什么.....
		}
	}
})

基本案例

<!DOCTYPE html>
<html lang="zh">
<head>
 <meta charset="UTF-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <title>html页面</title>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> 
 <style>
   body{
     
     
     background-color: #eee;
   }
   #app{
     
     
     background-color:#fff;
     width: 500px;
     margin: 50px auto;
     box-shadow: 3px 3px 3px rgba(0 , 0, 0, 0.5);padding:2em;
    }
    .btn{
     
     
      float:right;
      cursor: pointer;
    }
   .box{
     
     
     padding: 1em;
     border:1px solid #ccc;
     margin:1em;
   }
   </style>
 </head>
 <body>
  <div id="app">
    {
   
   {num}}, {
   
   {asset.price}}
  </div>

   <script>
    var vm = new Vue({
     
     
      el: '#app',
      data: {
     
     
        num: 10,

        asset: {
     
     
          price: 100
        }
      },
      // 目标: 当用户把num的值修改了,我们要能感知到!!!
      watch: {
     
     

        // 只要当num变化时,就会自动执行这个函数
        // newNum 变化之后的新值
        // oldNum 变化之前的旧值
        "num": function(newNum, oldNum) {
     
     
          console.log('num从', oldNum, '变成了', newNum)
        },
        "asset.price": function(newNum, oldNum) {
     
     
          console.log('asset.price从', oldNum, '变成了', newNum)
        }

      }
    })
</script>
 </body>
</html>
  • 侦听器用来对数据变化进行监控

侦听器与计算属性

共同点:

  1. 如果它们都侦听(依赖)同一个数据项,当数据项变化时,会去执行函数。
  2. 它们表现格式都是: { xx1(){}, xx2(){} }

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

  • 计算属性:本质是一个函数。如果这个函数中依赖的数据项变化时,这个函数就会重新执行,它必须要有返回结果
  • 侦听器:本质是一个函数。当侦听到某个数据变化时,这个函数就会重新执行,但不一定是依赖这个数据直接得到你想要的数。从函数内的代码逻辑来说:侦听器的逻辑一般会更加复杂。侦听器的返回值是没有意义的。

优先级: 计算属性 > 侦听器

秒懂案例:侦听器是人工服务台;计算属性是查询话费余额的快捷键 1008611

案例-资产管理-搜索资产-侦听器

用侦听器实现上述的功能

      <!-- 搜索 -->
      <form class="form-inline" style="padding: 20px 0">
        <input v-model="keyword" type="text" class="form-control" placeholder="输入关键字进行搜索">
      </form>
      data: {
        // 搜索关键字
+        keyword: ''
      },
watch: {
    
    
  keyword: function(newVal, oldVal) {
    
    
        console.log(this.keyword)
        // 获取到用户要搜索的关键字
        // 如果关键字为空,就相当于是找全部的

        axios({
    
    
          method: 'GET',
          url: 'http://localhost:3000/assets',
          params: {
    
    
            name_like: this.keyword
          }
        }).then(res => {
    
    
          // 把查询到的数据更新到数据项中
          this.list = res.data
        })
      }
}

案例-资产管理-完成后的代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
  <div id="app">
    <div class="container">
      <!-- 搜索 -->
      <form class="form-inline" style="padding: 20px 0">
        <!-- @input="hKeywordChange" -->
        搜索:
        <input
        v-model.trim="keyword" type="text" class="form-control" placeholder="输入关键字进行搜索">
      </form>
      <table class="table table-bordered table-hover">
        <thead>
          <tr>
            <th>编号</th>
            <th>资产名称</th>
            <th>价值</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(item,index) in list">
            <td>{
   
   {index+1}}</td>
            <td>{
   
   {item.name}}</td>
            <td>{
   
   {item.price}}</td>
            <!-- 做删除,传入id -->
            <td><a href="#" v-on:click.prevent="hDel(item.id)">删除</a></td>
          </tr>
        </tbody>
      </table>

      <!-- 添加资产 -->
      <form class="form-inline">
        <div class="form-group">
            <div class="input-group">
              <input type="text" v-model.trim="asset.name" class="form-control" placeholder="资产名称">
            </div>
            <div class="input-group">
              <input type="text" v-model.trim.number="asset.price" class="form-control" placeholder="价值">
            </div>
      
            <button class="btn btn-primary" @click.prevent="hAdd">添加资产</button>
        </div>
      </form>
    </div>
  </div>

 <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.js"></script>
 <!-- 引入axios -->
 <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.20.0/axios.min.js"></script>


  <script>

    // 0. 数据要从接口处获取
    // 1. v-if, v-else. 是否显示表格内容,或者是提示。 
    // 2. v-for. 循环列表
    // 3. {
     
     { }} 显示数据
    // 4. @click.prevent
    // 5. 计算属性算总价
    // 6. 过滤器,处理货币金额
    // 7. 列表数据筛选
    //    通过设计计算属性,让它来决定表格区域的数据。
    // 8. 自定义指令
    const vm = new Vue({
     
     
      el: '#app',
      data:{
     
     
        keyword: '', // 搜索关键字
        asset: {
     
     
          name: '',
          price: ''
        },
        list: []
      },
      computed: {
     
     },
      methods: {
     
     
        loadData () {
     
     
          axios({
     
     
            method: 'get',
            url: 'http://localhost:3000/assets'
          }).then(res => {
     
     
            console.log('成功')
            // console.log(res.data);
            // 将请求回来的数据保存到list中
            this.list = res.data
            console.log(this.list)
          }).catch(err => {
     
     
            console.log('失败')
            console.log(err)
          })
        },
        hDel (id) {
     
     
          if(confirm('你确认要删除吗?')) {
     
     
            axios({
     
     
              method: 'DELETE',
              url: 'http://localhost:3000/assets/' + id
            }).then(res => {
     
     
              // alert('删除成功')
              // 重新获取数据,以更新页面
              this.loadData()
            }).catch(err => {
     
     
              alert('删除失败,请与管理员联系')
            })
          }
          // alert('删除')
        },
        hAdd () {
     
     
          const {
     
     name, price} = this.asset
          // 1. 判断数据是否为空
          if (name === '' || price === '') {
     
     
            return
          }
          // 2. 发ajax
          axios({
     
     
            method: 'POST',
            url:'http://localhost:3000/assets',
            data: {
     
     
              name,
              price
            }
          }).then(res => {
     
     
          // 3. 根据ajax执行结果,给出后续动作
            console.log('ok')
            // (1) 清空表单区域的内容
            this.asset.name = this.asset.price = ''
            // (2) 重发请求
            this.loadData()
          }).catch(err => {
     
     
            console.log('error')
          })
        },
        // hKeywordChange () {
     
     
        //   console.log(Date.now(), 'input事件,....')
        // }
      },
      watch: {
     
     
        keyword(newVal, oldVal) {
     
     
          console.log(Date.now(), 'keyword变化了........', newVal)
          // 去发出ajax请求,获取新数据
          axios({
     
     
            method: 'GET',
            url: 'http://localhost:3000/assets',
            params: {
     
     
              name_like: newVal
            }
          }).then(res => {
     
     
            this.list = res.data
          }).catch(err => {
     
     
            this.list = []
          })
        }
      },
      // 当vue实例被创建时,会自动去执行created函数--钩子函数(这个函数钩在vue上,当vue创建时,这个函数会自动执行)
      //  1. 可以在这里里面去发ajax
      //  2. 可以在这个函数中去通过this来访问数据项
      created () {
     
     
        // alert(1)
        this.loadData()
      }
    })
  </script>
</body>
</html>

如有不足,请多指教,
未完待续,持续更新!
大家一起进步!

猜你喜欢

转载自blog.csdn.net/qq_40440961/article/details/112911255