Vue实战——饿了么(二)
Axios
上一次做到了该发接口请求拿真实数据的时候,那么曾经我们使用过很多方式发送接口请求,比如fetch
,XMLHttpRequest
等等,今天在我们的vue项目中,我选用axios发送接口请求。
Axios 是一个基于 promise
的网络请求库,可以用于浏览器
和 node.js
Axios 使用简单,包尺寸小且提供了易于扩展的接口。
当某个工具大家不熟悉如何使用时,一定要学会自行查阅官方文档Axios中文文档 | Axios中文网 (axios-http.cn)
安装依赖
npm i axios
上集谈到,因为数据不仅在header中使用,因此我们决定在App.vue中发送接口请求,一般我们使用axios,会在项目中对axios做一定的封装,使其更加优雅,因此我们在src下新建文件夹api,新建文件axios.js
接口地址: ustbhuangyi.com/sell/seller
参照官方文档,在安装完axios之后的接口请求过程应该是:
axios封装
因此我们在axios.js中进行封装:
axios.js
import axios from "axios";
const baseUrl = 'http://ustbhuangyi.com/sell/'
export function get(url) {
return function (params = {}) {
return axios.get(baseUrl + url, {
params
}).then(res => {
const { errno, data } = res.data
if (errno === 0) {
return data;
}
}).catch(err => {
console.log(err);
})
}
}
因为后续还会有很多的接口,有很多个export,为了让代码更优雅,再在api文件夹下对axios进一步封装,创建index.js文件
indexjs
import { get } from './axios.js'
const getSeller = get('seller')
export {
getSeller
}
// getSeller().then
此时,我们把getSeller抛出后,里面得到的promise对象返回出来的data就可以拿到App.vue中去使用了
App.vue
<template>
<Header />
</template>
<script setup>
import Header from '@/components/header/Index.vue'
import { getSeller } from './api/index.js';
// ajax request seller
getSeller().then(seller => {
console.log(seller);
})
</script>
<style lang="less" scoped></style>
跨域请求错误
此时我们应该能够看到控制台拿到接口请求到的数据,但是我们发现会出现跨域报错
因此我们需要先解决一下跨域问题,在vite.config.js中添加一下vue已经封装好了的解决跨域问题的代码
server: {
proxy: {
'/api': {
target: 'http://ustbhuangyi.com/sell/',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, '/api')
}
}
}
那么此时的axios.js中的baseUrl的路径就不再是'ustbhuangyi.com/sell/',而是改成…' 再回头看浏览器已经能够拿到data数据了。注意:这里只在开发环境中解决跨域问题,打包之后工具将失效。
1. avatar: "http://static.galileo.xiaojukeji.com/static/tms/seller_avatar_256px.jpg"
1. bulletin: "粥品香坊其烹饪粥料的秘方源于中国千年古法,在融和现代制作工艺,由世界烹饪大师屈浩先生领衔研发。坚守纯天然、0添加的良心品质深得消费者青睐,发展至今成为粥类的引领品牌。是2008年奥运会和2013年园博会指定餐饮服务商。"
1. deliveryPrice: 4
1. deliveryTime: 38
1. description: "蜂鸟专送"
1. foodScore: 4.3
1. infos: (4) ['该商家支持发票,请下单写好发票抬头', '品类:其他菜系,包子粥店', '北京市昌平区回龙观西大街龙观置业大厦底商B座102单元1340', '营业时间:10:00-20:30']
1. minPrice: 20
1. name: "粥品香坊(回龙观)"
1. pics: (4) ['http://fuss10.elemecdn.com/8/71/c5cf5715740998d5040dda6e66abfjpeg.jpeg?imageView2/1/w/180/h/180', 'http://fuss10.elemecdn.com/b/6c/75bd250e5ba69868f3b1178afbda3jpeg.jpeg?imageView2/1/w/180/h/180', 'http://fuss10.elemecdn.com/f/96/3d608c5811bc2d902fc9ab9a5baa7jpeg.jpeg?imageView2/1/w/180/h/180', 'http://fuss10.elemecdn.com/6/ad/779f8620ff49f701cd4c58f6448b6jpeg.jpeg?imageView2/1/w/180/h/180']
1. rankRate: 69.2
1. ratingCount: 24
1. score: 4.2
1. sellCount: 90
1. serviceScore: 4.1
1. supports: (5) [{…}, {…}, {…}, {…}, {…}]
1. [[Prototype]]: Object
组件通信
能够看见,数据中有avatar头像、信息等等,接下来我们就把数据渲染到Header中,也就是组件通信,父组件拿到数据传递给子组件。
App.vue
<template>
<Header :seller="sellerData" />
</template>
<script setup>
import Header from '@/components/header/Index.vue'
import { getSeller } from './api/index.js';
import { ref } from 'vue';
let sellerData = ref({});
// ajax request seller
getSeller().then(seller => {
sellerData.value = seller;
// console.log(seller);
})
</script>
<style lang="less" scoped></style>
子组件接收数据defineprops,然后渲染到页面。
Index.vue
<template>
<div class="header">
<!-- 上面部分 -->
<div class="content-wrapper">
<!-- 商家/店铺头像 -->
<div class="avatar">
<img :src="seller.avatar" alt="">
</div>
<div class="content">
<div class="title">
<span class="brand"></span>
<span class="name">{{ seller.name }}</span>
</div>
<div class="description">
{{ seller.description }}/{{ seller.deliveryTime }}分钟送达
</div>
<div class="support" v-if="seller.supports">
<!-- pic -->
<span class="text">{{ seller.supports && seller.supports[0].description }}</span>
</div>
</div>
<div class="support-count">
<span class="count">{{ seller.supports.length }}个</span>
<i class="iconfont icon-youjiantou"></i>
</div>
</div>
<!-- 下面的公告部分 -->
<div class="bulletin-wrapper">
</div>
</div>
</template>
<script setup>
defineProps({
seller: {
type: Object,
default: () => { }
}
})
</script>
<style lang="less" scoped>
@import '@/assets/variable.less';
@import '@/assets/mixin.less';
.header {
position: relative;
overflow: hidden;
color: @color-white;
background-color: @color-background-ss;
}
.content-wrapper {
display: flex;
padding: 24px 12px 18px 24px;
position: relative;
}
.avatar {
flex: 0 0 64px;
margin-right: 16px;
img {
width: 100%;
border-radius: 2px;
}
}
.content {
flex: 1;
.title {
display: flex;
margin-bottom: 8px;
.brand {
width: 30px;
height: 18px;
.bg-image('brand');
background-size: 100% 100%;
background-repeat: no-repeat;
}
.name {
margin-left: 6px;
font-size: @fontsize-large;
font-weight: bold;
}
}
.description {
font-size: @fontsize-small;
margin-bottom: 8px;
}
.support {
display: flex;
align-items: center;
.text {
font-size: @fontsize-small-s;
margin-left: 4px;
}
}
}
.support-count {
position: absolute;
right: 12px;
bottom: 14px;
padding: 0 8px;
height: 24px;
line-height: 24px;
text-align: center;
background-color: @color-background-sss;
border-radius: 14px;
display: flex;
align-items: center;
.count {
font-size: @fontsize-small-s;
}
.iconfont {
font-size: 8px;
margin-left: 2px;
}
}
</style>
目前header数据就已经全部换成了真实数据,但是在线支付前面还有一个图片,到底放哪一张?(gitee自取)
从后端接口传来的数据中能看出,什么时候放哪张图,只有通过type来确定,当type威0的时候放减,当type为1的时候放折...因此我们就在组件标签上绑定一个type属性,再在组件中通过defineprops接收值,默认为0
Index.vue
<template>
<span class="support-icon" :class="iconCls"></span>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
type: {
type: Number,
default: 0
},
size: {
type: String,
default: '1'
}
})
const calssMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee']
const iconCls = computed(() => {
return `icon-${props.size} ${calssMap[props.type]}` // 'icon-1 discount'
})
</script>
<style lang="less" scoped>
@import '@/assets/mixin.less';
.support-icon {
display: inline-block;
background-repeat: no-repeat;
}
.icon-1 {
width: 12px;
height: 12px;
background-size: 100% 100%;
&.decrease {
.bg-image('decrease_1')
}
&.discount {
.bg-image('discount_1')
}
&.special {
.bg-image('special_1')
}
&.invoice {
.bg-image('invoice_1')
}
&.guarantee {
.bg-image('guarantee_1')
}
}
.icon-2 {
width: 16px;
height: 16px;
background-size: 100% 100%;
&.decrease {
.bg-image('decrease_2')
}
&.discount {
.bg-image('discount_2')
}
&.special {
.bg-image('special_2')
}
&.invoice {
.bg-image('invoice_2')
}
&.guarantee {
.bg-image('guarantee_2')
}
}
.icon-3 {
width: 12px;
height: 12px;
background-size: 100% 100%;
&.decrease {
.bg-image('decrease_3')
}
&.discount {
.bg-image('discount_3')
}
&.special {
.bg-image('special_3')
}
&.invoice {
.bg-image('invoice_3')
}
&.guarantee {
.bg-image('guarantee_3')
}
}
.icon-4 {
width: 16px;
height: 16px;
background-size: 100% 100%;
&.decrease {
.bg-image('decrease_4')
}
&.discount {
.bg-image('discount_4')
}
&.special {
.bg-image('special_4')
}
&.invoice {
.bg-image('invoice_4')
}
&.guarantee {
.bg-image('guarantee_4')
}
}
</style>
效果
转载自:https://juejin.cn/post/7388278660149231666