Vue 中的Ajax

Vue 中的Ajax

配置代理

发送ajax请求的方式:

1.xhr new XMLHttpRequest()

  • xhr.open() 配置请求信息

  • xhr.send() 发送请求

  • 虽是鼻祖,但很麻烦,一般对其进行二次封装

2.jQuery

  • $.get

  • $.post

  • jQuery的核心是 DOM操作,在vue等框架中不常使用

3.axios

  • 与jQuery相比的优势是 promise风格

  • 支持请求拦截器和响应拦截器

  • 体积小

4.fetch

  • jQuery和axios 都是对xhr的封装,fetch是与xhr平级

  • 是 promise风格

  • 会包两层 promise

  • 兼容性较差

 

下面解决 ajax 请求跨域问题

<template>
  <div>
    <button @click="sendRequest">点击发送请求</button>
  </div>
</template>
​
<script>
import axios from "axios";
export default {
    name:'App',
    methods:{
      sendRequest(){
        axios.get('http://localhost:5000/students').then(
            response =>{
              console.log("请求成功,", response.data)
            },
            error =>{
              console.log("请求失败",error.message)
            }
        )
      }
    }
}
</script>

上面是没有解决跨域问题

image-20240627184009190

结果是请求失败

所谓跨域就是违背了同源策略

同源策略规定 协议名、主机名、端口号必须一致

目前的情况是 http://localhost:8080http://localhost:5002 发送请求,所以跨域了

请求也发了,服务器也回应了,但是浏览器发现跨域后,没有把数据返回

如何解决?

  1. 用 cors,服务器返回的时候携带了一些特殊的响应头,所以能收到发来的数据

  2. 用 jsonp,借助了script标签里面的src 属性在引入外部资源时不受同源限制 来解决的,只能解决get请求

  3. 配置一台代理服务器,代理服务器和主机所处的端口相同,主机想要访问数据时,直接向代理服务器发送请求,代理服务器再向服务器请求

    代理服务器和服务器打交道不用ajax请求

开启代理服务器的方法

  • nginx

  • vue-cli

在vue.config.js 文件中配置

//   开启代理服务器
devServer:{
    proxy:'http://localhost:5002'
}

在请求时 请求8080端口

axios.get('http://localhost:8080/students').then(
    response =>{
      console.log("请求成功,", response.data)
    },
    error =>{
      console.log("请求失败",error.message)
    }
)

这时就可以请求到数据了

当你请求的资源本身就有,就不会转发给5002服务器了

用这种方式不能配置多个代理,并且不能灵活控制是否向服务器发送请求

还有第二种方式配置代理服务器,能够解决配置多个服务器,并且可以控制是否发送请求

//     方式二
  devServer:{
    proxy:{
      '/api':{
        target:'http://localhost:5002',
        pathRewrite:{'^/api' : ''},
        ws:true,     //用于支持websocket
        changeOrigin:true   //用于控制请求中的host值
      },
      '/api1':{
        target:'http://localhost:5001',
        pathRewrite:{'^/api' : ''},
        ws:true,     //用于支持websocket
        changeOrigin:true   //用于控制请求中的host值
      }
    }
  }

./api 代表的是除了 协议名主机名端口号之外的前缀,只要你的请求中带有这个前缀那么就走代理服务器,向服务器发送请求,请求的服务器地址是 target

这里有个问题,你的请求中是带有 ./api前缀的,那么请求到服务器也会有这个前缀,所以会报找不到资源

这时用 pathRewrite 将前缀替换成 空字符串即可

changeOrigin 如果是 true,那么服务器收到的请求的host 就是服务器的host,否则就是8080,默认值是true

axios.get('http://localhost:8080/api/students').then(
    response =>{
      console.log("请求成功,", response.data)
    },
    error =>{
      console.log("请求失败",error.message)
    }
)

请求时的路径要带前缀 /api

 

插槽

默认插槽

插槽可以动态地将不同的模板插入到指定的位置

下面用一个分类案例引入插槽

一开始是三个分类,分类中是 一个列表,展示每个分类的具体内容

<template>
  <div class="container">
    <Category title="美食" :listData="food"/>
    <Category title="游戏" :listData="game"/>
    <Category title="影视" :listData="movie"/>
  </div>
</template>

在App组件中引入定义的 Category 组件,传入数据

<template>
  <div class="category">
    <h3>{{title}}分类</h3>
    <ul>
      <li v-for="(item,index) in listData" :key="index">{{item}}</li>
    </ul>
  </div>
</template>

在 Category 组件的模板中,定义有一个标题和列表,效果如图

image-20240630114933801

现在的需求改变了,想让 美食分类中只展示一张图片,影视分类展示一段视频,游戏分类不变,这时就用到插槽

首先在Category 组件中,把原先的列表删除,取而代之的是 <slot> 标签,标签里面是默认内容

<template>
  <div class="category">
    <h3>{{title}}分类</h3>
    <slot>默认内容,什么都不传就会展示</slot>
  </div>
</template>

然后在引入 Category 的地方,在 Category 组件标签里添加标签体内容,内容就是想要展示的内容

<template>
  <div class="container">
    <Category title="美食" :listData="food">
      <img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg">
    </Category>
    <Category title="游戏" :listData="game">
      <ul>
        <li v-for="(item,index) in game" :key="index">{{item}}</li>
      </ul>
    </Category>
    <Category title="影视" :listData="movie">
      <video controls src="https://haokan.baidu.com/v?vid=18035948914920602112&tab=recommend"></video>
    </Category>
  </div>
</template>

slot 标签就是在Category 标签中占个位,等待去填充

image-20240630120703302

具名插槽

具名插槽就是拥有名字的插槽,可以指定什么内容往哪个插槽里放

如果想要在内容下面再追加一些内容的话,可以再定义一个插槽,这时存在的两个插槽就要给他们定义名字,否则就会把模板往这两个插槽中放两份

<template>
  <div class="category">
    <h3>{{title}}分类</h3>
    <slot name="center">1默认内容,什么都不传就会展示</slot>
    <slot name="footer">2默认内容,什么都不传就会展示</slot>
  </div>
</template>

用name属性去定义 slot的名字

在使用组件的地方使用 slot 属性指定往哪个插槽中插入

<Category title="美食" :listData="food">
  <img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg">
  <a slot="footer" src="www.baidu.com">跳转到百度</a>
</Category>

指定slot 的时候 还有另外一种写法

就是 用 v-slot:center 用 v-slot 直接绑定某个插槽的名字

这种写法只能使用于 template 标签

 

作用域插槽

当数据在组件定义的地方,而组件的结构是由组件使用者来决定的,那么组件的使用者在使用组件时就获取不到组件中的数据,这时可以用作用域插槽

在组件定义的地方,也就是用 slot标签占位的地方,把数据给组件使用者传递过去

<template>
  <div class="category">
    <h3>{{title}}分类</h3>
    <slot :games="game">1默认内容,什么都不传就会展示</slot>
  </div>
</template>

在使用组件的地方,用scope 或 slot-scope 接收,这里需要注意 必须在template 标签中写这两个属性

属性值可以随意起,它接收到的是一个对象,里面就有组件传递过来的数据

<template>
  <div class="container">
    <Category title="游戏">
      <template scope="appGame">
        <ul>
          <li v-for="(item,index) in appGame.games" :key="index">{{item}}</li>
        </ul>
      </template>
    </Category>
    <Category title="游戏" >
      <template scope="appGame">
        <ol>
          <li v-for="(item,index) in appGame.games" :key="index">{{item}}</li>
        </ol>
      </template>
    </Category>
    <Category title="游戏">
      <template scope="appGame">
        <h4>
          <li v-for="(item,index) in appGame.games" :key="index">{{item}}</li>
        </h4>
      </template>
    </Category>
  </div>
</template>

 

总结

作用:让父组件可以向子组件指定位置插入html结构,也是组件间通信的方式

posted @ 2024-07-01 19:20  GrowthRoad  阅读(2)  评论(0编辑  收藏  举报