[Day 29] 实作-axios 串接api

先看一下有哪些api

下面列出这次用到的openapi,

可以看到他有一个共通的domain https://cloud.culture.tw/frontsite

然後後面分成 trans 跟 opendata,後续又根据功能不同拆成多个类别

节庆相关
https://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindFestivalTypeJ

主题推荐
https://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindIssueTypeJ

艺文活动-所有类别
https://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindTypeJ&category=all

音乐表演资讯
https://cloud.culture.tw/frontsite/trans/SearchShowAction.do?method=doFindTypeJ&category=1

查询单一活动详细资料
https://cloud.culture.tw/frontsite/opendata/activityOpenDataJsonAction.do?method=doFindActivityById&id=5a64e3d8c6355e2a94b8a1cf

经纬度查询附近未过期活动
https://cloud.culture.tw/frontsite/opendata/activityOpenDataJsonAction.do?method=doFindActivitiesNearBy&lat=25.051345&lon=121.549569&range=2

查询单一类别未过期活动资料
https://cloud.culture.tw/frontsite/opendata/activityOpenDataJsonAction.do?method=doFindActivitiesByCategory&category=1

开始串接!

首先在src下建立一个 api资料夹,建立 api.js 档。

import axios from 'axios';

// 建立一个axios实例
const publicService = axios.create({
  baseURL: 'https://cloud.culture.tw/frontsite', // url = base url + request url
});

时间有限所以先做节庆活动跟主题推荐这2只api,

会更新主题推荐主页、节庆活动主页、节庆活动详细页面 3个页面!


// 节庆活动 api
// eslint-disable-next-line import/prefer-default-export
export const getFestival = data => publicService.get('/trans/SearchShowAction.do?method=doFindFestivalTypeJ', data);

// 主题推荐 api
export const getTopic = data => publicService.get('/trans/SearchShowAction.do?method=doFindIssueTypeJ', data);

更新主题推荐的api

这页比较简单一点,在TopicPage里,我把资料逐笔塞进Topic 子组件,没有做其他操作

所以只要修改TopicPage的资料来源,Topic子组件就会自动吃到新的资料

<script>
import Topic from './Topic';
import { getTopic } from '../api/api'; // 从api.js import 主题推荐的api方法

export default {
  name: 'TopicPage',
  components: { Topic },
  data() {
    return {
      title: '',  // 原本这边都是写死的假资料,直接改成空值即可
      note: '',
      issue: [],
    };
  },
  methods: {
    getTopicData() { // 写一个接资料的方法
      getTopic()     // 呼叫api方法
        .then((res) => {
          this.title = res.data.title;   // 把api回传的值存到data的参数里
          this.note = res.data.note;
          this.issue = res.data.issue;
        })
        .catch((err) => {
          // eslint-disable-next-line no-console
          console.log(err);
        });
    },
  },
  created() {
    this.getTopicData();  // 生命周期函数,在页面初始化时要执行资料
  },
};
</script>

看看成果

成功! 如果有看过 Day21 的应该会发现Title跟下面的活动内容都更新了!

而且後续api资料更新,这页的资料也会自动刷新~

https://ithelp.ithome.com.tw/upload/images/20211013/20140745yGEjMB3rpR.png


更新节庆专区的api

这页跟主题推荐差不多,都是回圈渲染组件,所以就不赘述啦

<script>
import Festival from './Festival';
import { getFestival } from '../api/api';

export default {
  name: 'FestivalPage',
  components: { Festival },
  data: () => ({
    date: null,
    form: {
      keyword: null,
      start: null,
      end: null,
      location: [],
    },
    locations: ['台北市', '基隆市', '新北市', '宜兰县', '桃园市', '新竹市', '新竹县', '苗栗县', '台中市', '彰化县', '南投县', '云林县', '嘉义县', '嘉义市', '台南市', '高雄市', '屏东县', '澎湖县', '花莲县', '台东县', '金门县', '连江县'],
    festivalList: [],
  }),
  methods: {
    getFestivalData() {
      getFestival()
        .then((res) => {
          this.festivalList = res.data;
        })
        .catch((err) => {
          // eslint-disable-next-line no-console
          console.log(err);
        });
    },
  },
  created() {
    this.getFestivalData();
  },
};
</script>

看看成果

https://ithelp.ithome.com.tw/upload/images/20211013/20140745igJ1Kd2vsE.png


更新节庆专区详细页面

这页就略为复杂了,他一样是要用节庆专区的api,

但是拿到的是全部资料,还需要再从中筛选出页面对应的那笔

跟上面2个一样,把假资料改为空值,在create()的地方引入api方法

有更改的地方我会用注解标注

<script> 
import { getFestival } from '../api/api';  //引入api方法

export default {
  name: 'FestivalDetailPage',
  data: () => ({
    actId: 0,
    actData: {},
    festivalList: [],  // 把原本的假资料改为空值
  }),
  methods: {
	//获取全部资料
    getAllData() { 
      getFestival()
        .then((res) => {
          this.festivalList = res.data; //先把全部资料存入data()
          this.getActData();           // 挑出这页要用的那笔资料
        })
        .catch((err) => {
          // eslint-disable-next-line no-console
          console.log(err);
        });
    },
    getActData() {
      const actId = this.$route.query.actId;
      let selectedAct;
      this.festivalList.forEach((obj) => {
        if (obj.actId === parseInt(actId, 10)) {
          selectedAct = obj;
        }
      });
      this.actData = selectedAct;
    },
    getImageUrl(imageUrl) {
      return `https://cloud.culture.tw/${imageUrl}`;
    },
    getDateFormat(datetime) {
      const newDate = new Date(Date.parse(datetime));
      return `${newDate.getFullYear()}/${newDate.getMonth() + 1}/${newDate.getDate()}`;
    },
    getGrade() {
      const { grade1, grade2, grade3, grade4, grade5, grade6 } = this.actData;
      const gradeList = [grade1, grade2, grade3, grade4, grade5, grade6];
      let gradeResult = '';
      gradeList.forEach((grade) => {
        if (grade) {
          gradeResult += (`${grade} `);
        }
      });
      return gradeResult;
    },
  },
  created() {
    this.getAllData(); //在页面初始化时戳api拿资料
  },
};
</script>

更改完後,页面可以正常显示了,但是好像有点小问题

节庆专区刷新时会跳error

错误讯息如下,可以看到本来应该带imageUrl的地方,它却拿到undefined,所以报错

https://ithelp.ithome.com.tw/upload/images/20211013/20140745bz8EgPKU6S.png

虽然图片显示正常,但是有error我们还是要处理一下!

这个问题是因为我原本的资料是放在data()里,

然後template里用 getImageUrl() 去把图片栏位换成正确的网址,转换後才会渲染页面

原本的写法

<v-img :src='getImageUrl(actData.imageUrl)' />
getImageUrl(imageUrl) {
    return `https://cloud.culture.tw/${imageUrl}`;
},

那现在变成页面初始化时,因为data的值我们改成空值了,getImageUrl时会拿不到资料 报错,

然後才执行create() 里的方法,去把api捞到的资料存到data里

用文字讲比较难理解,直接上图!

原本的写法在左边,因为直接拿data的资料所以会正常显示不报错

改拿api资料後,他会先拿一次资料,执行完create()後又拿一次,所以页面会正常显示但是第一次失败後会报错误讯息

https://ithelp.ithome.com.tw/upload/images/20211013/20140745PdYnZ9SLwR.png

修改程序码

既然第二次拿的到资料,就代表第一次的拿资料是不必要的

只要保留让api捞取後可以把资料存进data,再让他渲染这段即可

https://ithelp.ithome.com.tw/upload/images/20211013/20140745nqF3CSaH5D.png

<!-- 改成直接拿data里的资料 -->
<v-img :src='actData.imageUrl'/> 
// 移除getImageUrl(),直接在取得单笔资料时,更改image格式

getActData() {
      const actId = this.$route.query.actId;
      let selectedAct;
      this.festivalList.forEach((obj) => {
        if (obj.actId === parseInt(actId, 10)) {
          selectedAct = obj;
        }
      });
      this.actData = selectedAct;
      this.actData.imageUrl = `https://cloud.culture.tw/${this.actData.imageUrl}`;
    },

好惹~ api的部分就先讲到这边啦

後续其实还有挺多东西要做的,不过时间有限真的是讲不完

29天了,明天来讲一下目前的成果总结

快完赛啦 oh ya


<<:  [D29] 检测框的精准度

>>:  完赛

(急)毕业问卷填写

https://docs.google.com/forms/d/1YL9riLzCASVo7hkaO...

轻松跨越Windows地雷而不会被炸得粉身碎骨

曾经被系统的地雷,炸得支离破碎 很多好用的应用程序都对Windows不太友善,今天就让你轻松跨越这些...

k8s开的kubectl logs路径修改

【YC的迷路青春】 如果不要用预设的路径,例如专案是用tomcat起的,我们不想看tomcat的lo...

[Day09] swift & kotlin 入门篇!(7) 方法, 类别, 介面

方法 程序设计里面 方法太重要了 当然~也有人习惯叫他函数 每个方法我们可以看做一个命令 这其中有...

[Day 27] 使用GCP部署机器学习API

使用GCP部署机器学习API 此范例使用鸢尾花朵资料集进行 XGBoost 分类器模型训练。将模型储...