FrontEnd笔记 -- Vue 异步请求

六、异步请求

6.1 跨域问题

  • 跨域

安装 Axios:npm install axios

App running at - Local: http://localhost:8080/

  1. 编写异步请求
<template>
    <div>
        <button @click="getStudents">获取学生信息</button>
    </div>
</template>

<script>
    import axios from 'axios'

    export default {
        name: 'App',
        methods: {
            getStudents() {
                axios.get("http://localhost:5000/students").then(
                    response => {
                        console.log('请求成功了 ', response.data)
                    },
                    error => {
                        console.log('请求失败了 ', error.message)
                    }
                )
            }
        }
    }
</script>
  1. 准备服务端 API
GET http://127.0.0.1:5000/students

[
    {
        "id": "001",
        "name": "tom",
        "age": 18
    },
    {
        "id": "002",
        "name": "jerry",
        "age": 19
    },
    {
        "id": "003",
        "name": "tony",
        "age": 120
    }
]
GET http://127.0.0.1:5001/cars

[
    {
        "id": "001",
        "name": "奔驰",
        "price": 199
    },
    {
        "id": "002",
        "name": "马自达",
        "price": 109
    },
    {
        "id": "003",
        "name": "捷达",
        "price": 120
    }
]
  1. 由于端口不一致出现跨域问题

在这里插入图片描述

  • 跨域问题解决

Vue 解决跨域参考:https://cli.vuejs.org/zh/config/#devserver-proxy

  1. 配置 vue.config.js
module.exports = {
    // 可以在 '/vue.config.js' 下覆盖 Vue 的默认配置,如配置则必须指定 'entry' 入口文件
    pages: {
        index: {
            entry: 'src/main.js'
        }
    },
    lintOnSave: false, // 关闭语法检查
    // 开启代理服务器
    devServer: {
        proxy: {
            '/school': {
                target: 'http://localhost:5000',
                pathRewrite: {'^/school': ''},
                ws: true, // 用于支持 websocket
                changeOrigin: true // 用于控制请求头中的 host 值(false = localhost:8080, true = localhost:5000)
            },
            '/store': {
                target: 'http://localhost:5001',
                pathRewrite: {'^/store': ''},
                ws: true,
                changeOrigin: true
            }
        }
    }
}
  1. 修改请求路径
<template>
    <div>
        <button @click="getStudents">获取学生信息</button>
        <button @click="getCars">获取汽车信息</button>
    </div>
</template>

<script>
    import axios from 'axios'

    export default {
        name: 'App',
        methods: {
            getStudents() {
                axios.get("http://localhost:8080/school/students").then(
                    response => {
                        console.log('请求成功了 ', response.data)
                    },
                    error => {
                        console.log('请求失败了 ', error.message)
                    }
                )
            },
            getCars() {
                axios.get("http://localhost:8080/store/cars").then(
                    response => {
                        console.log('请求成功了 ', response.data)
                    },
                    error => {
                        console.log('请求失败了 ', error.message)
                    }
                )
            }
        }
    }
</script>
  1. 不再出现跨域问题

在这里插入图片描述

6.2 Github 用户搜索案例

在这里插入图片描述

  • 静态组件拆分
  1. App.vue
<template>
    <div class="container">
        <Search/>
        <List/>
    </div>
</template>

<script>
    import Search from './components/Search.vue'
    import List from './components/List.vue'

    export default {
        name: 'App',
        components: {Search, List}
    }
</script>
  1. Search.vue
<template>
    <div>
        <section class="jumbotron">
            <h3 class="jumbotron-heading">Search Github Users</h3>
            <div>
                <input type="text" placeholder="enter the name you search"/>&nbsp;<button>Search</button>
            </div>
        </section>
    </div>
</template>

<script>
    export default {
        name: 'Search'
    }
</script>
  1. List.vue
<template>
    <div>
        <div class="row">
            <div class="card">
                <a href="https://github.com/xxxxxx" target="_blank">
                <img src="https://cn.vuejs.org/images/logo.svg" style='width: 100px'/>
                </a>
                <p class="card-text">xxxxxx</p>
            </div>
            <div class="card">
                <a href="https://github.com/xxxxxx" target="_blank">
                <img src="https://cn.vuejs.org/images/logo.svg" style='width: 100px'/>
                </a>
                <p class="card-text">xxxxxx</p>
            </div>
        </div>
    </div>
</template>

<script>
    export default {
        name: 'List'
    }
</script>
    
<style scoped>
    .album {
    min-height: 50rem; /* Can be removed; just added for demo purposes */
    padding-top: 3rem;
    padding-bottom: 3rem;
    background-color: #f7f7f7;
    }

    .card {
    float: left;
    width: 33.333%;
    padding: .75rem;
    margin-bottom: 2rem;
    border: 1px solid #efefef;
    text-align: center;
    }

    .card > img {
    margin-bottom: .75rem;
    border-radius: 100px;
    }

    .card-text {
    font-size: 85%;
    }
</style>
  1. 外部样式引入

在这里插入图片描述

  1. 静态效果

在这里插入图片描述

  • 实现动态请求
  1. Search 接收关键词发送请求并通过消息总线回调传值
<template>
    <div>
        <section class="jumbotron">
            <h3 class="jumbotron-heading">Search Github Users</h3>
            <div>
                <input type="text" placeholder="enter the name you search" v-model="keyWord"/>&nbsp;
                <button @click="searchUsers">Search</button>
            </div>
        </section>
    </div>
</template>

<script>
    import axios from 'axios'

    export default {
        name: 'Search',
        data() {
            return {
                keyWord: ''
            }
        },
        methods: {
            searchUsers() {
                axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
                    response => {
                        this.$bus.$emit('getUsers', response.data.items)
                    },
                    error => {
                        console.log('请求失败了', error.message)
                    }
                )
            }
        }
    }
</script>
  1. List 动态展示数据
<template>
    <div class="row">
        <div class="card" v-for="user in users" :key="user.login">
            <a :href="user.html_url" target="_blank">
            <img :src="user.avatar_url" style='width: 100px'/>
            </a>
            <p class="card-text">{{user.login}}</p>
        </div>
    </div>
</template>

<script>
    export default {
        name: 'List',
        data() {
            return {
                users: []
            }
        },
        mounted() {
            this.$bus.$on('getUsers', (users) => {
                this.users = users
            })
        }
    }
</script>

在这里插入图片描述

  • 细节调优(欢迎信息、请求中、请求失败信息)
  1. List 改造
<template>
    <div class="row">
        <!-- 展示用户列表 -->
        <div v-show="listInfo.users.length" class="card" v-for="user in listInfo.users" :key="user.login">
            <a :href="user.html_url" target="_blank">
            <img :src="user.avatar_url" style='width: 100px'/>
            </a>
            <p class="card-text">{{user.login}}</p>
        </div>
        <!-- 展示欢迎词 -->
        <h1 v-show="listInfo.isFirst">欢迎使用!</h1>
        <!-- 展示加载中 -->
        <h1 v-show="listInfo.isLoading">加载中...</h1>
        <!-- 展示错误信息 -->
        <h1 v-show="listInfo.errMsg">{{listInfo.errMsg}}</h1>
    </div>
</template>

<script>
    export default {
        name: 'List',
        data() {
            return {
                // 将 List 中的数据作为一个整体
                listInfo: {
                    isFirst: true,
                    isLoading: false,
                    errMsg: '',
                    users: []
                }
            }
        },
        mounted() {
            this.$bus.$on('updateListData', (dataObj) => {
                // 将 dataObj 里有的数据更新到 listInfo
                this.listInfo = {...this.listInfo, ...dataObj}
            })
        }
    }
</script>
  1. Search 改造
<template>
    <div>
        <section class="jumbotron">
            <h3 class="jumbotron-heading">Search Github Users</h3>
            <div>
                <input type="text" placeholder="enter the name you search" v-model="keyWord"/>&nbsp;
                <button @click="searchUsers">Search</button>
            </div>
        </section>
    </div>
</template>

<script>
    import axios from 'axios'

    export default {
        name: 'Search',
        data() {
            return {
                keyWord: ''
            }
        },
        methods: {
            searchUsers() {
                // 请求前更新 List 的数据
                this.$bus.$emit('updateListData', {isFirst: false, isLoading: true, errMsg: '', users: []})
                axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
                    response => {
                        // 请求成功后更新 List 的数据
                        this.$bus.$emit('updateListData', {isLoading: false, errMsg: '', users: response.data.items})
                    },
                    error => {
                        // 请求失败后更新 List 的数据
                        this.$bus.$emit('updateListData', {isLoading: false, errMsg: error.message, users: []})
                    }
                )
            }
        }
    }
</script>

6.3 插槽 slot

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

6.3.1 不使用插槽

在这里插入图片描述

  1. App.vue
<template>
    <div class="container">
        <Category title="美食" :listData="foods"/>
        <Category title="游戏" :listData="games"/>
        <Category title="电影" :listData="films"/>
    </div>
</template>

<script>
    import Category from './components/Category.vue'

    export default {
        name: 'App',
        data() {
            return {
                foods: ['火锅', '烧烤', '小龙虾', '牛排'],
                games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽'],
                films: ['《教父》', '《拆弹专家》', '《你好,李焕英》', '《尚硅谷》']
            }
        },
        components: {Category}
    }
</script>

<style>
    .container {
        display: flex;
        justify-content: space-around;
    }
</style>
  1. Category.vue
<template>
    <div class="category">
        <h3>{{title}}分类</h3>
        <ul>
            <li v-for="(item, index) in listData" :key="index">{{item}}</li>
        </ul>
    </div>

</template>

<script>
    export default {
        name: 'Category',
        props: ['title', 'listData']
    }
</script>

<style>
    .category {
        background-color: skyblue;
        width: 200px;
        height: 300px;
    }
    h3 {
        text-align: center;
        background-color: orange;
    }
</style>

6.3.2 默认插槽

不同的数据页展示不同类型的数据。

在这里插入图片描述

<template>
    <div class="container">
        <Category title="美食">
            <img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
        </Category>
        <Category title="游戏">
            <ul>
                <li v-for="(game,index) in games" :key="index">{{game}}</li>
            </ul>
        </Category>
        <Category title="电影">
            <video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
        </Category>
    </div>
</template>
<template>
    <div class="category">
        <h3>{{title}}分类</h3>
        <!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
		<slot>我是一些默认值,当使用者没有传递具体结构时,我会出现</slot>
    </div>

</template>

6.3.3 具名插槽

同个组件需要传递多个插槽时。

在这里插入图片描述

<template>
	<div class="container">
		<Category title="美食" >
			<img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
			<a slot="footer" href="http://www.atguigu.com">更多美食</a>
		</Category>

		<Category title="游戏" >
			<ul slot="center">
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
			<div class="foot" slot="footer">
				<a href="http://www.atguigu.com">单机游戏</a>
				<a href="http://www.atguigu.com">网络游戏</a>
			</div>
		</Category>

		<Category title="电影">
			<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
			<template v-slot:footer>
				<div class="foot">
					<a href="http://www.atguigu.com">经典</a>
					<a href="http://www.atguigu.com">热门</a>
					<a href="http://www.atguigu.com">推荐</a>
				</div>
				<h4>欢迎前来观影</h4>
			</template>
		</Category>
	</div>
</template>
<template>
	<div class="category">
		<h3>{{title}}分类</h3>
		<!-- 定义一个插槽(挖个坑,等着组件的使用者进行填充) -->
		<slot name="center">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
		<slot name="footer">我是一些默认值,当使用者没有传递具体结构时,我会出现2</slot>
	</div>
</template>

6.3.4 作用域插槽

理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)

在这里插入图片描述

<template>
	<div class="container">

		<Category title="游戏">
			<template scope="atguigu">
				<ul>
					<li v-for="(g,index) in atguigu.games" :key="index">{{g}}</li>
				</ul>
			</template>
		</Category>

		<Category title="游戏">
			<template scope="{games}">
				<ol>
					<li style="color:red" v-for="(g,index) in games" :key="index">{{g}}</li>
				</ol>
			</template>
		</Category>

		<Category title="游戏">
			<template slot-scope="{games}">
				<h4 v-for="(g,index) in games" :key="index">{{g}}</h4>
			</template>
		</Category>

	</div>
</template>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值