在Vue框架中可以有很多方式实现 ajax, 其中有xhr、jQuery、fetch、axios、vue-resource, 其中Vue的作者尤雨溪推荐使用axios,所以在使用Vue框架时,尽量还是使用axios
但是当我们使用ajax时,经常会遇到跨域的问题,比如你本地的端口号是8080, 而服务器的端口号是5050,当你向服务器请求数据时,就会存在跨域的问题。
跨域也有很多的解决方案:
【1】cors方法:不需要前端人员操作,只需要后端人员在写服务器的时候,给你返回响应的时候,会加几个特殊的响应头;
【2】jsonp: 需要后端人员和前端人员都进行相应的操作,不常用 <script src=""></script> 只能解决 GET 请求的跨域问题,其它的请求方式解决不了。
【3】代理 proxy: 在Vue框架中经常使用
因为服务器和服务器之间的数据传输并不是用的ajax,仅仅用的是http,所以不存在跨域的问题,这样本地端口向代理服务器发起请求,而代理服务器目标服务器请求,这样就解决了跨域问题。
1 配置代理服务器
在vue.config.js 中配置
// 1. 开启代理服务器,解决跨域问题(方式一)devServer: {proxy: 'http://localhost:5000' // 需要转发的服务器的端口},// 2.开启代理服务器(方式二)devServer: {proxy: {'/api': { // /api为请求前缀,想要走代理,就在请求的地址前面加上/api,前缀可以根据需要更改target: '<url>', // <url> 为请求的目标地址,比如:http://localhost:5000pathRewrite: {'^/api': '' // 去掉请求路径中的/api},ws: true, // 用于支持websocketchangeOrigin: true // 用于控制请求头中host值},// 配置多个'/api2': { // /api为请求前缀,想要走代理,就在请求的地址前面加上/api,前缀可以根据需要更改target: '<url>', // <url> 为请求的目标地址,比如:http://localhost:5000pathRewrite: {'^/api': '' // 去掉请求路径中的/api},ws: true, // 用于支持websocketchangeOrigin: true // 用于控制请求头中host值}, // 配置多个...// '/foo': {// target: '<other_url>'// }}}
建议使用方式2,可以配置多个代理服务器,还有一个问题就是当请求的资源本地有时,会优先读取本地得信息,不会走代理,这样就不会读取到服务器中真实的信息。所以如果想要指定走代理的话,需要指定请求前缀。
2 请求github数据案例
【List组件】
<template><div class="row"><!-- 展示用户列表 --><div class="card" v-show="info.users.length" v-for="user in info.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="info.isFirst">欢迎使用Github用户搜索</h1><!-- 展示加载中 --><h1 v-show="info.isLoading">加载中...</h1><!-- 展示错误信息 --><h1 v-show="info.errMsg">{{ info.errMsg }}</h1></div>
</template><script>export default {name: 'List',data() {return {info: {isFirst: true,isLoading: false,errMsg: '',users: []}}},mounted() {this.$bus.$on('updateUsers', (dataObj) => {this.info = {...this.info, ...dataObj} // 重名的属性以后面的为主,后面没有的就用前面的})},}
</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>
【Search组件】
<template><div><section class="jumbotron"><h3 class="jumbotron-heading">Search Github Users</h3><div><input type="text" v-model="keyWord" placeholder="enter the name you search"/> <button @click="search">Search</button></div></section></div>
</template><script>import axios from 'axios'export default {name: 'Search',data() {return {keyWord: ''}},methods: {search() {/* 请求前更新List数据 */this.$bus.$emit('updateUsers', { isFirst: false, isLoading: true, errMsg: '', users: []})axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(response => {console.log('请求成功了', response.data.items)/* 请求成功后更新List数据 */this.$bus.$emit('updateUsers', { isLoading: false, errMsg: '', users: response.data.items})},error => {console.log('请求失败了', error.message)/* 请求失败后更新List数据 */this.$bus.$emit('updateUsers', { isLoading: false, errMsg: error.message, users: []})})}},}
</script><style></style>
【App组件】
<template><div class="container"><Search/><List/></div></template><script>import List from './components/List.vue'import Search from './components/Search.vue'export default {name:'App',components:{List,Search},}
</script>
3 插槽
3.1 默认插槽
【App组件】
<template><div class="container"><Category title="美食" :listData="foods"><img src="./assets/imgs/girl6.jpg" alt="" id="pg1"></Category><Category title="游戏" :listData="games"><ul><li v-for="(item,index) in games" :key="index">{{item}}</li></ul></Category><Category title="电影" :listData="films"><img src="./assets/imgs/girl3.jpg" alt="" id="pg1"></Category></div></template><script>import Category from './components/Category.vue'export default {name:'App',components:{Category,},data() {return {foods:['火锅','烧烤','小龙虾','牛排'],games:['红色警戒','穿越火线','劲舞团','超级玛丽'],films:['《教父》','《拆弹专家》','《你好,李焕英》']}},}
</script><style scoped>.container {display: flex;justify-content: space-around;}#pg1 {width: 100%;}</style>
【Category组件】
<template><div class="category"><h1>{{title}}分类</h1><!-- 定义一个插槽 (默认插槽)--><slot></slot></div>
</template><script>export default {name: 'Category',// props: ['listData', 'title']props: ['title']}
</script><style>.category {margin-left: 100px;margin-top: 100px;;width: 200px;height: 300px;background-color: skyblue;border: 1px solid orange;}h1{text-align: center;background-color: pink;}</style>
3.2 具名插槽
【App组件】
<template><div class="container"><Category title="美食" :listData="foods"><img slot="slot1" src="./assets/imgs/girl6.jpg" alt="" id="pg1"><a slot="slot2" href="http://www.baidu.com">百度</a></Category><Category title="游戏" :listData="games"><ul slot="slot1"><li v-for="(item,index) in games" :key="index">{{item}}</li></ul><a slot="slot2" href="http://www.baidu.com">百度</a></Category><Category title="电影" :listData="films"><img slot="slot1" src="./assets/imgs/girl3.jpg" alt="" id="pg1"><!-- <a slot="slot2" href="http://www.baidu.com">百度</a><h4 slot="slot2">欢迎光临</h4> --><!-- 使用 template标签这种写法时,就可以使用另一种写法 v-slot: 指定放入的插槽了 --><template v-slot:slot2><a href="http://www.baidu.com">百度</a><h4>欢迎光临</h4></template></Category></div></template><script>import Category from './components/Category.vue'export default {name:'App',components:{Category,},data() {return {foods:['火锅','烧烤','小龙虾','牛排'],games:['红色警戒','穿越火线','劲舞团','超级玛丽'],films:['《教父》','《拆弹专家》','《你好,李焕英》']}},}
</script><style scoped>.container {display: flex;justify-content: space-around;}#pg1 {width: 100%;}</style>
【Category组件】
<template><div class="category"><h1>{{title}}分类</h1><!-- 定义一个插槽 (具名插槽)--><slot name="slot1">我是插槽1, 没有内容放入时,会显示</slot><slot name="slot2">我是插槽1, 没有内容放入时,会显示</slot></div>
</template><script>export default {name: 'Category',// props: ['listData', 'title']props: ['title']}
</script><style>.category {margin-left: 100px;margin-top: 100px;;width: 200px;height: 300px;background-color: skyblue;border: 1px solid orange;}h1{text-align: center;background-color: pink;}</style>
3.3 作用域插槽
【Category组件】
<template><div class="category"><h1>{{title}}分类</h1><!-- 定义一个插槽 (作用域插槽)--><slot :games="games" :msg="msg">我是插槽1, 没有内容放入时,会显示</slot> <!-- games传递给插槽的使用者 --></div>
</template><script>export default {name: 'Category',// props: ['listData', 'title']props: ['title'],data() {return {games:['红色警戒','穿越火线','劲舞团','超级玛丽'],msg:'你好啊'}},}
</script><style>.category {margin-left: 100px;margin-top: 100px;;width: 200px;height: 300px;background-color: skyblue;border: 1px solid orange;}h1{text-align: center;background-color: pink;}</style>
【App组件】
<template><div class="container"><Category title="游戏"><template scope="data"><ul><li v-for="(item,index) in data.games" :key="index">{{item}}</li></ul></template></Category><Category title="游戏"><!-- 解构赋值的写法 --><!-- 也可以使用 slot-scope="{games, msg}" --><template scope="{games, msg}"><ol><li v-for="(item,index) in games" :key="index" style="color:red">{{item}}</li></ol><h4>{{msg}}</h4></template></Category><Category title="游戏"><template scope="data"><h3><li v-for="(item,index) in data.games" :key="index">{{item}}</li></h3></template></Category></div></template><script>import Category from './components/Category.vue'export default {name:'App',components:{Category,}, }
</script><style scoped>.container {display: flex;justify-content: space-around;}
</style>