Vue组件化开发和异步编程

1. 组件

  • 组件 (Component) 是 Vue.js 最强大的功能之一
  • 组件可以扩展 HTML 元素,封装可重用的代码

1.1 组件注册

全局注册

  • Vue.component('组件名称', { })
  • 全局组件注册后,任何vue实例都可以用

注意:

  • data值必须是一个函数,同时这个函数要求返回一个对象
  • 组件模板必须是单个根元素
  • 组件模板的内容可以是模板字符串(es6语法,需要浏览器提供支持)
  

补充:组件命名方式有短横线“ - ”和驼峰式2种

局部注册

  • 只能在当前注册它的vue实例中使用
  

1.2 Vue组件之间传值

父组件向子组件传值

  • 以属性的形式绑定值到子组件身上,一种是静态的值,一种是动态绑定(:)
  • 子组件用属性props,以数组方式接收(单向数据传送)
  • 在props中使用驼峰形式,模板中需要使用短横线的形式(html不区分大小写)字符串形式的模板中没有这个限制
  
{{pmsg}}

子组件向父组件传值

  • 子组件用$emit()触发事件
  • $emit() 第一个参数为 自定义的事件名称 第二个参数为需要传递的数据
  • 父组件用v-on 监听子组件的事件
 
{{pmsg}}

兄弟之间的传递

  • 兄弟之间传递数据需要借助于事件中心,通过事件中心传递数据
    • 提供事件中心 var hub = new Vue()
  • 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)
  • 接收数据方,通过mounted(){} 钩子中 触发hub.$on()方法名
  • 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
 
父组件

1.3 组件插槽

  • 作用:父组件向子组件传递内容
  • 组件的最大特性就是复用性,而用好插槽能大大提高组件的可复用能力

匿名插槽

  
有bug发生 有一个警告

具名插槽

  • 具有名字的插槽
  • 使用 中的 "name" 属性绑定元素
  

标题信息

主要内容1

主要内容2

底部信息信息

主要内容1

主要内容2

作用域插槽

  • 父组件对子组件的内容进行加工处理
  • 既可以复用子组件的slot,又可以使slot内容不一致

购物车案例

1. 实现组件化布局

  • 把静态页面转换成组件化模式
  • 把组件渲染到页面上
 

2、实现 标题和结算功能组件

  • 标题组件实现动态渲染
    • 从父组件把标题数据传递过来 即 父向子组件传值
    • 把传递过来的数据渲染到页面上
  • 结算功能组件
    • 从父组件把商品列表list 数据传递过来 即 父向子组件传值
    • 把传递过来的数据计算最终价格渲染到页面上
 

3. 实现列表组件删除功能

  • 从父组件把商品列表list 数据传递过来 即 父向子组件传值
  • 把传递过来的数据渲染到页面上
  • 点击删除按钮的时候删除对应的数据
    • 给按钮添加点击事件把需要删除的id传递过来
      • 子组件中不推荐操作父组件的数据有可能多个子组件使用父组件的数据 我们需要把数据传递给父组件让父组件操作数据
      • 父组件删除对应的数据
 

4. 实现组件更新数据功能 上

  • 将输入框中的默认数据动态渲染出来
  • 输入框失去焦点的时候 更改商品的数量
  • 子组件中不推荐操作数据 把这些数据传递给父组件 让父组件处理这些数据
  • 父组件中接收子组件传递过来的数据并处理
 

5. 实现组件更新数据功能 下

  • 子组件通过一个标识符来标记对用的用户点击 + - 或者输入框输入的内容
  • 父组件拿到标识符更新对应的组件



  
  Document
  


  

2.前后端交互

2.1 接口调用的方式有哪些

原生ajax
基于jQuery的ajax
Fetch
Promise

2.2 url 地址格式有哪些

  • 传统的url

    协议+域名/ip地址+端口+路径+请求参数+锚点

  • Restful形式的url

    请求方式:增删改查 post delete put get

3.异步编程与promise

3.1异步

  • JavaScript的执行环境是「单线程」
  • 所谓单线程,是指JS引擎中负责解释和执行JavaScript代码的线程只有一个,也就是一次只能完成一项任务,这个任务执行完后才能执行下一个,它会「阻塞」其他任务。这个任务可称为主线程
  • 异步模式可以一起执行多个任务
  • JS中常见的异步调用
    • 定时器
    • ajax
    • 事件函数

3.2promise

  • 主要解决异步深层嵌套的c问题
  • promise 提供了简洁的API 使得异步操作更加容易
 
  

基于Promise发送Ajax请求

 
  

3.3 Promise 基本API

实例方法

.then()
  • 得到异步任务正确的结果
.catch()
  • 获取异常信息
.finally()
  • 成功与否都会执行(不是正式标准)
  
  

静态方法

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

区别:返回数据的条件不同,all是所有执行完,race是只要有一个执行完就返回结果

  

3.4 fetch

  • Fetch API是新的ajax解决方案 ,fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象
  • 基于标准的Promises实现,支持async/await,Fetch会返回Promise
  • 使用fetch(url, options).then()

fetch API 中的 HTTP 请求

  • fetch(url, options).then()
  • HTTP协议,它给我们提供了很多的方法,如POST,GET,DELETE,UPDATE,PATCH和PUT
    • 默认的是 GET 请求
    • 需要在options对象中指定对应的method method:请求使用的方法
    • post和普通请求的时候 需要在options设置请求头 headers 和 body
   

fetchAPI 中 响应格式

  • 用fetch来获取数据,如果响应正常返回,我们首先看到的是一个response对象,其中包括返回的一堆原始字节,这些字节需要在收到后,需要我们通过调用方法将其转换为相应格式的数据,比如JSONBLOB或者TEXT等等
    /*
      Fetch响应结果的数据格式
    */
    fetch('http://localhost:3000/json').then(function(res){
      return res.json();   //  将获取到的数据使用 json 转换对象
      // return res.text(); //  将获取到的数据 转换成字符串 
    }).then(function(data){
      // console.log(data.uname)
      // console.log(typeof data)
      console.log(obj.uname,obj.age,obj.gender)
    })

3.5 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(res){ 
    //   拿到 res 是一个对象      所有的对象都存在 res 的data 属性里面
    // 注意:data属性用于获取后台的实际数据
    // console.log(res.data)
    console.log(res)
})

//服务端
app.get('/adata', (req, res) => {
    res.send('ok');
})


//  2.  get 请求传递参数
//  2.1  通过传统的url  以 ? 的形式传递参数
axios.get('http://localhost:3000/axios?id=123').then(res => {
    console.log(res)
})

//服务端
app.get('/adata', (req, res) => {
    res.send(req.query.id);
})

//  2.2  restful 形式传递参数 
axios.get('http://localhost:3000/axios/123').then(res => {
    console.log(res)
})

//服务端
app.get('/adata/:id', (req, res) => {
    res.send(req.params.id);
})

//  2.3  通过params  形式传递参数 
axios.get('http://localhost:3000/axios', {
    params: {
        id: 789
    }
}).then(res => {
    console.log(res)
})

//服务端(同2.1)
app.get('/adata', (req, res) => {
    res.send(req.query.id);
})

// 3 axios delete 请求传参     传参的形式和 get 请求一样
axios.delete('http://localhost:3000/axios', {
    params: {
        id: 111
    }
}).then(function(ret){
    console.log(ret.data)
})
//服务端(同2.1)
app.delete('/adata', (req, res) => {
    res.send(req.query.id);
})

//  4  axios 的 post 请求
//  4.1  通过选项传递参数
axios.post('http://localhost:3000/axios', {
    uname: 'lisi',
    pwd: 123
}).then(function(ret){
    console.log(ret.data)
})
//服务端
app.post('/axios', (req, res) => {
  res.send(req.body.uname + '---' + req.body.pwd)
})

//  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)
})
//服务端
app.put('/axios/:id', (req, res) => {
  res.send(req.params.id + '---' + req.body.uname + '---' + req.body.pwd)
})

axios响应结果

  • data 实际响应回来的数据

  • headers 响应头

  • status响应状态码

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) //http://localhost:3000/adata
    //  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)
})

axios.get('http://localhost:3000/adata').then(function(data){
      console.log(data)//服务端返回的“Hello axios!”
})

4. async 和 await

async/await是ES7引入的

  • 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)
    })

5. 图书列表案例

1. 基于接口案例-获取图书列表

  • 导入axios 用来发送ajax
  • 把获取到的数据渲染到页面上
  
编号 名称 时间 操作
{{item.id}} {{item.name}} {{item.date }} 修改 | 删除
1. 导入axios

2 添加图书

  • 获取用户输入的数据 发送到后台
  • 渲染最新的数据到页面上
 methods: {
    handle: async function(){
          if(this.flag) {
            // 编辑图书
            // 就是根据当前的ID去更新数组中对应的数据
            this.books.some((item) => {
              if(item.id == this.id) {
                item.name = this.name;
                // 完成更新操作之后,需要终止循环
                return true;
              }
            });
            this.flag = false;
          }else{
            //  1.1  在前面封装好的 handle 方法中  发送ajax请求  
            //  1.2  使用async  和 await 简化操作 需要在 function 前面添加 async   
            var ret = await axios.post('books', {
              name: this.name
            })
            //  1.3  根据后台返回的状态码判断是否加载数据 
            if(ret.status == 200) {
             //  1.4  调用 queryData 这个方法  渲染最新的数据 
              this.queryData();
            }
          }
          // 清空表单
          this.id = '';
          this.name = '';
        },        
 }         

3 验证图书名称是否存在

  • 添加图书之前发送请求验证图示是否已经存在
  • 如果不存在 往后台里面添加图书名称
    • 图书存在与否只需要修改submitFlag的值即可
 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;
          }
        }
},

4. 编辑图书

  • 根据当前书的id 查询需要编辑的书籍
  • 需要根据状态位判断是添加还是编辑
 methods: {
        handle: async function(){
          if(this.flag) {
            // 4.3 编辑图书   把用户输入的信息提交到后台
            var ret = await axios.put('books/' + this.id, {
              name: this.name
            });
            if(ret.status == 200){
              // 4.4  完成添加后 重新加载列表数据
              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){
          // 4.1  flag状态位用于区分编辑和添加操作
          this.flag = true;
          // 4.2  根据id查询出对应的图书信息  页面中可以加载出来最新的信息
          //  调用接口发送ajax 请求  
          var ret = await axios.get('books/' + id);
          this.id = ret.id;
          this.name = ret.name;
        },

5 删除图书

  • 把需要删除的id书籍 通过参数的形式传递到后台
   deleteBook: async function(id){
          // 删除图书
          var ret = await axios.delete('books/' + id);
          if(ret.status == 200) {
            // 重新加载列表数据
            this.queryData();
          }
   }

你可能感兴趣的:(Vue组件化开发和异步编程)