---
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>
```