VUE 前端,TP5(thinkPHP5)后端,axios 请求第一个(聚合数据)接口,解决跨城问题

问题描述:

1: 用 VUE 当前端
2: 用 TP5(thinkPHP5) 当后端
3: 前端请求后端接口

前端界面如下:ElementUI 使用(仿了一个 admin-vue 后端)
VUE 前端,TP5(thinkPHP5)后端,axios 请求第一个(聚合数据)接口,解决跨城问题

分成头部、左侧、右侧

router.js

import Vue from 'vue'
import Router from 'vue-router'
import Main from '@/components/Main'
import Right from '@/components/Right'
import Joke from '@/components/apis/Api_1'

Vue.use(Router)

export default new Router({
    mode: 'history',
    routes: [
        { path: '/',
          component: Main,
          children: [
            { path: '', component: Right },
            { path: 'joke', component: Joke }
          ]
        }
    ]
})

右侧代码:

<template>
    <div class="content-box content-right">
        <el-card class="box-card api-card" @mouseenter="goon = !goon" @mouseleave="goon = !goon">
            <div slot="header" class="clearfix">
                <span>API 列表</span>
                <el-button class="refreshBtn" type="text">刷新</el-button>
            </div>

            <div class="card-list">
                <el-card v-for="api in apiItems" :key="api.nmb" class="box-card sub-box-card">
                    <div class="sub-box-body">
                        <img class="image" :src="api.src" :alt="api.alt" />
                        <h2 class="title"></h2>
                        <p>{{ api.name }}</p>
                    </div>
                    <a class="click-btn" :href="api.link">点击使用</a>
                </el-card>

            </div>
        </el-card>
    </div>
</template>

<script>
import eventBus from '../../static/js/eventBus' // 根据 header 里面的传值

export default {
    name: 'right',
    mounted () {
        this.getApis()
        eventBus.$on('collapseOrNot', (data) => { // 对位置的绝对值进行重写
            console.log(data)
            let contentRightWidth = document.getElementsByClassName('content-right')[0]
            if (data) {
                contentRightWidth.style.left = '65px'
            } else {
                contentRightWidth.style.left = '158px'
            }
        })
    },
    data () {
        return {
            apiItems: ''
        }
    },
    methods: {
        getApis () {
            this.$axios.get('/static/json/apis.json').then(res => { // 获取 apis.json 里面的数据
                if (res.data.code === 200) { this.apiItems = res.data.data }
            }).catch(error => {
                console.log(error)
            })
        }
    }

}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

.content-box {
    padding: 1rem;
    position: absolute;
    left: 158px;
    top: 6rem;
    bottom: 0;
    padding-bottom: 30px;
    -webkit-transition: left .3s ease-in-out;
    transition: left .1s ease-in-out;
    background: #ffffff;
}
.clearfix:before, .clearfix:after {
    display: table;
    content: "";
}
.clearfix:after {
    clear: both
}

.api-card {
    padding-bottom: 2rem;
}

.refreshBtn {
    float: right; padding: 3px 0;
}

.sub-box-card {
    text-align: center;
    width: 9rem;
    float: left;
    margin: 0 2rem;
    position: relative;
    margin-bottom: 2rem;
}

.sub-box-card:hover, .sub-box-body {
    transform: translateY(-10px);
    transition: .5s;
}

.sub-box-card:hover {
    box-shadow: 0px 10px 10px -5px #eee;
}

.sub-box-card:hover .click-btn {
    opacity: 1;
    animation-fill-mode: forwards;
    animation: floatbtn .5s;
    animation-duration: 0.5s;
    animation-timing-function: ease;
    animation-delay: 0s;
    animation-iteration-count: 1;
    animation-direction: normal;
    animation-fill-mode: none;
    animation-play-state: running;
    animation-name: floatbtn;
}

.click-btn {
    opacity: 0;
    position: absolute;
    bottom: 0;
    margin-left: -50%;
    width: 100%;
    height: 2rem;
    text-align: center;
    line-height: 2rem;
    color: white;
    font-size: 1rem;
    font-weight: bold;
    background-color: #00bdff;
    border-radius: 0.2rem;
    text-decoration: none;
    padding: 0;
    transition: .5s;
    cursor: pointer;
}

.sub-box-card .image {
    width: 4rem;
    height: 4rem;
    margin-bottom: 1rem;
}

.sub-box-card .title{
    font-size: 18px;
    color: white;
}
</style>

apis.json:

{
    "msg": "success",
    "code": 200,
    "data": [
        { "nmb": 1, "src": "/static/imgs/constellation.jpeg", "alt": "星座", "name": "星座", "link": "https://www.baidu.com" },
        { "nmb": 2, "src": "/static/imgs/weather.png", "alt": "天气", "name": "天气", "link": "https://www.baidu.com" },
        { "nmb": 3, "src": "/static/imgs/phone_attribution.jpeg", "alt": "星座", "name": "星座", "link": "https://www.baidu.com" },
        { "nmb": 4, "src": "/static/imgs/news.jpeg", "alt": "新闻", "name": "新闻", "link": "https://www.baidu.com" },
        { "nmb": 5, "src": "/static/imgs/video.jpeg", "alt": "热门视频榜单", "name": "热门视频榜单", "link": "https://www.baidu.com" },
        { "nmb": 6, "src": "/static/imgs/joke.jpeg", "alt": "笑话大全", "name": "笑话大全", "link": "/joke" },
        { "nmb": 7, "src": "/static/imgs/rate.jpeg", "alt": "汇率", "name": "汇率", "link": "https://www.baidu.com" },
        { "nmb": 8, "src": "/static/imgs/history.jpg", "alt": "历史上的今天", "name": "历史上的今天", "link": "https://www.baidu.com" },
        { "nmb": 9, "src": "/static/imgs/idiom.jpeg", "alt": "成语接龙", "name": "成语接龙", "link": "https://www.baidu.com" },
        { "nmb": 10, "src": "/static/imgs/drive_liscence.jpeg", "alt": "驾照题库", "name": "驾照题库", "link": "https://www.baidu.com" },
        { "nmb": 11, "src": "/static/imgs/calendar.jpeg", "alt": "万年历", "name": "万年历", "link": "https://www.baidu.com" },
        { "nmb": 12, "src": "/static/imgs/qq.jpeg", "alt": "QQ号测吉凶", "name": "QQ号测吉凶", "link": "https://www.baidu.com" },
        { "nmb": 13, "src": "/static/imgs/idiom_2.jpeg", "alt": "成语大全", "name": "成语大全", "link": "https://www.baidu.com" },
        { "nmb": 14, "src": "/static/imgs/dictionary.jpg", "alt": "新华字典", "name": "新华字典", "link": "https://www.baidu.com" },
        { "nmb": 15, "src": "/static/imgs/code.jpeg", "alt": "邮编查询", "name": "邮编查询", "link": "https://www.baidu.com" },
        { "nmb": 16, "src": "/static/imgs/zhougong.jpeg", "alt": "周公解梦", "name": "周公解梦", "link": "https://www.baidu.com" },
        { "nmb": 17, "src": "/static/imgs/ebook.jpeg", "alt": "图书电商数据", "name": "图书电商数据", "link": "https://www.baidu.com" },
        { "nmb": 18, "src": "/static/imgs/balance.jpeg", "alt": "健康指数器", "name": "健康指数器", "link": "https://www.baidu.com" },
        { "nmb": 19, "src": "/static/imgs/solar_terms.jpeg", "alt": "二十四节气", "name": "二十四节气", "link": "https://www.baidu.com" },
        { "nmb": 20, "src": "/static/imgs/flower.jpeg", "alt": "生日花语", "name": "生日花语", "link": "https://www.baidu.com" },
        { "nmb": 21, "src": "/static/imgs/id.jpg", "alt": "身份证查询", "name": "身份证查询", "link": "https://www.baidu.com" }
    ]
}

Api_1.vue

<template>
    <div class="api_interface content-box content-right">
        <el-card class="box-card">
            <div slot="header" class="clearfix">
                <span>笑话大全</span>
                <el-button type="text" @click="refresh">刷新</el-button>
            </div>
            <div class="joke">
                <el-select v-model="value" placeholder="按更新时间查询笑话" @change="selectType($event)">
                    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"></el-option>
                </el-select>
            </div>

            <!-- 按更新时间查询笑话 -->
            <div class="type-one">
                <div class="page_number">
                    <el-select v-model="page" placeholder="显示第1页">
                        <el-option v-for="i in 20" :key="i" :label="'显示第' + i + '页'" :value="'显示第' + i + '页'"></el-option>
                    </el-select>
                </div>
                <div class="pagesize">
                    <el-select v-model="pagesize" placeholder="显示1条">
                        <el-option v-for="i in 20" :key="i" :label="'显示' + i + '条'" :value="'显示' + i + '条'"></el-option>
                    </el-select>
                </div>
                <div class="timestamp"></div>
            </div>

            <!-- 最新笑话 -->
            <div class="type-two">
                <div class="page_number">
                    <el-select v-model="page" placeholder="显示第1页">
                        <el-option v-for="i in 20" :key="i" :label="'显示第' + i + '页'" :value="'显示第' + i + '页'"></el-option>
                    </el-select>
                </div>
                <div class="pagesize">
                    <el-select v-model="pagesize" placeholder="显示1条">
                        <el-option v-for="i in 20" :key="i" :label="'显示' + i + '条'" :value="'显示' + i + '条'"></el-option>
                    </el-select>
                </div>
            </div>

            <!-- 随机获取笑话 -->
            <div class="type-three"></div>

            <el-button class="query-btn" round @click="queryFn">确定查询</el-button>

            <el-card class="box-card query-result">
                <div slot="header" class="clearfix">
                    <span>结果如下</span>
                </div>
                <div class="joke-result-show"></div>
            </el-card>

        </el-card>
    </div>
</template>

<script>

export default {
    name: 'right',
    data () {
        return {
            options: [
                { value: '1', label: '按更新时间查询笑话' },
                { value: '2', label: '最新笑话' },
                { value: '3', label: '随机笑话' }
            ],
            value: '',
            page: '',
            pagesize: ''
        }
    },
    methods: {
        selectType (e) {
            let typeOne = document.getElementsByClassName('type-one')[0]
            let typeTwo = document.getElementsByClassName('type-two')[0]
            let typeThree = document.getElementsByClassName('type-three')[0]
            switch (e) {
                case '2':
                    typeOne.style.display = 'none'
                    typeThree.style.display = 'none'
                    typeTwo.style.display = 'block'
                    break
                case '3':
                    typeOne.style.display = 'none'
                    typeTwo.style.display = 'none'
                    typeThree.style.display = 'block'
                    break
                default:
                    typeTwo.style.display = 'none'
                    typeThree.style.display = 'none'
                    typeOne.style.display = 'block'
            }
        },
        refresh () {
            this.$router.go(0)
        },
        queryFn () {
            let baseUrl = '/api_1'
            this.$axios({
                methods: 'get',
                url: baseUrl
            }).then(res => {
                console.log(res.data)
            }).catch(error => {
                console.log(error)
            })
        }
    }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.content-box {
    text-align: center;
    margin-left: 4rem;
}

.type-one {
    display: block;
}

.type-two {
    display: none;
}

.type-three {
    display: none;
}

.page_number, .pagesize {
    margin-top: 1rem;
}

.query-btn {
    margin: 2rem 0;
}

</style>

Api_1.vue 里面 axios 请求 /api_1, 配置对应的 /config/index.js

'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.

const path = require('path')

module.exports = {
  dev: {

    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    proxyTable: {
      '/api_1': {
        target:'http://www.chaxun.com/index/Apis/index', // 你请求的第三方接口
        changeOrigin:true,  // 在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
        pathRewrite:{       // 路径重写,
          '^/api_1': '/api_1'       // 替换target中的请求地址,也就是说以后你在请求 target 的地址的时候直接写成 /api_1 即可。
        }
      }
    },
    ... ... // 剩下的内容我没有改动过

剩下的内容就在 TP5 里面写了,TP5 布局如下:
VUE 前端,TP5(thinkPHP5)后端,axios 请求第一个(聚合数据)接口,解决跨城问题

Apis.php 里面的内容

<?php
namespace   app\index\controller;
use think\Route;
use think\View;
use think\Db;
use think\Request;

class Apis {
    public function index() 
    {
        return '<h1>This is my first controller.</h1>';
    }

    /**
 * 发起网络请求函数
 * @param String $url 请求的URL
 * @param bool $params  请求的参数内容
 * @param int $isPost   是否POST请求
 * @return bool|string  返回内容
 */
    public function httpRequest($url, $params = false, $isPost = 0){
        $httpInfo = [];
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
        curl_setopt($ch, CURLOPT_USERAGENT,  'ozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36');    // 浏览器代理信息,我这里设置的自己的浏览器
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);    // 连接的等待时间, 3秒
        curl_setopt($ch, CURLOPT_TIMEOUT, 12);          // 函数最长的执行时间 
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 将 curl_exec() 获取的信息以字符串返回,而不是直接输出
        if ($isPost) {
            curl_setopt($ch, CURLOPT_POST, true);       // true 表示 post 请求
            curl_setopt($ch, CURLOPT_POSTFIELDS, $params);  // post 的请求数据的处理
            curl_setopt($ch, CURLOPT_URL, $url);        // 设置访问的 URL
        } else {
            if ($params) {
                curl_setopt($ch, CURLOPT_URL, $url . '?' . $params);
            } else {
                curl_setopt($ch, CURLOPT_URL, $url);
            }
        }
        $reponse = curl_exec($ch);
        if ($reponse === FALSE) {
            return false;   // echo "cURL Error: ".curl_error($ch);
        }
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $httpInfo = array_merge($httpInfo, curl_getinfo($ch));
        curl_close($ch);
        return $reponse;
    }

    const CONST_KEY = "";   // 使用的时候 self::CONST_KEY, 自己聚合里面申请的KEY填写上

    public function joke() // joke api_01 笑话大全
    {
        $url = "http://v.juhe.cn/joke/content/list.php";  // 笑话大全方式一
        /*
参数名	    类型	是否必填	说明
sort	  string	是	    类型,desc:指定时间之前发布的,asc:指定时间之后发布的	
page	   int	    否	    当前页数,默认1,最大20	
pagesize   int	    否	    每次返回条数,默认1,最大20	
time	  string	是	    时间戳(10位),如: 1635328323
        */
        // $sort = 'desc';
        // $page = 1;
        // $pagesize = 20;
        // $time = time();

        // $parameters = "sort=desc&page=1&pagesize=20&time=1635328323&key=".self::CONST_KEY;
        $params = [ // 请求参数
            'sort' => 'desc',
            'page' => 1,
            'pagesize' => 20,
            'time' => time()
        ];

        $paramsString = http_build_query($params);  // 参数数组转换成字符串
        $response = self::httpRequest($url, $paramsString."&key=".self::CONST_KEY, 0);  // 第二个参数里面添加聚合里面给的 key
        echo $response;
        $result = json_decode($response, true); // true 返回 json 而不是 objection

        if ($result) {
            // return print_r($result);
            $errorCode = $result['error_code'];
            if ($errorCode == 0) {
                $data = $result['result'];
                return "<h1>I am good man.</h1>";
                // return $jsonData;
            } else {
                return "第一种错: {$errorCode}_{$result['reason']}".PHP_EOL;
            }
        } else {
            return "第二种错: ".PHP_EOL;    // 可能网络异常等问题,无法正常获得相应内容,业务逻辑可自行修改
        }

        return '<h1>Api coming</h1>';
    }
}

在前端运行的结果如下:
VUE 前端,TP5(thinkPHP5)后端,axios 请求第一个(聚合数据)接口,解决跨城问题

至于界面,准备写中。

上一篇:fastadmin --快速入门教程 --简介 --php --mysql --thinkphp5


下一篇:thinkphp5-图片处理