Skip to content

Commit

Permalink
13-Watchers-opAPI : basic 、 deep 、 flush post 、 stop watch 、 one eage…
Browse files Browse the repository at this point in the history
…r dot
  • Loading branch information
leo41271 committed Jul 18, 2024
1 parent d8c4ea4 commit 74cec6f
Show file tree
Hide file tree
Showing 11 changed files with 354 additions and 3 deletions.
6 changes: 3 additions & 3 deletions Vue3-Official-Doc-Learn/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<script setup></script>
<script>
import eventHandling from "@/pages/op-doc/App-event-handling.vue"
import watcher from "@/pages/op-doc/App-watcher.vue"
export default {
data() {
return {
}
},
components: {
eventHandling
watcher
}
}
</script>
<template>
<eventHandling></eventHandling>
<watcher></watcher>
</template>
<style scoped></style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script>// Watch-Basic.vue
export default {
data() {
return {
question: '',
answer: 'Questions usually contain a question mark. ;-)',
loading: false,
}
},
watch: {
question(newQuestion, oldQuestion) {
console.log("new ", newQuestion, "old ", oldQuestion)
if (newQuestion.includes('?')) { this.getAnswer() }
}
},
methods: {
async getAnswer() {
this.loading = true
this.answer = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
this.answer = (await res.json()).answer
}
catch (error) { this.answer = 'Error! Could not reach the API. ' + error }
finally { this.loading = false }
}
}
}
</script>
<template>
檢查包含 ? 字元 <input v-model="question" :disabled="loading" />
<p>{{ answer }}</p>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template><!-- Watch-Deep.vue -->
deepData.user.age<input type="number" v-model="deepData.user.age"><br>
deepData.user.name<input type="text" v-model="deepData.user.name"><br>
deepData.details.email<input type="email" v-model="deepData.details.email"><br>
deepData.details.address<input type="address" v-model="deepData.details.address">
<br> <br>
noDeepData.user.age<input type="number" v-model="noDeepData.user.age"><br>
noDeepData.user.name<input type="text" v-model="noDeepData.user.name"><br>
noDeepData.details.email<input type="email" v-model="noDeepData.details.email"><br>
noDeepData.details.address<input type="address" v-model="noDeepData.details.address"><br>
</template>
<script>
export default {
data() {
return {
deepData: {
user: { name: '深入監聽', age: 100 },
details: { email: 'deep@data.com', address: '看內層 資源消耗大' }
},
noDeepData: {
user: { name: '無深入監聽', age: 10 },
details: { email: 'noDeep@data.com', address: '只看當前被監聽之屬性內層不看' }
}
};
},
watch: {
deepData: {
handler(newValue, oldValue) {
console.log('新值:', newValue);
console.log('舊值:', oldValue);
},
deep: true // 啟用深度監視器
},
noDeepData(newValue, oldValue) {
console.log('noDeepData新值:', newValue);
console.log('noDeepData舊值:', oldValue);
}
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<template><!-- Watch-Dot.vue -->
<input type="text" v-model="userInfo.name">
<input type="number" v-model="userInfo.age">
</template>
<script>
export default {
data() {
return {
userInfo: { name: 'John', age: 25 }
}
},
computed: {
fullName() {
console.log("computed", this.userInfo.name)
return this.userInfo.name;
}
},
watch: {
fullName(newValue, oldValue) {
console.log('New name:', newValue);
},// Note: only simple paths. Expressions are not supported.
'userInfo.age'(newValue, oldValue) {
if (newValue > 18) { alert('You are an adult!'); }
}
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<template><!-- Watch-Eager.vue -->
<!-- 首次数据初始化,并不会触发watch -->
watch 預設是 lazy (資料有變動才會呼叫)<br>
部分狀況如 拿取(fetch)初始資料 ,而相關資料又變動時再拿取一次。 <br>
eager後: {{ eagerData }} <br> 沒eager前長這樣: {{ eagerOri }} <br>
一般後: {{ data }} <br> 一般沒eager前長這樣: {{ dataOri }}
</template>
<script>
export default {
data() {
return {
eagerData: "eager初始資料",
eagerOri: "eager初始資料 ",
data: "一般監聽原始",
dataOri: "一般監聽原始",
};
},
watch: {
eagerData: {
// handler 執行時 在 create hook 之前
handler(newValue, oldValue) {
if (this.eagerData === "eager初始資料") {
this.eagerData = "eager 觸發";// 代替re-fetch 一次
}
},
immediate: true // 啟用 Eager Watcher,立即觸發回調函數
},
data(newV, oldV) {
if (this.data === "一般監聽原始") { this.data = "一般的有變動到 實際不會" }
}
},
mounted() { console.log('mounted 的console', this.eagerData); }
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template><!-- Watch-Flush-Post.vue -->
<!-- Callback Flush Timing <br>
預設情況下,偵聽器回呼會在父元件更新 (如有) 之後、所屬元件的 DOM 更新之前被調用,<br>
在偵聽器回呼中存取所屬元件的 DOM,那麼 DOM 將處於更新前的狀態。<br>
Post Watchers: 取得更新後的。<br> -->
<p>Counter: {{ counter1 }} noPost</p>
<span>Counter: {{ counter2 }} post</span>
<button @click="increment">Increment</button>
</template>
<script>
export default {
data() {
return {
counter1: 0,
counter2: 0
};
},
methods: {
increment() {
this.counter1++;
this.counter2++;
}
},
watch: {
counter1(newValue, oldValue) {
console.log('Watcher triggered:', newValue);
console.log('DOM updated:', document.querySelector('p').textContent);
},
counter2: {
handler(newValue, oldValue) {
console.log('Watcher triggered (flush: post):', newValue);
console.log('DOM updated (flush: post):', document.querySelector('span').textContent);
},
flush: 'post', // 使用 'post' 選項,確保在 Vue 更新 DOM 後才觸發 watcher 回調
}
}
};
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<template><!-- Watch-Flush-Sync.vue -->
<input type="text" v-model="message" placeholder="輸入訊息">
訊息: {{ message }}
</template>
<script>
export default {
data() {
return { message: '111', count: 0 };
},
created() {
// 在同一个事件循环中VUE会在最后才用data数据刷新DOM
this.message += 1;
this.message += 1;
this.message += 1;
},
watch: {
message: {
handler(newValue, oldValue) {
this.count++;
console.log(this.count, ' new :', newValue);
},
flush: 'sync', // 同時我們也知道在VUE中DOM的更新渲染是異步的 透過改成同步 count 能符合預期顯示3次。 建議只觀察布林值
// https://juejin.cn/post/7095271649573863437
}
}
};
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template><!-- Watch-One.vue -->
3.4 版本以上才有
<input type="text" v-model="data">
{{ checkOne }}
</template>
<script>
export default {
data() {
return {
data: "data ",
checkOne: "data change",
}
},
watch: {
data: {
handler(newValue, oldValue) {
// when `source` changes, triggers only once
this.checkOne = newValue;
},
once: true
}
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<template><!-- Watch-Stop-Choose.vue -->
<div>
結論 使用 Option API 定義的監聽器沒有直接的方法可以手動停止。這是因為在 Option API 中,監聽器是通過 watch 選項來定義的,而這些監聽器不會返回一個可以用來停止它們的函數。<br>
data<input type="text" v-model="data" placeholder="輸入data訊息"> <br>
torch<input type="text" v-model="torch" placeholder="輸入torch訊息"><br>
message<input type="text" v-model="message" placeholder="輸入message訊息"><br>
<button @click="stopWatchers(kill)">停止 watcher</button>
<select v-model="kill" id="killName">
<option value="data">砍掉data監聽器</option>
<option value="torch">砍掉torch監聽器</option>
<option value="message">砍掉message監聽器</option>
<option value="all">砍掉all</option>
</select>
看似有砍掉實則只是沒動作 因為沒方法可執行
<br>
</div>
</template>
<script>
export default {
data() {
return {
message: '123',
data: "一二三",
torch: "火炬",
kill: "",
};
},
watch: {
message(newV, oldV) { console.log("message new ", newV, "old", oldV); },
data(newV, oldV) { console.log("data new ", newV, "old", oldV); },
torch(newV, oldV) { console.log("torch new ", newV, "old", oldV); },
$options(newV, oldV) { console.log("$options new ", newV, "old", oldV); },
},
methods: {
stopWatchers(killWatch) {
const watchers = this.$options.watch;
console.log(watchers, killWatch); // 有取得到 三個監聽器
// 判断是否需要停止所有观察者
console.log(watchers[killWatch]) // 等同 watchers.data 。尤其內容看與正統stop console比較內容 應該是無法stop 因為沒有定義如何停止
const unwatch = watchers[killWatch];
console.log(unwatch()); // undefined 表示沒有這個可以取消的方法
// how to stop watcher without unwatch() in vue
if (killWatch === 'all') { Object.keys(watchers).forEach(prop => { }); }
else {
if (watchers[killWatch]) { }
else { console.log("找不到" + killWatch + "的观察者"); }
}
}
}
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template><!-- Watch-Stop.vue -->
<input v-model="data" placeholder="输入一些内容" />
<p>data : {{ data }}</p>
<button @click="stopWatcher">stop Watch</button>
</template>
<script>
export default {
data() {
return { data: '' };
},
created() {
// 創建一個觀察者
this.unwatch = this.$watch('data', this.handleFooChange);
},
methods: {
handleFooChange(newValue, oldValue) {
console.log(oldValue, '=>', newValue);
},
stopWatcher() {
// console.log(this.unwatch()); // 這樣也會殺掉 監聽
this.unwatch(); // 或是在最後生命週期 鉤子 方法 時給去掉 unmounted 之類 (組件卸载時)
},
},
unmounted() {
this.unwatch(); // 最好是在組件卸载時 // 清除掉防抖計時器
},
};
</script>
49 changes: 49 additions & 0 deletions Vue3-Official-Doc-Learn/src/pages/op-doc/App-watcher.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script>
import WatchBasic from '@/components/op-doc/watchers-docs/Watch-Basic.vue'
import WatchDot from '@/components/op-doc/watchers-docs/Watch-Dot.vue'
import WatchDeep from '@/components/op-doc/watchers-docs/Watch-Deep.vue'
import WacthEager from '@/components/op-doc/watchers-docs/Watch-Eager.vue'
import WatchOne from '@/components/op-doc/watchers-docs/Watch-One.vue'
import WatchPost from '@/components/op-doc/watchers-docs/Watch-Flush-Post.vue';
import WatchSync from '@/components/op-doc/watchers-docs/Watch-Flush-Sync.vue'
import WatchKill from '@/components/op-doc/watchers-docs/Watch-Stop.vue'
import WatchKill2 from '@/components/op-doc/watchers-docs/Watch-Stop-Choose.vue';
export default {
components: { WatchBasic, WatchDot, WatchDeep, WacthEager, WatchOne, WatchPost, WatchSync, WatchKill, WatchKill2 },
}
</script>
<template>
Watch <br>
<WatchBasic></WatchBasic>
<hr>
<WatchDot></WatchDot>
<hr>
<WatchDeep></WatchDeep>
<hr>
<WacthEager></WacthEager>
<hr>
<WatchOne></WatchOne>
<hr>
<WatchPost></WatchPost>
<hr>
<WatchSync></WatchSync>
<hr>
<WatchKill></WatchKill>
<hr>
<WatchKill2></WatchKill2>
https://michaelnthiessen.com/difference-between-computed-property-and-watcher <br>
計算較有聲明性
Computed props are more declarative than watched properties<br>
計算 較純粹:回傳值 同步 無副作用(如異步請求 更改DOM)
Computed props should be pure: return a value, synchronous, and have no side-effects<br>
計算確實產生(屬性)監聽則指呼叫函式
Computed props create new reactive properties, watched props only call functions<br>
計算可受多屬性影像(多對一)監聽可影響多屬性(一對多)
Computed props can react to changes in multiple props, whereas watched props can only watch one at a time<br>
經過計算得到的屬性值,它們會被緩存 只在需要時才會被重新計算,監聽屬性發生改變時立即執行相應的函數
Computed props are cached, so they only recalculate when things change. Watched props are executed every time<br>
同上Computed props are evaluated lazily, meaning they are only executed when they are needed to be used. Watched props
are executed whenever a prop changes<br><br>
Watch is for side effects. If you need to change state you want to use a computed prop instead.<br>
Most of the time you'll want a computed prop, so try to use that first.<br>
</template>

0 comments on commit 74cec6f

Please sign in to comment.