--- tags: VUE --- 【VUE】【VUE 3】簡介 === [官網](https://cli.vuejs.org/zh ## 資料夾結構 - public/ 大部分不會編譯, index.html會編譯 - src ## 環境變數 [說明](https://cli.vuejs.org/zh/guide/mode-and-env.html#%E6%A8%A1%E5%BC%8F) - 預設:development ```jsonld= "serve": "vue-cli-service serve --mode development", "build": "vue-cli-service build", ``` - .env: 一般的環境文件 - .env.production 優先權較 .env高 ## Router 1. 不用事先import ```javascript= { path: '/', name: 'home', component: () => import('./views/Home.vue') }, ``` [vue3中文手冊](https://www.vue3js.cn/docs/zh/guide/installation.html#cdn) [手冊2](https://v3.cn.vuejs.org/api/) ## 起手式 ```javascript= const App = { setup () { const msg = 'Hello Vue3' // vue 的資料,透過return放到html上 return {} } } Vue.createApp(App).mount('#app') ``` #### createApp - 將App物件載入 ## 綁定資料 - [用ref還是reactive](https://medium.com/i-am-mike/vue-3-ref-%E8%B7%9F-reactive-%E6%88%91%E8%A9%B2%E6%80%8E%E9%BA%BC%E9%81%B8-2fb6b6735a3c) ### ref - 可接受任何型別 ```javascript= const { ref } = vue const App = { setup() { const text = ref('Hello vue!') return { text } } } ``` ```javascript= text.value = 'ccccooo' ``` ```javascript= watch( () => text.value, (newValue) => { console.log(newValue) } ) ``` ### reactive - 只接受**陣列** 或 **物件** ```javascript= const message = reactive({ text: 'jucy'}) ``` ```javascript= watch( message, (newValue) => { console.log(newValue) } ) watch( () => message.text, () => { console.log() } ) ``` # Ref ```pug= input(ref="textInput" type="text" placeholder="輸入...") ``` ```javascript= setup() { const textInput = ref(null) onMounted(()=>{ console.log(textInput.value) // input實體 textInput.value.focus() }) return { textInput, } } ``` # Directive - example1 ```javascript= app.directive('focus', { mounted(el) { // el: dom元素 el.focus() } }) ``` ```pug= input(v-focus type="text" placeholder="輸入...") ``` - example2 - #### 資料改變: updated() ```javascript= app.directive('format-number', { mounted (el, binding) { const p = numPrice(binding.value) el.innerHTML = p }, updated (el, binding) { const p = numPrice(binding.value) el.innerHTML = p }, }) ``` ```pug= input(ref="textInput" type="text" v-focus v-model="price") h1(v-format-number="price") ``` # Watch ```javascript= watch(data, (newData, oldData) => { console.log(newData, oldData) }) watch( () => route.path, () => { } ); ``` # 組件Component ## props [v3 props文件](https://v3.vuejs.org/guide/component-props.html) - child component ```javascript= export default { props: [ 'options' ], setup(props) { return { props } } } ``` - 預設值 ```javascript= props: { type: Array, default: () => [], }, obj: { type: Object, default: () => ({}), }, obj2: { type: Object, default: (){ return {} } }, handleClick: { type: Function, default: () => {}, }, }, ``` - 引用組件 ```pug= .video-wrap Vue-Video(:options="videoOptions") ``` ## emit 參數1: 父層要接收事件的名稱 參數2: 要回傳的內容 - 子組件 ```javascript= emits: ['callBack'], setup (props, context) { const num = ref(0) onMounted(() => { context.emit('callBack', num) }) } // or setup (props, { emit }) { ... onMounted(() => { emit('callBack', num) }) } ``` - 父層 ```htmlembedded= <TextInput @callBack="handleCallBack" /> ``` ```javascript= const handleCallBack = (value) => { console.log(value) } ``` - emit 檢查 ```javascript= // vue warn emits: { callBack: (num) => { // if(num.value === 0) { // return true // } else { // return false // } return num.value === 0 } } ``` # VUEX ```javascript= import { useStore } from 'vuex' const store = useStore() ``` ### vuex modules ```javascript= import { createStore } from "vuex"; import state from "./state.js"; import actions from "./actions.js"; import mutations from "./mutations.js"; import getters from "./getters.js"; import Auth from "./Auth"; export default createStore({ state, actions, mutations, getters, modules: { Auth, }, }); ``` - namespaced: true ```javascript= // store / auth / index.js export default { namespaced: true, ... }; // .vue onMounted(() => { store.dispatch("Auth/handSetToken", "Acbz1x3WQw4eq9qilpFjregn"); console.log("TOKEN =>", store.getters["Auth/getToken"]); }); ``` ```javascript= actions: { async initLoad({ commit }) { try { const res = await apiGetPhotoRequest(); commit("setPhoto", res.data); return res.data; } catch (error) { console.error(error); } }, } ``` # Route, Router ```javascript= import { useRoute, useRouter } from "vue-router"; const route = useRoute(); const router = useRouter(); // route.params.id // router.go(-1); ``` ```javascript= watch(data, (newData, oldData) => { console.log(newData, oldData) }) watch( () => route.path, () => { } ); ``` # composition api ### 調整引入路徑 1. 共用index ```javascript= import { MousePosition } from './useMousePosition' export const useMousePosition = MousePosition ``` 2. export 方法 ```javascript= export function MousePosition () { ... return { ... } } ``` 3. import改變為 ```javascript= import { useMousePosition } from './composition-api' ``` ### toRefs - reactive 和 共用邏輯封裝解構問題 : toRefs ```javascript= return toRefs(pos) ``` ```javascript= return { ...toRefs(pos), name } ``` ----- ```javascript= export * as AModule from './a' - export ///=======等價=======/// import { default as aDefault, aaa, bbb } from './a' export const AModule = { default: aDefault, aaa, bbb, } ``` - 引用 ```javascript= import { AModule } from './test/index' aModule.aaa aModule.bbb aModule.default ``` # Suspense - [參考網址](https://medium.com/peerone-technology-%E7%9A%AE%E5%81%B6%E7%8E%A9%E4%BA%92%E5%8B%95%E7%A7%91%E6%8A%80/%E5%8D%87%E7%B4%9A-vue-3-%E5%89%8D-%E4%BD%A0%E5%BF%85%E9%A0%88%E8%A6%81%E7%9F%A5%E9%81%93%E7%9A%84%E6%94%B9%E5%8B%95-5891a297dbe2) ```htmlembedded= <!-- 傳統做法 --> <div v-if="loading"> Loading ...</div> <div v-else> {{ data }} </div> <!-- 使用 suspense --> <Suspense> <template #default>{{ data }}</template> <template #fallback> Loading... </template> </Suspense> ⚠️ #default #fallback 其實是 v-slot 的簡寫 ``` # 組件v-model 多個 v-model https://codepen.io/deathhell/pen/jOMZdMO?editors=1010 ```htmlembedded= <!-- 父組件 --> <user-name v-model:first-name="firstName" v-model:last-name="lastName"></user-name> ``` ```htmlmixed= <template lang="pug"> input( :value="inputValue" @input="$emit('update:inputValue', $event.target.value)" ) </template> <script> export default { props: { // input輸入值 inputValue: { type: [String, Number], default: '', }, }, </script> ```