iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 14
0
自我挑戰組

網頁前端框架 Vue 3 從頭開始(重新挑戰)系列 第 14

vue3 Composition API 學習手冊-14 透過axios載入外部json

  • 分享至 

  • xImage
  •  

在前面“多層次動態選單”的文章中,我們把選單資料放在Javascript中進行描述,可以發現整支Javascript中邏輯運算的部分極少,大多都是描述頁面資料的部分,也提到在未來我們應該可以將這部分的資料獨立拉出來至一個檔案,甚至在前、後端分離的網頁中,頁面資料大多由後端API提供,如此一來我們就不得不了解一下Axios的部分了!

關於Vue與後端API擷取資料的部分,比較熱門的做法其實有兩個:

  1. vue-resource
  2. axios

大家看今天的標題應該也知道,我們應該不會去介紹vue-resource,原因是因為他在Vue 2.0之後就已經不再維護,連官方都推薦使用axios,所以這篇文章我們就先用axios來示範如何取得外部的json檔,其實意思也類似打api只是這個api現在是個固定的json檔罷了。

本次我們準備的檔案有兩個,一個是HTML並且把Javascript撰寫在HTML頁面中,另外就是外部的json檔,需要注意json檔跟Javascript中的物件還是有一些差異,因為json檔不管是key或value都需要用雙引號包覆起來,我們製作的Sample json檔的內容如下:

{
    "title": "網站框架整理",
    "frameworks": [
        {
            "type": "frontend",
            "content":[ 
                {
                    "name": "Vue",
                    "version": "2.x"
                },
                {
                    "name": "React",
                    "version": "16.x"
                },
                {
                    "name": "React",
                    "version": "9.x"
                }                
            ]
        },
        {
            "type": "backend",
            "content":[
                {
                    "name": "Laravel",
                    "version": "7.x"
                },
                {
                    "name": "CakePHP",
                    "version": "4.x"
                },
                {
                    "name": "Django",
                    "version": "3.x"
                }
            ]
        }
    ]
}

接下來我們就要透過網頁將其讀入,並且列示於畫面上:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
    <style>
        .noteText {
            font-size: 12px;
        }
    </style>
</head>

<body>
    <div id="app">
        <ul>
            <li v-for="item in state.frameworks">
                {{ item.type }}
                <ul>
                    <li v-for="itemDetail in item.content">
                        {{ itemDetail.name }} ( {{ itemDetail.version }} )
                    </li>
                </ul>
            </li>
        </ul>
    </div>
</body>

</html>
<script>
const { reactive, onBeforeMount } = Vue;
const app = {
    setup(){
        const state = reactive({
            frameworks: null,
        })
        onBeforeMount(() => {
            axios.get("frameworks.json").then(function (response) {
                state.frameworks = response.data.frameworks;
            }).catch(function (response) {
                console.log(response);
            })
        })
        return { state };
    }
}
const myVue = Vue.createApp(app).mount("#app");
</script>

可以看到上面程式HTML的部分我們加入了兩行的Plugin,因為axios並不是vue或HTML內建的功能,所以必須要透過外掛載入(也就是第HTML第8行)。

在Javascript 第8~12行則是axios的語法,我們希望在vue onBeforeMount的階段去執行載入json的動作,這也是前一篇文章介紹過的一個生命週期,可以看到頁面上的效果如下:

範例檔

如此一來我們就成功地把資料與頁面分離,未來這個部分也會成為前後端分離開發方式的基石,有了上面範例的成功,我們想到之前的多層式選單案例,當時就覺得頁面中的Javascript中有太多的json資料,我們也試著把三層式選單的案例改寫,將資料獨立出來看看寫法上有沒有什麼不同!

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://unpkg.com/vue@next"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
    <style>
        .noteText {
            font-size: 12px;
        }
    </style>
</head>

<body>
    <div id="app">
        <h3>Please make your decision:</h3>
        <p>
            Gender:
            <select v-model="state.genderIdx">
                <option v-for="(item, index) in state.clothes" :value="index">
                    {{item.gender}}
                </option>
            </select>
        </p>
        <p>
            Type:
            <select v-model="state.partIdx">
                <option v-for="(item, index) in pickTypes" :value="index">
                    {{item.part}}
                </option>
            </select>
        </p>
        <p>
            Product:
            <select v-model="state.itemIdx">
                <option v-for="(item, index) in pickContents" :value="index">
                    {{item.product}}
                </option>
            </select>
        </p>
    </div>
</body>

</html>
<script>
    const { reactive, onBeforeMount, computed } = Vue;
const app = {
    setup(){
        const state = reactive({
            genderIdx: 0, // 記錄第一層選單的被選取項目
            partIdx: 0, // 記錄第二層選單的被選取項目
            itemIdx: 0, // 記錄第三層選單的被選取項目
            clothes: null,
        })
        onBeforeMount(() => {
            axios.get("clothes.json").then(function (response) {
                state.clothes = response.data.clothes;
            }).catch(function (response) {
                console.log(response);
            })
        })
        const pickTypes = computed(() => {
            return (state.clothes === null ? "" : state.clothes[state.genderIdx].types);
        })
        const pickContents = computed(() => {
            return (state.clothes === null ? "" : state.clothes[state.genderIdx].types[state.partIdx].contents);
        })
        return { state, pickTypes, pickContents };
    }
}
const myVue = Vue.createApp(app).mount("#app");
</script>
{
    "clothes":[
    {
        "gender": "男",
        "types": [
            {
                "part": "上衣類",
                "contents": [
                    { "product": "短袖/背心" },
                    { "product": "長袖" },
                    { "product": "立領/高領" },
                    { "product": "針織衫" },
                    { "product": "休閒襯衫" },
                    { "product": "商務襯衫" },
                    { "product": "法蘭絨系列" },
                    { "product": "厚棉系列" }
                ]
            },
            {
                "part": "外套類",
                "contents": [
                    { "product": "休閒外套" },
                    { "product": "Fleece系列" },
                    { "product": "極輕羽絨" },
                    { "product": "極暖羽絨" }
                ]
            },
            {
                "part": "下身類",
                "contents": [
                    { "product": "短/七分褲" },
                    { "product": "九分/束口褲" },
                    { "product": "休閒長褲" },
                    { "product": "牛仔褲" },
                    { "product": "保暖褲" }
                ]
            },
            {
                "part": "家居服",
                "contents": [
                    { "product": "家居套裝" },
                    { "product": "家居褲" },
                    { "product": "家居毯" }
                ]
            }
        ]
    },
    {
        "gender": "女",
        "types": [
            {
                "part": "上衣類",
                "contents": [
                    { "product": "印花短T" },
                    { "product": "印花長T" },
                    { "product": "短袖/背心" },
                    { "product": "七分/長袖" },
                    { "product": "長版上衣" },
                    { "product": "針織衫" },
                    { "product": "polo衫" },
                    { "product": "Pima棉" }
                ]
            },
            {
                "part": "外套類",
                "contents": [
                    { "product": "休閒外套" },
                    { "product": "Fleece系列" },
                    { "product": "極輕羽絨" },
                    { "product": "極暖羽絨" }
                ]
            },
            {
                "part": "下身類",
                "contents": [
                    { "product": "休閒短褲" },
                    { "product": "七/九分褲" },
                    { "product": "牛仔系列" },
                    { "product": "寬褲系列" },
                    { "product": "休閒長褲" },
                    { "product": "裙子" },
                    { "product": "連身/吊帶褲" },
                    { "product": "緊身褲" },
                    { "product": "裙子" }
                ]
            },
            {
                "part": "洋裝",
                "contents": [
                    { "product": "洋裝" },
                    { "product": "家居褲" },
                    { "product": "吊帶裙" }
                ]
            }
        ]
    }
]
}

結果可以參考範例檔,如此一來我們就能將資料和頁面分離,也慢慢接近了現在最流行的網頁前、後端分離的開發方式。


上一篇
vue3 Composition API 學習手冊-13 生命週期
下一篇
vue3 Composition API 學習手冊-15 安裝Chrome擴充功能
系列文
網頁前端框架 Vue 3 從頭開始(重新挑戰)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言