TP5后端,VUE前端请求京东万象菜谱大全

写这个代码的收获:
1: http 请求 https 有一个证书验证(我这里给它关了,接口的数据就进来了)
2: 对后端的一些参数过滤(给默认值, 或者直接拒绝服务)

代码演示效果:
TP5后端,VUE前端请求京东万象菜谱大全
1: 前端VUE布局代码:

<template>
    <!--
        1: 先把单个菜品写死,以便查看渲染后的效果
        2: 再把菜单的列表渲染出来
        3: 添加 查询 【 菜谱搜索, ,  】 (【菜谱分类,直接写到vue json 里面,省得数据多)
    -->
    <div class="content headContainer">
        <el-card :span="12">

            <div class="alignR" :class="{unfold: isCollapsed}">
                <el-button type="success" round style="text-align: right;" @click="unfold">继续看该菜谱</el-button>
            </div>

            <!-- 单个菜品展示 -->
            <div v-if="singleRecipeBool">
                <div class="listEles" v-show="isCollapsed">
                    <el-card :span="4">
                        <div class="recipeContent">
                            <div class="classfiy">
                                <div class="classF">分类: {
  { singleRecipeData.classid }}</div>
                            </div>
                            <h1>{
  { singleRecipeData.name }}</h1>
                            <div class="forHowMany">
                                <div class="forH">{
  { singleRecipeData.peoplenum }}份</div>
                            </div>

                            <p class="authSays">{
  { singleRecipeData.content }}</p>

                            <div class="durationTime">
                                <img src="/static/imgs/clock.jpg" alt="" class="clock">
                                <p>煮制时间: {
  { singleRecipeData.cookingtime }}</p>
                            </div>
                            <div class="material">
                                <p>原料共: {
  { singleRecipeData.material.length }} 种</p>
                                <el-table :data="singleRecipeData.material" border stripe :header-cell-style="{fontSize: '1.35rem', color: 'black'}" align="center" class="materialOl">
                                    <el-table-column type="index" align="center" width="40"></el-table-column>
                                    <el-table-column prop="mname" label="食材" align="center" width="180"></el-table-column>
                                    <el-table-column prop="type" label="类型" align="center" width="140"></el-table-column>
                                    <el-table-column prop="amount" label="用量" align="center" ></el-table-column>
                                </el-table>
                            </div>

                            <p class="prepareTime">准备时间: {
  { singleRecipeData.preparetime }}</p>

                            <div class="process">
                                <div class="processCard">
                                    <el-card>
                                        <div slot="header" class="clearfix">
                                            <span class="processCardTitle">制作步骤({
  { singleRecipeData.process.length }})</span>
                                        </div>
                                        <div v-for="(p, index) in singleRecipeData.process" :key="index">
                                            <div class="recipe_step">
                                                <div class="recipe_step_num"><strong>步骤</strong> <em>step</em> <p>{
  { index + 1 }}</p></div>
                                                <div class="stepContent">
                                                    <p>{
  { p.pcontent }}</p>
                                                    <img :src="p.pic" :alt="p.pcontent">
                                                </div>
                                            </div>
                                        </div>
                                    </el-card>
                                </div>

                                <p class="recipeTag">
                                    <span>标签:</span>
                                    <el-tag v-for = "(t, index) in tags" class="recipeTag" :key="index">{
  { t }}</el-tag>
                                </p>
                            </div>

                        </div>
                    </el-card>
                    <!-- 返回顶部使用,target 对应上级包裹的 class -->
                    <el-backtop target=".listEles">
                        <i class="el-icon-caret-top"></i>
                        <!-- 添加 stop,防止冒泡事件 -->
                        <div class="toHide" @click.stop="hideAndShow">{
  { toHideText }}</div>
                    </el-backtop>
                </div>
            </div>

            <!-- 菜品列表 + 查询 -->
            <div class="showEle">

                <!-- 菜谱查询 -->
                <div class="queryRecipe">
                    <el-input placeholder="查找菜谱" class="queryRecipeIpt" v-model="queryRecipeText"></el-input>
                    <el-button type="success" @click="queryRecipe">查找</el-button>
                </div>

                <!-- 菜谱分类 -->
                <div class="effectCategory">
                    <div class="recipeList">
                        <el-select v-for="(e, index) in effectArr" :key="index" v-model="e.name" :placeholder="e.name" @change="selectEffect(e.classid)" class="recipeSelect">
                            <el-option v-for="(item, index) in e.list" :key="index" :label="item.name" :value="item.name"></el-option>
                        </el-select>
                    </div>
                </div>

                <!-- 菜品列表 -->
                <el-card :span="6">
                    <div class="smallList">
                        <div v-for="(d, index) in data" :key="index" class="samllItem" @click="showRecipe(index)">
                            <img :src="d.process[0].pic" alt="">
                            <p>{
  { d.name }}</p>
                        </div>
                    </div>

                    <div class="pagination">
                        <el-pagination :current-page.sync="currentPage" :page-size="pageSize" :total="totalPage" @size-change="handleSizeChange" @current-change="handleCurrentChange" layout="total, prev, pager, next"></el-pagination>
                    </div>
                </el-card>
            </div>

        </el-card>

    </div>
</template>

<script>

export default {
     
    name: 'idioms',
    mounted: function () {
     
        this.getClass()
        this.getData()
    },
    data () {
     
        return {
     
            apiUrl: '/api_9', // API 默认首页接口
            data: [], // 列表数据
            toHideText: '收起', // 收起文字
            isCollapsed: true, // 是否收起
            singleRecipeData: '', // 单个菜品
            singleRecipeBool: false,
            tags: [], // 处理后的tags
            queryRecipeText: '', // 查询菜谱的内容
            effectArr: [], // 功效分类
            effectArrCopy: [], // 功效分类复制一份
            effectChoose: '', // 用户选择的功效
            currentPage: 1, // 当前页码
            pageSize: 0, // 一页多少条数据【默认是10】
            totalPage: 0, // 总页数
            currentType: 'd', // 当前菜谱查看模式【 d: 默认, a: 查询, c: 分类 】
            isSearch: true, // 是否搜索查询,用于搜索页和分类查询页,是否从第一页看起
            startNmb: 0, // 第几条数据开始
            queryType: 'd', // 搜索类型,默认d
            queryClass: 0 // 当前查找类型
        }
    },
    methods: {
     
        getClass: function () {
      // 获取分类
            this.$axios.get('/static/json/recipeClass.json')
            .then(res => {
     
                if (res.status === 200) {
     
                    let result = res.data.result
                    this.effectArr = result.result
                    for (let i = 0; i < this.effectArr.length; i++) {
     
                        this.effectArrCopy[i] = this.effectArr[i].name
                    }
                }
            }).catch(err => {
     
                console.log(err)
            })
        },
        getData: function (urlType, startNmb, recipeName, classId) {
      // 获取数据 [分类, 起始值 ]
            if (urlType === undefined || startNmb === undefined) {
     
                urlType = this.currentType
                startNmb = 0
            }

            this.$axios({
     
                url: this.apiUrl,
                params: {
     
                    urlType: urlType,
                    startNmb: startNmb,
                    recipeName: recipeName,
                    classId: classId
                },
                methods: 'get'
            }).then(res => {
     
                if (res.data.code === '10000') {
     
                    let data = res.data.result.result
                    this.totalPage = data.total
                    this.pageSize = data.num
                    this.data = data.list
                } else {
     
                    console.log('something err' + res)
                }
            }).catch(err => {
     
                console.log(err)
            })
        },
        hideAndShow: function () {
      // 收起
            this.isCollapsed = false
        },
        unfold: function () {
      // 展开
            this.isCollapsed = true
        },
        showRecipe: function (index) {
      // 展开单个菜谱,并把该菜品的 TAGS 处理一下
            this.singleRecipeData = this.data[index]
            let tags = this.singleRecipeData.tag
            this.tags = tags.split(',')
            this.singleRecipeBool = true
            this.isCollapsed = true
        },
        queryRecipe: function () {
      // 查找
            // 搜索接口 https://way.jd.com/jisuapi/search?keyword=白菜&num=10&start=0&appkey=您申请的APPKEY
            if (!this.isSearch) {
      // 判断有没有换另外一种搜索方式
                this.startNmb = 0
                this.isSearch = true
            }
            this.queryType = 's'
            let searchType = this.queryType
            if (this.queryRecipeText.trim() === '') {
     
                return alert('请输入文字')
            }
            this.getData(searchType, this.startNmb, this.queryRecipeText.trim())
        },
        selectEffect: function (classId) {
      // 选择菜谱功能 【 分类id 】
            // 分类接口 https://way.jd.com/jisuapi/byclass?classid=2&start=0&num=10&appkey=您申请的APPKEY
            if (this.isSearch) {
      // 判断有没有换另外一种搜索方式
                this.isSearch = false
                this.startNmb = 0
            }
            this.queryType = 'c'
            let searchType = this.queryType
            this.queryClass = classId
            this.getData(searchType, this.startNmb, null, classId)
        },
        handleSizeChange (val) {
      // 一页多少条数据变化
            console.log(`${
       val} items per page`)
        },
        handleCurrentChange (val) {
      // 当前页码变化函数
            let startNmb = val * 10
            if (this.isSearch) {
      // 搜索模式就传递词,否则传递分类ID
                this.getData(this.queryType, startNmb, this.queryRecipeText.trim(), 0)
            } else {
     
                this.getData(this.queryType, startNmb, null, this.queryClass)
            }
        }
    }
}
</script>

<style scoped>
.listEles {
     
    height: 100vh;
    overflow-x: hidden;
}
.content {
     
    margin-left: 9%;
}
.showEle {
     
    text-align: center;
}
.recipeContent {
     
    text-align: center;
}
.recipeContent .classfiy {
     
    width: 8rem;
    height: 8rem;
    overflow: hidden;
    margin: 0 auto;
    margin-top: -4rem;
}
.recipeContent .classfiy .classF {
     
    width: 8rem;
    height: 8rem;
    border-top-left-radius: 4rem;
    border-top-right-radius: 4rem;
    background-color: #ffe851;
    line-height: 3.5rem;
    margin-top: 5rem;
    font-weight: bolder;
}
.recipeContent h1 {
     
    min-width: 10rem;
    max-width: 20rem;
    background-color: #ffe851;
    border-radius: 50rem;
    margin: 0 auto;
    padding: 0.5rem 0;
    position: relative;
    color: red;
}
.recipeContent .forHowMany {
     
    height: 5rem;
    overflow: hidden;
}
.recipeContent .forH {
     
    width: 8rem;
    height: 8rem;
    border-bottom-left-radius: 4rem;
    border-bottom-right-radius: 4rem;
    background-color: #ffe851;
    margin: -5rem auto 0 auto;
    line-height: 12rem;
    font-weight: bolder;
}
.recipeContent .authSays, .durationTime {
     
    text-align: left;
    text-indent: 2rem;
}
.recipeContent .authSays {
     
    display: block;
    width: 50rem;
    margin: 0 auto;
}
.recipeContent .durationTime {
     
    display: flex;
    justify-content: center;
    margin: 1rem 0;
}
.recipeContent .durationTime img {
     
    width: 2rem;
}
.recipeContent .durationTime p {
     
    margin-top: 0.7rem;
    font-weight: bolder;
    color: coral;
}
.recipeContent .authSays {
     
    font-size: 1.5rem;
}
.recipeContent .material .materialOl {
     
    margin: 0 auto;
    width: 40%;
}
.recipeContent .prepareTime {
     
    margin: 1rem 0;
}
.recipeContent .processCard {
     
    text-align: left;
    width: 50rem;
    margin: 0 auto;
}
.recipeContent .processCard .recipe_step {
     
    display: flex;
    justify-content: lfet;
}
.recipeContent .processCard .recipe_step .recipe_step_num {
     
    height: 6rem;
    width: 5rem;
    background: #ffe851;
    border-radius: 1.5rem;
    border-bottom-right-radius: 2px;
}
.recipeContent .processCard .recipe_step .recipe_step_num strong {
     
    font-size: 1.4rem;
    text-align: right;
    color: #000;
    font-weight: bolder;
    line-height: 1.1rem;
    margin-top: 1rem;
    display: block;
    padding-right: 1rem;
}
.recipeContent .processCard .recipe_step .recipe_step_num em {
     
    font-size: 1rem;
    text-align: right;
    color: #000;
    font-weight: bolder;
    line-height: 1.5rem;
    display: block;
    padding-right: 1.3rem;
}
.recipeContent .processCard .recipe_step .recipe_step_num p {
     
    font-size: 2.7rem;
    text-align: right;
    color: #000;
    font-weight: bolder;
    line-height: 2rem;
    display: block;
    padding-right: 1.5rem;
}
.recipeContent .processCard .recipe_step .stepContent {
     
    margin-left: 3rem;
}
.recipeContent .processCard .recipe_step .stepContent p{
     
    font-weight: bolder;
}
.recipeContent .processCard .recipe_step .stepContent img{
     
    margin: 0.5rem 0 2rem 0;
}
.recipeContent .processCard .processCardTitle {
     
    font-weight: bolder;
    font-size: 2.3rem;
}
.recipeContent .recipeTag {
     
    margin-top: 1rem;
    text-align: right;
    font-weight: bolder;
}
/* 小图片 + 标题 列表*/
.smallList {
     
    display: flex;
    justify-content: left;
    flex-wrap: wrap;
}
.smallList .samllItem {
     
    width: 18rem;
    height: 18rem;
    margin-bottom: 2rem;
    cursor: pointer;
}
.smallList .samllItem img{
     
    width: 16rem;
    height: 16rem;
}
.smallList .samllItem p{
     
    font-weight: bolder;
    font-size: 1.2rem;
}
/* 返回顶部 */
.toHide {
     
    width: 3rem;
    height: 3rem;
    position: absolute;
    top: 3rem;
}
/* 展开按钮 */
.unfold {
     
    display: none;
}
.alignR {
     
    text-align: right;
}
/* 菜谱查询 */
.queryRecipe {
     
    text-align: left;
    margin: 2rem 0 0 2rem;
}
.queryRecipe .queryRecipeIpt {
     
    width: 8rem;
}
.effectCategory {
     
    margin: 1rem 0;
}
.recipeList {
     
    margin: 1rem 0 0 2rem;
    display: flex;
    flex-wrap: wrap;
    justify-items: left;
}
.recipeList .recipeSelect {
     
    width: 8rem;
    margin:1rem 1rem 0 0;
}
/* 菜谱 tag */
.recipeTag {
     
    margin-right: 1rem;
}
</style>

2: 前端路由代理配置代码

'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/joke', // 你请求的第三方接口
        changeOrigin:true,  // 在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
        pathRewrite:{
          // 路径重写,
          '^/api_1': '/api_1'       // 替换target中的请求地址,也就是说以后你在请求 target 的地址的时候直接写成 /api_1 即可。
        }
      },
      '/api_2': {
   
        target: 'http://www.chaxun.com/constellation',
        changeOrigin: true,
        pathRewrite: {
   
          '^/api_2': '/api_2'
        }
      },
      '/api_3': {
   
        target: 'http://www.chaxun.com/weather',
        changeOrigin: true,
        pathRewrite: {
   
          '^/api_3': '/api_3'
        }
      },
      '/api_4': {
   
        target: 'http://www.chaxun.com/news',
        changeOrigin: true,
        pathRewrite: {
   
          '^/api_4': '/api_4'
        }
      },
      '/api_5': {
   
        target: 'http://www.chaxun.com/videos',
        changeOrigin: true,
        pathRewrite: {
   
          '^/api_5': '/api_5'
        }
      },
      '/api_6': {
   
        target: 'http://www.chaxun.com/driverlicense',
        changeOrigin: true,
        pathRewrite: {
   
          '^/api_6': '/api_6'
        }
      },
      '/api_7': {
   
        target: 'http://www.chaxun.com/today_in_history',
        changeOrigin: true,
        pathRewrite: {
   
          '^/api_7': '/api_7'
        }
      },
      '/api_8': {
   
        target: 'http://www.chaxun.com/idioms',
        changeOrigin: true,
        pathRewrite: {
   
          '^/api_8': '/api_8'
        }
      },  
      '/api_9': {
   
          target: 'http://www.chaxun.com/recipe',
          changeOrigin: true,
          pathRewrite: {
   
            '^/api_9': '/api_9'
          }
      }
    },

    // Various Dev Server settings
    host: '0.0.0.0', // can be overwritten by process.env.HOST
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: false,
    errorOverlay: true,
    notifyOnErrors: true,
    poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-

    // Use Eslint Loader?
    // If true, your code will be linted during bundling and
    // linting errors and warnings will be shown in the console.
    useEslint: true,
    // If true, eslint errors and warnings will also be shown in the error overlay
    // in the browser.
    showEslintErrorsInOverlay: false,

    /**
     * Source Maps
     */

    // https://webpack.js.org/configuration/devtool/#development
    devtool: 'cheap-module-eval-source-map',

    // If you have problems debugging vue-files in devtools,
    // set this to false - it *may* help
    // https://vue-loader.vuejs.org/en/options.html#cachebusting
    cacheBusting: true,

    cssSourceMap: true
  },

  build: {
   
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',

    /**
     * Source Maps
     */

    productionSourceMap: true,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',

    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],

    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }
}

3: 前端菜谱分类 json

{
   "code":"10000","charge":false,"msg":"查询成功","result":{
   "status":0,"msg":"ok","result":[{
   "classid":1,"name":"功效","parentid":0,"list":[{
   "classid":2,"name":"减肥","parentid":1},{
   "classid":3,"name":"瘦身","parentid":1},{
   "classid":4,"name":"消脂","parentid":1},{
   "classid":5,"name":"丰胸","parentid":1},{
   "classid":6,"name":"美容","parentid":1},{
   "classid":7,"name":"养颜","parentid":1},{
   "classid":8,"name":"美白","parentid":1},{
   "classid":9,"name":"防晒","parentid":1},{
   "classid":10,"name":"排毒","parentid":1},{
   "classid":11,"name":"祛痘","parentid":1},{
   "classid":12,"name":"祛斑","parentid":1},{
   "classid":13,"name":"保湿","parentid":1},{
   "classid":14,"name":"补水","parentid":1},{
   "classid":15,"name":"通乳","parentid":1},{
   "classid":16,"name":"催乳","parentid":1},{
   "classid":17,"name":"回奶","parentid":1},{
   "classid":18,"name":"下奶","parentid":1},{
   "classid":19,"name":"调经","parentid":1},{
   "classid":20,"name":"安胎","parentid":1},{
   "classid":21,"name":"抗衰老","parentid":1},{
   "classid":22,"name":"抗氧化","parentid":1},{
   "classid":23,"name":"延缓衰老","parentid":1},{
   "classid":24,"name":"补钙","parentid":1},{
   "classid":25,"name":"补铁","parentid":1},{
   "classid":26,"name":"补锌","parentid":1},{
   "classid":27,"name":"补碘","parentid":1},{
   "classid":28,"name":"补硒","parentid":1},{
   "classid":29,"name":"补虚","parentid":1},{
   "classid":30,"name":"降血脂","parentid":1},{
   "classid":31,"name":"降血糖","parentid":1},{
   "classid":32,"name":"降血压","parentid":1},{
   "classid":33,"name":"降低胆固醇","parentid":1},{
   "classid":34,"name":"解酒","parentid":1},{
   "classid":35,"name":"提神","parentid":1},{
   "classid":36,"name":"增高","parentid":1},{
   "classid":37,"name":"解暑","parentid":1},{
   "classid":38,"name":"清热解暑","parentid":1},{
   "classid":39,"name":"清热解毒","parentid":1},{
   "classid":40,"name":"去火","parentid":1},{
   "classid":41,"name":"清火","parentid":1},{
   "classid":42,"name":"下火","parentid":1},{
   "classid":43,"name":"清热下火","parentid":1},{
   "classid":44,"name":"生津止渴","parentid":1},{
   "classid":45,"name":"止泻","parentid":1},{
   "classid":46,"name":"增肥","parentid":1},{
   "classid":47,"name":"抗过敏","parentid":1},{
   "classid":48,"name":"补气","parentid":1
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值