iT邦幫忙

2024 iThome 鐵人賽

DAY 30
0
JavaScript

歡迎參加我的原生JS畢業典禮系列 第 30

【Day29】.NET Core MVC & Vue—讓Axios幫我拿資料

  • 分享至 

  • xImage
  •  

參賽進入最尾聲了,剩下最後一個實戰任務!將會用我之前透過.net MVC開發的訂房網站為基礎進行;今天來完成房間資訊頁,並比較看看和原先jQuery差別在哪!

這系列兩大重點:

  1. 實際操作本機資料庫
  2. 當Vue.js加入.NET Core MVC專案後,是如何改善透過jQuery處理前端畫面的程式碼

Axios

昨天我們透過Vue處理網站前端的靜態資料,進入房間資訊頁發現介面上有許多區塊需要動態渲染:
https://ithelp.ithome.com.tw/upload/images/20241014/20169356WrUMswqhJ9.png

  • 左側圖片輪播器:要對應該房型提供幾張圖片動態生成
  • 右側客房提供服務:要對應該房型提供哪些類型的服務動態生成

因此,想藉由.NET Core進行SSR之前先讓Vue處理好這兩區畫面就能透過Axios來實現!
◎小提示:Axios是以Promise為基礎(promise-based)的HTTP請求工具,提供Get和Post方法

引入CDN

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

▲我嘗試透過npm下載,但一直無法順利引用node_modules之下的套件

  • Get請求用法:
const url= './RoomService?No=' + '@ViewData["No"]';
   axios.get(url)
        .then((res) => {
            console.log(res.data)
        })

我們透過單一url夾帶參數的方式呼叫api,並取得res.data,也可以一次請求多個url:

const url1 = './RoomService?No=' + '@ViewData["No"]';
const url2 = './RoomInfo?No=' + '@ViewData["No"]';
const request1 = axios.get(url1);
const request2 = axios.get(url2);

    axios.all([request1, request2])
        .then(axios.spread((response1, response2) => {
            // 在這裡處理 response1 和 response2
          ...
        }))
        .catch((error) => {
            // 處理錯誤
        });         
  • 加入Vue完整寫法:
  import { ref, createApp } from '../../vue/dist/vue.esm-browser.prod.js';
  const url1 = './RoomService?No=' + '@ViewData["No"]';
  const url2 = './RoomInfo?No=' + '@ViewData["No"]';
  createApp({
      setup() {
          const nowImg = ref(1);
          const roomItem = ref();
          const roomInfo = ref();
          const roomImg = ref([]);
          const request1 = axios.get(url1);
          const request2 = axios.get(url2);
              axios.all([request1, request2])
                  .then(axios.spread((response1, response2) => {
                      // 在這裡處理 response1 和 response2
                      roomItem.value = response1.data;
                      roomInfo.value = response2.data;
                      let array = response2.data[0].bS01_07.split(",");
                  for (var y = 0; y < array.length; y++) {
                          roomImg.value.push({
                              id:y+1,
                          src: array[y]
                          });
                      };
                  }))
                  .catch((error) => {
                      // 處理錯誤
                  });
          return { roomItem, roomInfo, roomImg, nowImg };
      },
  }).mount("#roomDetail");

後端Controller處理資料

  • 進入房間資訊頁:從首頁傳遞房間編號進去,讓Vue可以拿著No取得詳細資料
 //進入房間資訊頁
 public IActionResult RoomDetail(int No) {
     ViewData["No"] = No;
     return View();
 }
  • Axios請求RoomInfo:透過get發送請求1領取該房相關資料,BS01_07-BS01_09為房間照片,將三個欄位合併一起回傳
 //取得房間相關資料
 public IEnumerable RoomInfo(int No)
 {
     var result = from room in ud_RoomContext.ut_BS001
                         where room.BS01_02.Equals(No)
                         select new ut_BS001
                         {
                             BS01_01 = room.BS01_01,
                             BS01_02 = room.BS01_02,
                             BS01_03 = room.BS01_03,
                             BS01_04 = room.BS01_04,
                             BS01_05 = room.BS01_05,
                             BS01_07 = room.BS01_07 == null ? "roomsetting.png" :
                             room.BS01_07 + (room.BS01_08 != null ? "," + room.BS01_08 + (room.BS01_09 != null ? "," + room.BS01_09 : "") : "")
                         };
     return result;
 }
  • Axios請求RoomService:透過get發送請求2領取該房提供的相關服務設施,服務設施記錄在BS01_06欄位,進入ut_BS001_A表比對之後回傳相符的資料
 //取得房間相關設施
 public IEnumerable RoomService(int No) {
     var result = from room in ud_RoomContext.ut_BS001_A
                  let trimmedValue = (room.BS01A_01).ToString().Trim()
                  where ud_RoomContext.ut_BS001
                          .Where(b => b.BS01_02.Equals(No))
                          .Select(b => b.BS01_06)
                          .Any(bs01_06 => bs01_06.Contains(trimmedValue))
                  select new ut_BS001_A
                  {
                      BS01A_01 = room.BS01A_01,
                      BS01A_02 = room.BS01A_02,
                      BS01A_03 = room.BS01A_03
                  };
     return result;
 }

前端View渲染資料

我們在Vue裡面宣告了多個響應式資料去接Axios的回傳結果:

   const nowImg = ref(1); //紀錄當前輪播圖片
   const roomItem = ref(); //房間提供的服務設施
   const roomInfo = ref(); //房間資訊,價格等
   const roomImg = ref([]); //房間照片
   ...
     roomItem.value = response1.data;
     roomInfo.value = response2.data;
     let array = response2.data[0].bS01_07.split(",");
     for (var y = 0; y < array.length; y++) {
           roomImg.value.push({
                id:y+1,
                src: array[y]
           });
        };
     }))

▲房間照片的內容包在response2.data裡面,因此還要再做一個拆解的動作
接下來的v-for渲染,就跟昨天首頁的渲染方式很像,不過這次的資料我們是從DB拿過來的:

  • 輪播器渲染
 <div class="carousel-indicators">
     <button v-for="img in roomImg" v-bind:key="img.id" type='button' data-bs-target='#carouselExampleIndicators' v-bind:data-bs-slide-to="img.id-1" v-bind:class="{'active' : nowImg === img.id}" aria-current="true">
         <img v-bind:src="'../../img/'+img.src" class='d-block w-100'>
     </button>
 </div>
 <div class="carousel-inner">
     <div class="carousel-item" v-bind:class="{'active' : nowImg === img.id}" v-for="img in roomImg" v-bind:key="img.id">
         <img v-bind:src="'../../img/'+img.src" class="d-block w-100">
     </div>
 </div>

順帶一提,這個環節我之前透過js寫,是透過ajax的方式拿資料,寫出來長這樣:

//放房間相關圖片
 $.ajax({
            url: './GetRoomDetail',
            type: 'POST',
            async: false,
            data: { BS01_02: No },
            success: function (data) {
                var result = JSON.parse(data);
                var num = 1;
                for (var i = 7; i < 12; i++) {
                    var str = "0";
                    if (i < 10) {
                        str += i;
                    } else {
                        str = i;
                    }
                    if (result["BS01_" + str] != "" && result["BS01_" + str] != undefined) {
                        if (i == 7) {
                            $(".carousel-indicators").append("<button type='button' data-bs-target='#carouselExampleIndicators' style='width:120px;height:60px' data-bs-slide-to='" + (num - 1) + "' class='active' aria-current='true' aria-label='Slide " + num + "'><img src='../../Image/" + result["BS01_" + str] + "' class='d-block w-100'></button>");
                            $(".carousel-inner").append(" <div class='carousel-item active'><img src='../../Image/" + result["BS01_" + str] + "' class='d-block w-100'></div>");
                        } else {
                            $(".carousel-indicators").append("<button type='button' data-bs-target='#carouselExampleIndicators' style='width:120px;height:60px' data-bs-slide-to='" + (num - 1) + "' aria-label='Slide " + num + "'><img src='../../Image/" + result["BS01_" + str] + "' class='d-block w-100'></button>");
                            $(".carousel-inner").append("<div class='carousel-item'><img src='../../Image/" + result["BS01_" + str] + "' class='d-block w-100'></div>");
                        }
                        num += 1;
                    } else {
                        if (i == 7) {
                            $(".carousel-indicators").append("<button type='button' data-bs-target='#carouselExampleIndicators' style='width:120px;height:60px' data-bs-slide-to='" + (num - 1) + "' class='active' aria-current='true' aria-label='Slide " + num + "'><img src='../../Image/roomsetting_big.png' class='d-block w-100'></button>");
                            $(".carousel-inner").append("<div class='carousel-item active'><img src='../../Image/roomsetting_big.png' class='d-block w-100'></div>");
                            break;
                        } else {
                            break;
                        }
                    }
                }

◎說明:一樣從後端拿到一包房間資料,用迴圈判斷到圖片欄位的時候,appendHtml到介面上,看起來超級阿雜的…

  • 客房設備icon渲染
  <div id="ItemList">
      <span v-for="item in roomItem" v-bind:key="item.bS01A_01">
          <img v-bind:src="'../../img/'+item.bS01A_03" />
          &nbsp;<text>{{item.bS01A_02}}</text>&nbsp;&nbsp;&nbsp;
      </span>
  </div>

我們一樣跟js寫法比較看看,也是透過js去塞html,非常不好維護:

//取得目前所有設施
$.ajax({
            url: './GetAllItem',
            type: 'POST',
            async: false,
            data: {},
            success: function (data) {
                var result = JSON.parse(data);
                var num = 0;
                for (var i = 0; i < result.length; i++) {
                    if (i == 0 || i % 2 == 0) {
                        num += 1;
                        $("#ItemList").append("<div id='ItemRow" + num + "' style='display:flex;flex-direction:column;margin-left:2%;margin-top:2%;'></div>");
                    }
                    $("#ItemRow" + num).append("<span id='item" + result[i].BS01A_01 + "' style='color:#b3b3b3'><img style='filter:opacity(0.3);' src='../../Image/" + result[i].BS01A_03 + "'>&nbsp;" + result[i].BS01A_02 + "&nbsp;&nbsp;&nbsp;</span></br>");
                }
            },
            error: function (err) {
                console.log("無法取得當前所有設施列表!");
            },
        });

小結

改版訂房網站壓在三天內最終還是太硬了啦!TT,又要透過我沒接觸過的.net Core還有LinQ語法真的是很難徹底改版,內容的重點稍微調整了一下,看看Vue引入到專案後是如何改善我的前端程式碼,這樣一比較下來真的覺得之前用ajax也寫得太恐怖了吧…


參考資料
在Vue.js中使用Axios取得資料
Axios 并发请求怎么实现?这里有三种方法帮助你


上一篇
【Day28】.NET Core MVC & Vue—Bootstrap套件也能v-for!
下一篇
【Day30】歡迎參加我的原生JS畢業典禮
系列文
歡迎參加我的原生JS畢業典禮31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言