Vue(day4)

使用接口的形式发送数据

一 : json-server 提供假数据接口

  1. json-server 作用 : 根据指定的 JSON 文件, 提供假数据接口

  2. 地址 : json-server

  3. 使用步骤

    1. 全局安装 json-server  : `npm i -g json-server`
    2. 准备一个json数据
    3. 执行 :  `json-server data.json`
    
    > json数据参考
    json数据可以参考 :
    {
      "todos": [
        {
          "id": 1,
          "name": "吃饭",
          "age": 20
        }
      ]
    }
    
  4. REST API 格式

* 1. 查询 : GET
* 2. 添加 : POST
* 3. 删除 : DELETE
* 4. 更新 : PUT 或者 PATCH(打补丁)
  1. 具体接口
* 1. 查询全部数据 http://localhost:3000/todos
*    查询指定数据 http://localhost:3000/todos/2
*
*  2. 添加一个对象 //localhost:3000/todos
*     POST
*     id 会自动帮我们添加
*
* 3. 更新数据 http://localhost:3000/todos/3
*    PUT 或者 PATCH
*    PUT 需要提供该对象的所有数据
*    PATCH 只需要提供要修改的数据即可
*
* 4. 删除数据
*    http://localhost:3000/todos/3
*    DELETE
  1. 可以借助 postman 测试接口;

二 : axios 发送请求 (重点掌握)

读音 : /艾克笑丝/

  1. 作用 : 一个专门用来发送 ajax 请求的库, 可以在浏览器或者 node.js 中使用

    Promise based HTTP client for the browser and node.js
    	以Promise为基础的HTTP客户端,适用于:浏览器和node.js
    	封装ajax,用来发送请求,异步获取数据
    
  2. 使用步骤

    1. 本地安装 axios : `npm i axios`
    2. 导入 axios
    3. 使用
    
  3. axios 使用说明

  4. GTE 方式发送请求

    // 方式1
    axios.get('http://localhost:3000/todos/3').then(res => {
      console.log('获取到数据了:', res.data)
    })
    // 方式2
    axios
      .get('http://localhost:3000/menus', {
        params: {
          id: 003
        }
      })
      .then(res => {
        console.log('获取到数据了:', res.data)
      })
    

    5、 POST 方式发送请求

         // post 请求
         axios
             // 第一个参数:表示接口地址
             // 第二个参数:表示接口需要的参数
             .post('http://localhost:3000/todos', {
               name: 'axios添加数据',
               done: true
             }).then ( res =>  打印 res)
    
  5. 使用axios测试 todos 的几种接口

     //1. GET
      // 没有参数
      axios.get('http://localhost:3000/todo').then(res => {
        console.log(res)
      })
      // 有参数
      axios.get('http://localhost:3000/todo/1').then(res => {
        console.log(res)
      })
      axios
        .get('http://localhost:3000/todo', {
          params: {
            id: 2
          }
        })
        .then(res => {
          console.log(res)
        })

      // 2. POST
      axios
        .post('http://localhost:3000/todo', {
          name: 'XXX',
          age: 1
        })
        .then(res => {
          console.log(res)
        })

      //3. 删除
      axios.delete('http://localhost:3000/todo/8', {}).then(res => {
        console.log(res)
      })

      //4. 更新 - put
      axios
        .put('http://localhost:3000/todo/2', {
          name: '111',
          age: 300
        })
        .then(res => {
          console.log(res)
        })

      // 4. 更新 - patch
      axios
        .patch('http://localhost:3000/todo/1', {
          age: 3000
        })
        .then(res => {
          console.log(res)
        })

三 : 完善 TodoMVC

  1. 获取全部

    axios.get('http://localhost:3000/list').then(res => {
        console.log(res.data);
        this.list = res.data;
    });
    
  2. 删除任务

    axios.delete('http://localhost:3000/list/' + id).then(res => {
        this.list = this.list.filter(item => item.id !== id);
        console.log(res);
    });
    
  3. 添加任务

    # id 会自动加
    axios
        .post('http://localhost:3000/list', {
        name: todoName,
        done: false
    })
        .then(res => {
        console.log(res.data);
        this.list.push(res里的对象);
    });
    
  4. 更新任务 (在 hideEdit 里实现)

    # 难点1 : 在 hideEdit 这个方法里
    # 难点2 : 获取的这个id 就是editId
    hideEdit(e) {
    
    axios.patch('http://localhost:3000/list/' + this.editId, {
        name: e.target.value
    }).then(res => {
        console.log(res);
    
        this.editId = -1;
    })
    
    },
    
  5. 删除已经完成 的

    # 因为 这个假接口没有实现以下删除 完毕
    clearCompleted() {
        // 清除已经完成的,,只需要过滤出来未完成的即可
    
        let arr = this.list.filter(item => item.done);
        arr = arr.map(item => item.id);
    
        for (let i = 0; i < arr.length; i++) {
            axios.delete('http://localhost:3000/list/' + arr[i]).then(res => {
                this.list = this.list.filter(item => item.id != arr[i]);
            });
        }
    },
    
  6. 点击修改状态

    # 单独给 checkbox 都注册点击事件
    # @input='stateChanged(item.id)' 
    
    stateChanged(id) {
        let todo = this.list.find(item => item.id == id);
    
        axios.patch('http://localhost:3000/list/' + id, {
            done: !todo.done
            }).then(res => {
            console.log(res);
            });
    }
    

组件 (重难点)

一 : 组件

  • 组件可以看作是一些可复用的ui模块

    • 小到一个标签 : <div>哈哈</div>
    • 大到一个页面 :<div><div><div><div><div></div></div></div></div></div>
  • 一个组件对应 一个实例

  • 组件 === Vue实例 == new Vue ( options )

  • 官网 : 组件是可复用的 Vue 实例

二 : 组件化开发

  • 概念 :将一个完整的页面,抽离成一个个独立的组件,最终,通过这一个个独立组件完成整个的页面(项目)的功能
  • 组件化开发的优势/作用 : 复用

三 : 组件的基本使用

先注册, 再使用

  • Vue 中的两种注册组件的方法 1.全局注册 2.局部注册
全局组件在所有的vue实例中都可以使用
局部组件在所有的当前实例中可以使用
  • 注册全局组件 - 基本使用
/**
 * 第一个参数 : 组件名
 * 第二个参数 : 是一个配置对象, 该配置对象与 Vue 实例的配置对象几乎完全相同
 *        也就是说: vue实例中用到的配置项,和组件中的配置项几乎相同
 */
Vue.component('child', {
  template: `
      <h1 class="red">这是child组件</h1>
      `
})
  • 注意点
    • 注册全局组件也是放到 vm 实例之前
    • 模板只能有一个根节点
    • 组件的配置项和 vue 实例 的配置项一样 (如:data、methods、filters、watch、computed、钩子函数等)
    • 组件的 data 是一个函数 , 并且返回一个对象
// 演示为什么vue在组件中的数据采用函数,而不是对象
// 原因 : 只想让组件复用,不想让数据复用
var Component = function() {}
// 使用对象
Component.prototype.data = {
    demo: 123
}
// 使用函数
Component.prototype.data = function() {
    return {
        demo: 111
    }
}
var component1 = new Component()
var component2 = new Component()
component1.data().demo = '8888'
console.log(component2.data().demo) // 456
  • 使用组件
    • 当标签一样使用 <child></child>

四 : 改造 TodoMVC 成 组件化结构

  • 下载模板 todomvc-at-template + 安装css依赖包 + 清除不要的 + 安装 vue + 实例化
  • 创建一个 components 文件夹
  • 具体步骤
    • 创建一个 todo-head.js
    • 导入 <script src="./components/todo-head.js"></script>
    • 使用 <todo-head></todo-head>

五 : 组件通讯 (介绍)

导入 : 演示子组件访问父组件数据,发现报错

  • 组件是一个独立、封闭的个体

    • 也就是说 : 组件中的数据默认情况下, 只能在组件内部使用,无法直接在组件外部使用

    • 可以将 vue 实例看做一个组件

  • 对于组件之间需要相互使用彼此的情况,应该使用 组件通讯 机制来解决

  • 组件通讯的三种情况 :

    1. 父组件将数据传递给子组件(父 -> 子)
    2. 子组件将数据传递给父组件 (子 => 父)
    3. 非父子组件(兄弟组件)

六 : 父 ==> 子 (重点) 两步

  1. 通过属性, 父组件将要传递的数据,传递给子组件
<child :msg="pmsg"></child>
  1. 子组件通过 props 配置项,来指定要接收的数据
props: ['msg']

// 以后使用
- 组件内 :  msg
- 事件中 : this.msg

完善 TodoMVC => 完成 传值 + 渲染列表页

七 : 子 ==> 父 (重点) 三步

  1. 父组件中提供一个方法
pfn(arg) {

    console.log('父组件中接受到子组件传递过来的数据:', arg)
 }
  1. 通过自定义事件, 父组件将这个方法传递给子组件
// 自定义事件 <child @fn="pfn"></child>
  1. 子组件调用这个方法( 触发父组件中传递过来的自定义事件 )
// 在钩子函数里演示也可以,自己调用
 created() {
    // 调用父组件中的方法 pfn
    // 注意:通过 $emit 方法来触发事件 fn
    // 第一个参数:表示要触发的自定义事件名称,也就是 @fn
    // 第二个参数:表示要传递给父组件的数据
    this.$emit('fn', 'child msg')
}

完善 TodoMVC => 完成 传值 +添加+ 删除+修改数据+清除完成

八 : 目前为止存属性的地方

  1. data
  2. 计算属性
  3. props

九 : 单向数据流(组件与组件之间) (了解)

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

  • 透漏三个问题 :
    • 组件与之间是单向数据流
    • 父级 prop 的更新会向下流动到子组件中
    • 子组件不允许修改父组件传过来的prop数据

vue 是单向的还是双向的 ??

双向 (V <=>M)

单向( 组件 与 组件 )

九 : props 的特点 : 只读

  • 演示验证 props 只读
    • 传的是简单类型 : 修改会报错
    • 传的复杂类型 (地址) : 修改不会报错,是因为地址没有变 ,测试 obj={}立马报错
  • 修改父组件传给子组件的数据

思路 : 把接收过来的数据,保存到 data 中一个临时值 (适用在该组件接收数据只会在当前组件内使用)

  Vue.component('child', {
        template: `
      <div>子组件 {{ cmsg }} </div>
       `,
        data() {
          return {
            cmsg: this.msg
          }
        },
        props: ['msg'],
        created() {
          this.cmsg = 666
        }
      })

完善TodoMVC => 修改状态 + 修改任务

八 : prop 的大小写

  • 官 : HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。

    • html 的标签和 属性 都是一样,忽略大小写
    • <H1 TITLE="哈哈">我是h1</H1>
  • 官 : 这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名不好使了

    • <child :cMsg="pmsg"></child> 会报警告,父传子也接收不到了
    • 原因是 : 接收的属性是:cMsg, 因为忽略大小写,已为 : cmsg
    • 所以已经准备要读取的 是 cmsg 的值,否则要报警告
      You should probably use "c-msg" instead of "cMsg".
  • 方式 1 : 全用小写,不要使用驼峰命名

    • 接收 : cmsg
    • props/读取 :cmsg
  • 方式 2 官 : 需要使用其等价的 kebab-case (短横线分隔命名) 命名: (推荐)

    • 接收 : :c-msg='pmsg'
    • props/读取 : cMsg / this.cMsg
  • 大小写在 父传子和 子传父中的应用 (都是要 带 - 的)

    • 父传子 : :c-msg ==> cMsg 改驼峰 - 因为props
    • 子传父 : @todo-head = 'pAddTodo' ==> this.$emit('todo-head') 不改驼峰
  • 完善 TodoMVC : 底部隐藏+剩余完成数+清除完成

    • 计算属性 : 已知值(todoList 在 根组件) ==> 得到一个新值(子组件里使用)
    • 父 => 子通讯
  • 番外篇 : 方法当属性传、传过来的带:得到的原型

十 : 非父子之间通讯 ( 组件 => 组件 ) (重点)

需求 : 组件 jack ===> 恁弄啥哩 ===> 组件 rose

  • 是通过 事件总线 (event bus 公交车) 的机制 来实现的
  • 事件总线 : 实际上就是一个 空Vue实例
  • 可以实现任意两个组件之间的通讯,而不管两个组件到底有什么样的层级关系
  • 看图
  • 示例 :
// 第一步 : 事件总线
var bus = new Vue()

// 第二步 : 发送数据   可在点击事件里 触发事件
// 参数1 : 唯一标识  参数2:参数
bus.$emit('todo', '恁弄啥哩?')

// 第三步 : 接收数据    可在 created 里 注册事件
bus.$on('todo', arg => {
  console.log('接收过来的', arg)
})

十一 : 开关灯案例

十二 : 注册局部组件

  • 局部组件只能在当前vue实例中使用
  • 示例 :
// 注册局部组件:
components: {
  // child表示组件名称
  // 值为配置对象,与 Vue.component 中的第二个参数相同
  // 注意:子组件child属于 Vue实例,因此,只能在 Vue实例的模板中使用
  child: {
    template: `
            <div>这是局部组件 child</div>
          `
  }
}

十三 : 获取组件(获取DOM元素) - refs

  • 说明 : vm.$refs 一个对象, 持有已注册过 ref 的所有子组件 ( HTML 元素)

  • 使用 :

    1. 注册
    // $refs = {  div : div元素, child:child组件 }
    // 标签
    <div ref="div">哈哈</div>
    // 组件 
    <child ref="child"></child>
    
    1. 注意 : mounted 中使用
    // mounted 操作DOM
    * this.$refs.div
    * this.$refs.child
    
    
  • 注意点 : 如果获取的是一个子组件,那么通过 ref 就能获取到子组件中的 datamethods

    this.$refs.child.num
    this.$refs.child.fn
    
  • 场景 : 一般在第三方的组件中, 可能会用到这个功能

  • 示例 :

// 组件
 <div ref="div">哈哈</div>
 <child ref="child"></child>
// js
 mounted() {
    console.log(this.$refs.div)
    console.log(this.$refs.child.fn)
  }
posted @ 2020-04-22 00:13  handsomehe  阅读(133)  评论(0编辑  收藏  举报