--- tags: share disqus: hackmd --- # 1100304 Vue 元件樹 --- * Nuxt 除了把vue檔案變成 router,也會有切換組件的功能(可從 vuetool 的 nuxt 組件下看出利用索引值切換組件) * template 就是元件模板( angular 也是將模板內的標籤視為字串) * 利用 `{{}}` 將字串轉成 `dom` * `:bind` 綁的屬性值為動態屬性(在編輯器上通常跟變數同個顏色),父組件傳值給子組件時用。 Vue --- * 在vue中父組件權限比較高 * 父組件傳屬性給子組件時是同js原生傳值原理(傳記憶體位置),因此子組件不可以主動改父組件資料(動態綁定屬性get跟set會被vue綁架),只能通知父組件要改資料,由父組件建立處理方式去修改 * v-for的`:key`屬性要寫:有`:key`之後,同一個key值的template不用重新渲染,可以優化效能。 元件詳解 --- * 一般寫法computed到class寫法會變成get * 父子組件如何溝通 `$emit、$on`都在Vue Class裡面 `this.$on`等於@(就是監聽事件) ```javascript= // 子組件 onClick(item){ this.$emit('onClick',item) this.$on('onClick',()=>{ }) } // 父組件模板 <Child @onClick="doSomething"><> // 父組件方法 doSomething(item){ // item 是子組件傳過來的值 } ``` 關於bus --- * 叫第三方(bus)去做通知,就跳過中間子組件傳值到任何地方。 * bus也是一個Vue Class * 靈活度高但不常用(因為不好維護,可能發生不確定bus的事件,有幾個組件註冊),通常用Vuex Vuex --- * vuex是單向流 * 轉資料中心,等同bus,只有兩種功能:拿資料取資料。 * `mutation` 是處理資料的地方 * `state` 是放資料的地方 * 使用時機:資料共用時,如登入狀態、購物車清單(可以想像原本存放在 local storage 的東西現在存放在Vuex,只要定義好 action 跟 mutation,再利用state就可以取得資料,就不用把資料傳來傳去) ```javascript= export default class DefaultLayout extends Vue { @State(state => state.app.sidebarTabMap) sidebarTabMap!: IMap<IRoute[]>; // or @State(state => state.app.sidebarTabMap) // 利用裝飾器State取得app中sidebarTabMap的資料 sidebarTabMap!: IMap<IRoute[]>; // 此處的sidebarTabMap是代表此Class的屬性,可自定義 // 裝飾器要緊鄰要使用的元素,可以換行但不可以空行 } ``` 專案 --- * store資料夾下存的是vuex state裡的模組 * `import { Vue, Component, State, Watch } from "nuxt-property-decorator";` 引入裝飾器 * 公用函式放在utils資料夾下 ### EXCEL * [系統權限作業角色](https://docs.google.com/spreadsheets/d/1vSMY4rcmpTLdiYczlPGDT4E26qZGA-VAJailjqJLKx8/edit#gid=1839445946) ![](https://i.imgur.com/b3ZWD1d.png) * ***GAD0104門禁異常清單 // 表示 API 文件名稱*** * ***gateLog // 表示優先使用此英文命名*** * [API:藍底表示一支 API](https://drive.google.com/drive/folders/1NIF1ChLxH1lY7hm8XvEfJsRpaYS8ymCF) ![](https://i.imgur.com/Z5Orinv.png) ### 專案建立流程:目標是畫出畫面,並建立基礎功能 18:43 1. 開 UI 介面了解有哪些功能、畫面。 2. 至 EXCEL 確認文件格式、API。 3. 建 DTO(models資料夾):讓編輯器認得懂我要的文件格式。 ![](https://i.imgur.com/hV7OvGX.png) ![](https://i.imgur.com/9JxQAWq.png) * **回傳**(`I.....`開頭,`Res`結尾) * 使用`interface`建立,因為回傳值由他方回傳,通常不會被修改或`new()`。 * 如果`interface`的資料是列表`[]`,就要先`interface`列表型別,再`interface`列表內各項資料的型別(命名規則:列表`List`、列表項目`Item`)。 * **傳入**(`ReqDTO`結尾) * 表示此`Class`會被當成參數打出去。 * API 由我方所建立的,所以用`class`建(因為會`new()`)。 * 一個`Res`就會對應一個`ReqDTO`。 * 實例 **EXCEL** ![](https://i.imgur.com/g0kPCTV.png) ![](https://i.imgur.com/x5LZ4JA.png) **程式碼** ```javascript= // ======= STEP ========= // 1.Class 定義傳入值型別:到 API excel 複製資料型別(提醒:編輯器內建型別開頭小寫,自定義 Class 型別開頭大寫) // 2.資料定義型別、給初始值。 // 3.建立標題註解(打/**再按enter) - 第9行查詢系統登入記錄 // 4.interface 定義回傳值型別 (重複上1.2.3步驟):code、msg、data 為泛型因此不用定義在 interface 內,且interface 只要給型別不用給初始值 /** * 查詢系統登入記錄 */ export class SYS0401LoginListReqDTO { beginDate: string = ""; // 起始日期 endDate: string = ""; // 終止日期 accountId: string = ""; // 登入者帳號 result: string = ""; // 登入結果 ip: string = ""; // 登入IP } export interface ISYS0401LoginListRes { loginLogList: ISYS0401LoginItem[]; // 登入記錄列表 } export interface ISYS0401LoginItem { logDT: string; // 登入時間 accountId: string; // 登入者帳號 ip: string; // 登入者IP result: string; // 登入結果 remark: string; // 備註 } /** * 匯出登入記錄 */ export class SYS0401ExportLogReq { beginDate: string = ""; // 起始日期 endDate: string = ""; // 終止日期 accountId: string = ""; // 登入者帳號 result: string = ""; // 登入結果 ip: string = ""; // 登入IP } export interface ISYS0401ExportLogRes { fieldId: number; // 檔案ID fieldUrl: string; // 檔案URL } // ======= 快捷鍵 ========== ctrl+alt+上下:同時多個游標 ctrl+end:飛到該行最後面 ctrl+左右:一次跳一組字 選取單字後+ctrl+D:向下選取同樣名稱的單字 shift+alt+上下:複製 ``` 4. 建 API(api 資料夾) * EXCEL ![](https://i.imgur.com/dvP0IDt.png) * 程式碼 ```javascript= // ***** 固定引用 axios 套件,API統一的出入口 import { $axios } from "@/utils/pluginsInstance"; import { SYS0401ExportLogReq, SYS0401LoginListReqDTO } from "~/models/SYS/SYS04/loginLog/SYS0401DTO"; // ***** api路徑位置("sys0401/list")就是excel的項目代號(如上圖) // ***** getLoginLogList 為下方定義的方法 export const API = { getLoginLogList: "sys0401/list", // 查詢系統登入記錄 exportLoginLogList: "sys0401/export" // 匯出登入記錄 }; // ***** params 代表參數,:後接型別 // ***** $axios.$post(參數1:打API的位置,參數2:資料) export const getLoginLogList = (params: SYS0401LoginListReqDTO) => $axios.$post(API.getLoginLogList, params); export const exportLoginLogList = (params: SYS0401ExportLogReq) => $axios.$post(API.exportLoginLogList, params); ``` 5. 畫畫面(pages資料夾) * 查詢框及 table 會是分開的組件。 * 建組件(components資料夾,新增的組件資料夾名稱參考**系統作業權限角色**)。 ![](https://i.imgur.com/dZkPFcE.png) ![](https://i.imgur.com/M6NSVBw.png) * 組件畫面可以直接複製,但是內文class名稱記得修改 * 程式碼 ```javascript= // 1.修改元件名稱 // 2.按照UI畫面分組件 // 3.到components資料夾建立組件檔案 檔案如果用複製的要記得改內文class名稱 // 4.回到page掛載組件 // 先 import import 組件名稱 from 'component資料夾位置的組件檔案' // 註冊元件(如果名稱取的一樣就只要寫一次) @Component({component:{元件名稱:元件屬性值}) // 5.修改template v-model等v開頭的屬性要優先先在前面 // 6.到頁面測試元件是否運作正常(值有沒有傳入DTO) // 比對時要寫3個等於=== // 取得API資料用then,接後端丟出來的值 catch處理失敗(如後端取不到資料) .then((放參數)=>{ }) .catch(()=>{ });`` // ***** 板手開頭就是api建的方法 <script lang="ts"> // ***** 來源是utils或model/common,表示公用函式或物件 import { Vue, Component, Prop, Watch } from "nuxt-property-decorator"; import { updateFormByTableOption } from "~/utils/form"; import { ITableOptions } from "~/models/common/PagesDTO"; import { SYS0401LoginListReqDTO } from "~/models/SYS/SYS04/loginLog/SYS0401DTO"; import { vRequired } from "~/utils/validate"; // ***** @Component(components: {}) 用來引入 import 進來的組件 @Component({ components: {} }) export default class SYS0401SearchForm extends Vue { valid = false; // ****** searchFrom 為我們自己建的 DTO(傳入值資料格式) searchForm = new SYS0401LoginListReqDTO(); // ***** 驗證表單固定寫法 rules = { beginDate: [vRequired("請輸入日期")], endDate: [vRequired("請輸入日期")] }; // ****** resetFrom 重設資料:讓 searchForm 初始化 resetForm() { this.searchForm = new SYS0401LoginListReqDTO(); } // ****** searchFrom 查詢資料 // ****** $refs:父元件取得子元件資料的方法(避免function傳參數):利用this.$refs(子組件標籤要綁屬性 ref='searchForm') // ***** .validate()為 vuetify 給 v-form 的方法 search() { (<any>this.$refs.searchForm).validate(); if (this.valid) { this.$emit("onSearch", true); } else { this.$warningMsg(); } } updateSearchForm(options: ITableOptions) { updateFormByTableOption(options, this.searchForm); } } </script> ``` Vuetify --- * 優先使用vuetify api * v-card:卡片 在畫面上製作形狀通常都會使用 v-card,其下還有很多子組件 * v-card-action:按鈕欄位 * v-card-text:內容 * v-card-subtitle * v-card-title:標題 * v-form:表格 * 屬性 API * counter:input 輸入字數限制,預設25(要搭配欄位綁v-model才會生效) * disabled:輸入框禁用(如果要從Vue定義的屬性值判斷,就以:disabled="屬性名字"作綁定) * StatusSelect:定義狀態 * dense:小尺寸 JS --- js 傳值的方法:指到同一個記憶體位置(傳址) ```javascript= const obj1 ={ // 複雜型別 a1:1, // 簡單型別 a2:{ // 複雜型別 a3:1 // 簡單型別 } } obj2 = 0bj1; obj2.a1=2; obj1 // 2; ``` 淺拷貝、深拷貝 --- 待補 關於程式命名 --- _aaa:表示私有屬性(做不可告人的事情) Sourcetree --- * 先 Fetch 再 Merge * 要併到dev跟 Karta 說 函式工廠 --- a = () => () => ..... * 它是一個函式。 * 它用來建立物件。 * 它像工廠一樣,生產出來的函式都是標準件(擁有同樣的屬性)