likes
comments
collection
share

Vue实战——饿了么(二)

作者站长头像
站长
· 阅读数 45

Axios

上一次做到了该发接口请求拿真实数据的时候,那么曾经我们使用过很多方式发送接口请求,比如fetchXMLHttpRequest等等,今天在我们的vue项目中,我选用axios发送接口请求。

Axios 是一个基于 promise 的网络请求库,可以用于浏览器node.js

Axios 使用简单,包尺寸小且提供了易于扩展的接口。

当某个工具大家不熟悉如何使用时,一定要学会自行查阅官方文档Axios中文文档 | Axios中文网 (axios-http.cn)

Vue实战——饿了么(二)

安装依赖

npm i axios

上集谈到,因为数据不仅在header中使用,因此我们决定在App.vue中发送接口请求,一般我们使用axios,会在项目中对axios做一定的封装,使其更加优雅,因此我们在src下新建文件夹api,新建文件axios.js

接口地址: ustbhuangyi.com/sell/seller

参照官方文档,在安装完axios之后的接口请求过程应该是:

Vue实战——饿了么(二)

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>

跨域请求错误

此时我们应该能够看到控制台拿到接口请求到的数据,但是我们发现会出现跨域报错

Vue实战——饿了么(二) 因此我们需要先解决一下跨域问题,在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数据了。注意:这里只在开发环境中解决跨域问题,打包之后工具将失效。

Vue实战——饿了么(二)

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自取)

Vue实战——饿了么(二) 从后端接口传来的数据中能看出,什么时候放哪张图,只有通过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>

效果

Vue实战——饿了么(二)

转载自:https://juejin.cn/post/7388278660149231666
评论
请登录