2020年12月25日 星期五

React api 管理及應用 axios

    最近剛拿到 React 的 offer ,惡補一下,看六角的洧杰老師的文章提到最好是七成舊,三成新才比較容易聚焦問題避免整組壞光光不知道從何改起,或是進步太少,之前用 Vue Promise 處理 API 駕輕就熟,直到看到 Mike 的文章跟面試真的有人問有幾十隻 API 分散在不同 component 要怎麼處理,才拿這篇出來救駕,今天來實作如何用建立一個 JS 檔案的方式管理 API。

首先先建立拿來管理 API 的檔案 api.js

然後 import axios

import axios from 'axios';

建立不同大分類以及 baseUrl

const sixUrl = axios.create({
  baseURL: 'https://course-ec-api.hexschool.io/'
})

每個大分類下的不同分支 API

export const productList = () => sixUrl.get(`api/${uuid}/ec/products`)

uuid 是 get 六角 API 用的就不貼了,可依照各 API 權限控管進行調整。

回到需要使用的頁面,import api.js,並且選擇有 export 的 API

import { productList } from "./api";

透過 async await 完成 getData

function Home() {
  async function getData () {
    try {
      const item = await productList()
      console.log(item)
    } catch (err) {
      console.log(err)
    }
  }
  console.log(getData())
  return (
    <div>
      <h2>Home</h2>
    </div>
  );
}

console.log(item) 有資料就成功啦,基礎用法就到這邊,接下來要研究如何與 hook 一起使用作畫面更新。


參考資料:

Mike 的文章

2020年12月11日 星期五

Vue 使用 vue-drag-drop 完成 Drag & Drop

 Drag & Drop 就是網站的拖曳效果,今天要達成的目標就是有兩個區域A及B,裡面有資料,

把資料拖曳到任一個區域都可以在該區域新增資料,並刪除原區域內的資料。透過 HTML 的

拖放 API,設定多而且 DOM 的長度可觀。


原理簡略的說: Drag 是可拖動的物件,Drop 是可放置的區域,透過今天使用的套件,可以使 

Drag 帶著資料去觸發 Drop 的事件,達成放置資料或其他操作。


import VueDragDrop from 'vue-drag-drop';
Vue.use(VueDragDrop);

先 import 跟 use,官方文件有一個範例,比較接近 Basic list support ,不過這個範例有幾個需要

改變的地方,第一個是兩個區域不能總貼在一起,再來是如何讓排列順序是有序的,範例中

使用 .sort 進行陣列重排,我希望跟積木一樣可以使用者將資料移到那就把資料放在那。


<template>
<div>
  <div class="container">
    <div class="row">
      <div class="col-3">
        <div class="drop">
          <div v-for="(item, i) in testList[0]" :key="i">
            <drop @drop="drop1(item, ...arguments)">
              <drag class="drag"
                :transfer-data="{ item: item, list: testList[0], example: 'lists' }">
                {{ item }}
              </drag>
            </drop>
          </div>
        </div>
      </div>
      <div class="col-9">
        <div class="drop">
          <div v-for="(item, i) in testList[1]" :key="i">
            <drop @drop="drop2(item, ...arguments)">
              <drag class="drag"
                :transfer-data="{ item: item, list: testList[1], example: 'lists' }">
                {{ item }}
              </drag>
            </drop>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
</template>


template 使用 bootstrap 進行簡單的排版,左右有兩個框,分別放置 testList[0] 跟 testList[1] 的

陣列,裡面的資料稍微用 CSS 讓資料變清楚,不同的區域基本方法是相同只是觸發區域

不一樣,可以看到每個 item 有一個 drop 讓 drag 可被放上去,也有 drag 讓 item 可被拖曳,

<drag> 以及<drop> 標籤就是 vue-drag-drop 套件替你省下了無數的 DOM 指令。


@drop(item, ...arguments) 方法是官方推薦的,表示當 drag 被放進 drop 時觸發的方法,第一個參數是 drop 所在的元素,第二個參數是 drag 額外帶的 data。 drag攜帶資料的方法:

<drag class="drag"
                :transfer-data="{ item: item, list: testList[1], example: 'lists' }">

利用 :transfer-data,攜帶 drag 的 item ,所在的 array ,或其他。


最後處理方法,只要清楚 drag 在哪? drop 在哪? 那哪裡應該放置新資料或刪除已移動的資料就是小事了。splice(索引, 從索引之後刪除幾項, 加入的資料)。


methods: {
    drop1 (item, data) {
      const testlist = data.list
      // drag 所在的陣列
      this.testList[0].splice(this.testList[0].indexOf(item), 0, data.item)
      // 接收的 drop 新增 item
      testlist.splice(testlist.indexOf(data.item), 1)
      // 刪除原陣列的 item
    },
    drop2 (item, data) {
      const testlist = data.list
      // drag 所在的陣列
      this.testList[1].splice(this.testList[1].indexOf(item), 0, data.item)
      // 接收的 drop 新增 item
      testlist.splice(testlist.indexOf(data.item), 1)
      // 刪除原陣列的 item
    }
  }


成品圖:兩個區域為了清晰加了一個固定大小的框,所以如果全部資料都在同一個區域會爆版,自行調整 CSS 即可。




參考資料:

MDN

vue-drag-drop 文件

2020年12月7日 星期一

vue-chart.js 及 Chart.js 在 Vue 中製作圖表

 Chart.js 是個可以方便製作圖表的 JavaScript library,可以在 HTML 中產生一個 canvas 物件產生

圖表。這篇以線圖舉例。


首先先 npm 安裝

npm install vue-chartjs chart.js --save


 Chart.js 的基本寫法是 new Chart,綁定一個 ID,裡面有三個參數:圖表類型( examle: line )、

資料內容 ( data )、選項( option ),HTML 中的 canvas 物件可以直接設定大小,但今天用 Vue,

所以要看看有什麼不同。


首先用 Vue 渲染的 canvas 是不能有 template 的,意味著通常要用 components 方式載入,不然整個畫面只有圖,使用 .vue 或 .js 檔案皆可,筆者比較習慣用 .vue。先製作空白圖表的 components。

在components 資料夾下新增 Chart.vue


import { 圖表種類 } in 'vue-chartjs';
extends: 圖表種類,
使用 mounted 得到資料後繪圖,圖表種類已經 import 過了,所以剩下 data、option 兩個參數。
一張圖表可以輸入不同的資料匯出不同的線圖,所以用 props 讓空白的表接收父組件的數據。

接下來回到父組件:

import 子組件 + components 子組件

import Chart from '../components/Chart.vue';
components: {
    Chart,
  },

template 放入組件的部分:

<template>
  <div>
    <div class="container">
      <div class="row">
        <div class="col-6">
          <chart v-if="loaded"
            :chartdata="chartdata"
            :options="options">
          </chart>
        </div>
      </div>
    </div>
  </div>
</template>


筆者有用 bootstrap 框架,這樣可以控制子組件,也就是圖表的大小,將 data 與 option 傳入組件,
為什麼要加上 v-if ?因為組件得到數據之後,"不會"重新繪圖
所以要透過確認有得到數據才繪圖。


json 格式的 data,沒有 API ,用 json-server 模擬從 API 得到資料,npm install -g json-server,用 VSCode ctrl+`打開終端機,然後 json-server --watch 想要觀測的檔案,沒取名照教學是db.json,npm install --save axios vue-axios 用來串接 API,別忘了 main.js 要加入 Vue.use(VueAxios, axios) 。


資料格式:

 data() {
    return {
      chartdata: {
        labels: [],
        datasets: [
          {
            label: '0050',
            fill: false,
            backgroundColor: 'rgba(188,96,147,1)',
            borderColor: 'rgba(212,85,49,1)',
            pointBackgroundColor: 'rgba(41,56,69,1)',
            data: [],
          },
        ],
      },
      options: {
        title: {
          display: true,
          fontSize: 24,
          text: '2020/11 0050 價格走勢',
        },
      },
      loaded: false,
    };
  },


chartdata 與 option 都必須是物件,chartdata 裡面就是 data,有兩個屬性,第一個 lebal 是 x 軸的值,是陣列,而 y 軸的值放在 datasets 的 data 下面。

將 json server 的數據陣列加入,並在 create 階段載入:

created() {
    this.getData();
  },
  methods: {
    getData() {
      const api = 'http://localhost:3000/0050';
      this.$http.get(api).then((res) => {
        this.chartdata.labels = res.data[0].Date;
        this.chartdata.datasets[0].data = res.data[0].Price;
        this.loaded = true;
        this.$forceUpdate();
      }).catch((error) => {
        if (error) {
          console.log(error);
        }
      });
    },
  },


中間有混入一個 loaded ,就是剛剛提到的拿來判斷是否收到數據,啟動子組件的繪圖。

最後就是剩下看文件找適合的選項把標題跟圖表畫的美美的。


附上 json 的結構,這個表是從證交所下載 .csv 並手動重製,x 軸為時間,y 軸為當天價格:



 


參考資料:

https://www.chartjs.org/

https://vue-chartjs.org/

https://dylan237.github.io/json-server.html

2020年12月4日 星期五

npm報錯:code ENOENT

 Google了一下發現是 npm 不知為何找不到正確的路徑,解決方法是

將 node_modules 資料夾刪除,再重新 npm install,之後就恢復正常了。


嘗試過 npm cache clear、npm install 有安裝過的套件、更新 Node.js 及 Vue Cli。


參考資料:

https://blog.csdn.net/weixin_43170297/article/details/96436565

https://stackoverflow.com/questions/17990647/npm-install-errors-with-error-enoent-chmod/23446110

https://juejin.cn/post/6864809486675574792

2020年12月2日 星期三

初學 TypeScript,型別註記的方法

 TypeScript 是強型別語言,相對於 JavaScript 的弱型別,例如 1 可以是 number ,也可以是 '1' 字串,如果是外部資料甚至是自己筆誤會得出錯誤結果而不自知。


TypeScript 簡單的定義型別的方法是用 : ,例如:

let name: string = 'Jack';


物件的定義:

let account: {name: string, password: string} = {

  name: 'Jack',

  password: 'abc4567',

};


函式的定義:


let addition = function(param1:number, param2:number) {

  return param1 + param2;

};


使用 type 作出一組型別定義,使用方法跟上述一樣接在:後面:

type accountInfo = {

  account: string,

  password: string,

  nickname: string,

  birth: Date,

  subscribed: boolean,

};


在 TypeScript 覆寫物件屬性值會有一個問題是必須完全覆寫,但以帳號資料或購物資料表單為例,實務上常常會有許多選填,因此需要選用註記?。


type accountInfo = {

  account: string,

  password: string,

  nickname?: string,

  birth?: Date,

  subscribed?: boolean,

};


let accountData: accountInfo = {

  account: 'Jack',

  password: 'abc1234',

}

雖然缺少了 nickname...等三個屬性沒有完全覆寫,但可以通過 TypeScript 的檢驗,筆記資料較為精簡,原文有詳細及深入的範例探討,有鐵人賽文章及實體書可選看。

參考資料:讓 TypeScript 成為你全端開發的 ACE! Day1~Day9