npm create vue@latest
### Run
npm install
npm run dev
只能監視以下四種屬性
watch 函數有返回值,用來執行停止監視。
<template>
<div>{{ sum }}</div>
<button @click="changeSum">Click</button>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
const sum = ref(0);
const changeSum = () => {
sum.value += 1;
};
const stopWatch = watch(sum, (newVal, oldVal)=>{
console.log("Sum Change", newVal, oldVal);
stopChange();
});
</script>
<template>
<div>{{ person.name }}--{{ person.age }}</div>
<button @click="changeName">Name</button>
<button @click="changeAge">Age</button>
<button @click="change">All</button>
</template>
<script lang="ts" setup>
import { ref, watch } from "vue";
const person = ref({
name: "JJ",
age: 28,
});
const changeName = () => {
person.value.name += "~";
};
const changeAge = () => {
person.value.age += 1;
};
const change = () => {
person.value = { name: "LL", age: 15 };
};
watch(
person,
(newVal, oldVal) => {
console.log("change", newVal, oldVal);
},
{
deep: true, // 深度監視
immediate: true, // 立即監視
}
);
</script>
<template>
<div>{{ person.name }}--{{ person.age }}</div>
<button @click="changeName">Name</button>
<button @click="changeAge">Age</button>
<button @click="change">All</button>
</template>
<script lang="ts" setup>
import { reactive, watch } from "vue";
const person = reactive({
name: "JJ",
age: 28,
});
const changeName = () => {
person.name += "~";
};
const changeAge = () => {
person.age += 1;
};
const change = () => {
Object.assign(person, { name: "LL", age: 15 });
};
watch(
person,
(newVal, oldVal) => {
console.log("change", newVal, oldVal);
}
);
</script>
<template>
<div>{{ person.name }} <button @click="changeName">Update</button></div>
<div>{{ person.age }} <button @click="changeAge">Update</button></div>
<div>
{{ person.car }}
<button @click="changeBrand">Brand</button>
<button @click="changePrice">Price</button>
<button @click="changeCar">All</button>
</div>
</template>
<script lang="ts" setup>
import { reactive, watch } from "vue";
const person = reactive({
name: "JJ",
age: 28,
car: {
brand: "Benz",
price: 1000,
},
});
const changeName = () => (person.name += "~");
const changeAge = () => (person.age += 1);
const changeBrand = () => (person.car.brand += "!");
const changePrice = () => (person.car.price += 50);
const changeCar = () => (person.car = { brand: "BWM", price: 5000 });
watch(
() => person.name,
() => console.log("Name Change")
);
watch(
() => person.age,
() => console.log("Age Change")
);
/**
* 當物件中屬性變動時,則觸發。changeBrand、changePrice
* 當物件整個變動時,則不會觸發。changeCar
*/
// watch(person.car, () => console.log("Car Change"));
/**
* 寫成函數形式,變為監聽位址,所以:
* 當物件中整個變動時,則觸發。changeCar
* 當物件屬性變動時,則不會觸發。changeBrand、changePrice
* 函數形式要兩者情況皆觸發時需加上 { deep:true }
*/
watch(
() => person.car,
() => console.log("Car Change"),
{ deep: true }
);
</script>
<template>
<div>{{ temp }}-{{ height }}</div>
<div>
<button @click="changeTemp">Temp</button>
<button @click="changeHeight">Height</button>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, watchEffect } from "vue";
const temp = ref(10);
const height = ref(0);
const changeTemp = () => (temp.value += 10);
const changeHeight = () => (height.value += 50);
// watch([temp, height], (value) => {
// const [newTemp, newHeight] = value;
// console.log(newTemp, newHeight);
// if (newTemp >= 60 || newHeight >= 80) {
// console.log("Fetch");
// }
// });
watchEffect(() => {
if (temp.value >= 60 || height.value >= 80) {
console.log("Fetch");
}
});
</script>
export interface IPerson {
id: number;
name: string
}
<template>
<Person
first-name="Wang"
last-name="JJ"
:user="personList[0]"
:user-list="personList"
></Person>
</template>
<script lang="ts" setup>
import Person from "./components/Person.vue";
import type { IPerson } from "./types";
// 補充:在 vite 中引入 interface 或 type 型態,需加上 type 關鍵字
const personList = [
{
id: 1,
name: "JJ",
},
{
id: 2,
name: "JJay",
},
{
id: 3,
name: "Jay",
},
] as IPerson[];
</script>
<template>
<div>{{ firstName }}--{{ lastName }}</div>
<hr>
<div>{{ user?.id }}--{{ user?.name }}</div>
<hr>
<div v-for="item in userList" :key="item.id">
{{ item.name }}
</div>
</template>
<script lang="ts" setup>
import type { IPerson } from "@/types";
import type { PropType } from "vue";
defineProps({
firstName: {
type: String,
},
lastName: {
type: String,
required: true,
},
user: {
type: Object as PropType<IPerson>,
required: false,
},
userList: {
type: Array<IPerson>,
required: true,
},
});
</script>
<template>
<div>{{ id }}</div>
</template>
<script setup lang="ts">
import { defineProps } from "vue";
defineProps(["id", "name", "age"]);
</script>
// url: /demo/001/JJ/25
{
name: "demo",
path: "/demo/:id/:name/:age",
component: () => import("@/Demo.vue"),
props: true
}
// url: /demo?id=001&name=JJ&age=25
{
name: "demo",
path: "/demo",
component: () => import("@/Demo.vue"),
props: (route) => route.query
}
{
name: "demo",
path: "/demo",
component: () => import("@/Demo.vue"),
props: {
id: "001",
name: "JJ",
age: 28
}
}
npm i pinia
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from "pinia";
const pinia = createPinia();
createApp(App).use(pinia).mount('#app')
Store 的建立方式可分為 Option Store、 Setup Store。
import { defineStore } from "pinia";
export const useCountStore = defineStore("count", {
state() {
return {
count: 1,
};
},
getters: {
bigSum: (state) => state.count * 10,
},
actions: {
increament(value: number) {
this.count += value;
console.log(this, value);
},
},
});
use
開頭及 Store
結尾,例如:useCountStoreimport { ref } from "vue";
export const useCountStore = defineStore("count", () => {
const count = ref(0);
const increament = () => (count.value += 1);
return { count, increament };
});
import { useCountStore } from "@/store/count";
const countStore = useCountStore();
countStore.count +=1;
import { useCountStore } from "@/store/count";
const countStore = useCountStore();
/*$patch 方法特性為可一次修改多的數值*/
countStore.$patch({
count: 50
});
import { useCountStore } from "@/store/count";
countStore.increament()
<template>
<h4>Father</h4>
{{ data }}
<Child @change-msg="updateMsg" @change-count="updateCount"></Child>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
import { ref } from "vue";
const data = ref({ msg: "Hi", count: 50 });
const updateMsg = () => (data.value.msg += "~");
const updateCount = (value: number) => (data.value.count += value);
</script>
<template>
<h4>Child</h4>
<div>
<button @click="editMsg">Change Msg</button>
<button @click="editCount">Change Count</button>
</div>
</template>
<script setup lang="ts">
const emit = defineEmits(["change-msg", "change-count"]);
const editMsg = () => emit("change-msg");
const editCount = () => emit("change-count", 5);
</script>
<template>
<div>
{{ car }}
<button @click="updateSon($refs)">Update Son</button>
</div>
<hr />
<Father ref="father"></Father>
</template>
<script setup lang="ts">
import { ref } from "vue";
import Father from "./Father.vue";
const car = ref("Benz");
// 組件提供存取的資料
defineExpose({ car });
const father = ref();
const updateSon = (refs: any) => {
console.log(refs.father.toy);
father.value.toy = "cat";
father.value.price += 10;
};
</script>
<template>
{{ toy }}--{{ price }}
{{ show($parent) }}
<hr />
</template>
<script setup lang="ts">
import { ref } from "vue";
const toy = ref("dog");
const price = ref(50);
// 組件提供存取的資料
defineExpose({ toy, price });
// 使用 $parent 取得父組件開放存取的資料
const show = (parent: any) => console.log(parent);
</script>
可用來接收 props 有傳入,但子組件沒有接收的資料
<template>
<h2>GrandPa</h2>
<hr>
<Father :a="1" :b="2" :c="3"></Father>
</template>
<script setup lang="ts">
import Father from './Father.vue';
</script>
<template>
<h2>Father--{{ a }}--{{ $attrs }}</h2>
<hr />
<Son v-bind="$attrs"></Son>
</template>
<script setup lang="ts">
import { useAttrs } from "vue";
import Son from "./Son.vue";
defineProps(["a"]); // props 只接收 a
console.log(useAttrs()); // 在 js 中使用
</script>
<template>
<h2>Son--{{ b }}--{{ c }}</h2>
<hr />
</template>
<script setup lang="ts">
// 接收父層來的 $attr 仍需要定義 props 來取得
defineProps(["b", "c"]);
</script>
<template>
<h4>Father</h4>
<h5>{{ count }}--{{ car }}</h5>
<Child></Child>
</template>
<script setup lang="ts">
import Child from "./Child.vue";
import { ref, provide } from "vue";
const count = ref(50);
const setCount = (value: number) => (count.value -= value);
const car = ref({ brand: "Benz", price: 70 });
provide("countContext", { count, setCount });
provide("car", car);
</script>
<template>
<h4>Child</h4>
<button @click="setCount(5)">Set Count</button>
<h5>{{ count }}--{{ car?.brand }}--{{ car?.price }}</h5>
</template>
<script setup lang="ts">
import { inject } from "vue";
const { count, setCount } = <
{ count: number; setCount: (value: number) => void }
>inject("countContext");
const car = inject<CarType>("car");
type CarType = { brand: string; price: number };
</script>
// 以下寫法等價
<input type="text" v-model="name" />
<input
type="text"
:value="name"
@input="name = (<HTMLInputElement>$event.target).value"
/>
// 第二個寫法需加上 <HTMLInputElement> 作為 ts 的斷言
// 否則 ts 會顯示 $event 可能為 null 的警告
<template>
<input
type="text"
:value="modelValue"
@input="emit('update:modelValue', (<HTMLInputElement>$event.target).value)"
/>
<input
type="text"
:value="word"
@input="emit('update:word', (<HTMLInputElement>$event.target).value)"
/>
</template>
<script setup lang="ts">
defineProps(["modelValue", "word"]);
// 此處注意 "update:modelValue" 是一個完整個事件名稱,並非拆開來看
const emit = defineEmits(["update:modelValue", "update:word"]);
</script>
<template>
<InputComponent :modelValue="name" @update:modelValue="name = $event" />
<!--簡寫形式-->
<InputComponent v-model="name" v-model:word="word"/>
</template>
<script setup lang="ts">
import InputComponent from "./InputComponent.vue"
import { ref } from "vue";
const name = ref("JJ");
const word = ref("Hello");
</script>
<template>
<div>APP</div>
<Suspense>
<template v-slot:default>
<Child></Child>
</template>
<!--也可直接使用組件標籤即可-->
<!--<Child></Child>-->
// v-slot:fallback 為非同步執行中的區塊
<template v-slot:fallback>
<div>Loading</div>
</template>
</Suspense>
</template>
<script lang="ts" setup>
import { Suspense } from "vue";
import Child from "./Child.vue";
</script>
<template>
<div>Child</div>
</template>
<script setup lang="ts">
import axios from "axios";
const data = await axios.get("https://jsonplaceholder.typicode.com/todos/1");
console.log(data);
</script>