iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0
SideProject30

Nuxt3的初心者之旅:淬鍊出屬於自己的金融投資儀表板系列 第 18

DAY18 - 誰是賠錢貨- Nuxt3建立HighChart股票績效比較圖(2)

  • 分享至 

  • xImage
  •  

今日工事

可以任意增加或刪減想要比較的股票
完成動態的股票績效圖

移除

// [id].vue
const stockChart2Api = `https://financialmodelingprep.com/api/v3/historical-price-full/meta?timeseries=365&apikey=${fmp}`
const stockChart3Api = `https://financialmodelingprep.com/api/v3/historical-price-full/googl?timeseries=365&apikey=${fmp}`

const getDataApi=()=>{
    // ...略
    const getSecondChart = axios.get(stockChart2Api)
    const getThirdChart = axios.get(stockChart3Api)
}

const stockChart2 = ref()
const stockChart3 = ref()

const stockChart2Rev = computed(() =>
  stockChart2.value ? stockChart2.value.reverse() : []
)

const stockChart3Rev = computed(() =>
  stockChart3.value ? stockChart3.value.reverse() : []
)

const stockChartFix2 = computed(() => {
  return fix(stockChart2Rev.value)
})

const stockChartFix3 = computed(() => {
  return fix(stockChart3Rev.value)
})

先移除昨天示範用固定的股票線圖

增加&刪減

// [id].vue
<ClientOnly>
        //增加股票
          <div class="flex items-center ">
            <font-awesome-icon
              :icon="['fas', 'circle-plus']"
              size="xl"
              style="color: #157d7f"
              @click="searchAdd = !searchAdd"
              class="mb-2"
            />
            <vue3-simple-typeahead
              id="typeahead_add"
              placeholder="搜尋股票..."
              v-if="searchAdd"
              class="w-[300px] m-4 p-1 bg-white rounded shadow :active:border-white"
              :items="checkData"
              :minInputLength="1"
              v-model="searchAddStock"
              @onInput="onInputEventHandler"
              @keydown.native.enter="changeChart('add')"
              @selectItem="selecAddtItem"
            >
              <template #list-item-text="slot">
                <div class="">
                  <span
                    class="inline-block w-[300px] bg-white rounded shadow ms-4 mb-1"
                    v-html="slot.boldMatchText(slot.itemProjection(slot.item))"
                  ></span>
                </div>
              </template>
            </vue3-simple-typeahead>
          </div>
          // 減少股票
          <div class="flex items-center">
            <font-awesome-icon
              :icon="['fas', 'circle-minus']"
              size="xl"
              style="color: #157d7f"
              class="inline-block"
              @click="searchRemove = !searchRemove"
            />
            <vue3-simple-typeahead
              id="typeahead_remove"
              placeholder="搜尋股票..."
              v-if="searchRemove"
              class="w-[300px] m-4 p-1 bg-white rounded shadow :active:border-white"
              :items="checkData"
              :minInputLength="1"
              v-model="searchRemoveStock"
              @onInput="onInputEventHandler"
              @keydown.native.enter="changeChart('remove')"
              @selectItem="selectRemoveItem"
            >
              <template #list-item-text="slot">
                <div class="">
                  <span
                    class="inline-block w-[300px] bg-white rounded shadow ms-4 mb-1"
                    v-html="slot.boldMatchText(slot.itemProjection(slot.item))"
                  ></span>
                </div>
              </template>
            </vue3-simple-typeahead>
          </div>
</ClientOnly>

<script setup>
const route = useRoute()
const id = route.params.id

// key
const fmp = import.meta.env.VITE_KEY_FMP

// API
const stockChartApi = `https://financialmodelingprep.com/api/v3/historical-price-full/${id}?timeseries=365&apikey=${fmp}`

const getDataApi=()=>{
    const getFirstChart = axios.get(stockChartApi)
    return [getFirstChart]
}

// 股票圖表資料
const stockChart = ref()

const stockChartRev = computed(() =>
  stockChart.value ? stockChart.value.reverse() : []
)

// 增加&刪減股票

const searchAdd = ref(false)
const searchRemove = ref(false)
const checkData = ref([])
const searchAddStock = ref('')
const searchRemoveStock = ref('')

const MultiChart = ref([])

watchEffect(() => {
  MultiChart.value = stockChartFix
    ? [
        {
          name: `${id}`,
          data: stockChartFix.value,
        },
      ]
    : []
})

// 輸入關鍵字時找出相關名稱股票
const searchApi = computed(() => {
  return `https://financialmodelingprep.com/api/v3/search?query=${searchAddStock.value}&limit=10&exchange=NASDAQ&apikey=${fmp}`
})

// 增加該筆股票的過去一年股價
const addChartApi = computed(() => {
  return `https://financialmodelingprep.com/api/v3/historical-price-full/${searchAddStock.value}?timeseries=365&apikey=${fmp}`
})

// item是這個callback的預設參數 就是input的值
const selecAddtItem = (item) => {
  searchAddStock.value = item
}

const selectRemoveItem = (item) => {
  searchRemoveStock.value = item
}

const onInputEventHandler = () => {
  axios.get(searchApi.value).then((res) => {
    checkData.value = res.data.map((v) => v.symbol)
  })
}

const changeChart = async (change) => {
  if (change === 'add'){
    let newChart = []
    await axios
      .get(addChartApi.value)
      .then((res) => {
        newChart = res.data.historical
      })
      .catch((rej) => {
        console.log(rej)
      })
    newChart = newChart.reverse().map((v) => {
      const dateTimeString = v.date // 日期
      let milliseconds // 換算後的時間
      const dateObject = new Date(dateTimeString)
      milliseconds = dateObject.getTime()
      return [milliseconds, v.close]
    })
    MultiChart.value.push({ name: searchAddStock.value, data: newChart })
  }else if(change === 'remove') {
    MultiChart.value = MultiChart.value.filter(item => item.name !== searchRemoveStock.value)
  }
}

const chartOptionsMulti = computed(() => {
  return {
    //... 略
    series: MultiChart.value,
  }
})
<script>

<template>先增加2個預先輸入搜尋框及2個font-awesome的圖標(+,-)
圖標只有前端有
所以外面要加一層<ClientOnly>

再來是績效圖的設定項chartOptionsMulti
裡面放資料的地方也就是series只吃array

那在進來這個股票頁的時候只有該股票的績效
所以array一開始只有一筆資料[{name: ``${id}``,data: stockChartFix.value, }]
而這筆資料是等打完api之後才會取得
該用computed讓它自動更新該筆資料

但因為array之後還會增加或刪除元素
computed過的資料不能直接去做更改
所以改用watchEffect去操作MultiChart這個array
保有增減資料的彈性

之後就是在預先輸入搜尋框
輸入要增加或刪減的股票名稱
再用push新增或filter過濾
就完成動態的績效比較圖了!!

成品

https://ithelp.ithome.com.tw/upload/images/20231003/20162573vj26y2dY3R.png

https://ithelp.ithome.com.tw/upload/images/20231003/20162573QHW7tqQ4se.png

小結:

搜尋框其實有個小bug
(就預先輸入框出現的時候,會推到下面的block導致其他畫面跟著移動,而不是覆蓋過去)
其他地方可能或多或少也有吧!

但重要功能先出來
還是比較重要

還是來找一天處理
主題訂為"修理這些微小又確切的bug"...嗎?


上一篇
DAY17 - 誰是賠錢貨- Nuxt3建立HighChart股票績效比較圖(1)
下一篇
DAY19 - 重新上路 - 調整部分UI
系列文
Nuxt3的初心者之旅:淬鍊出屬於自己的金融投資儀表板30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言