本文首發於微信公眾號:大遷世界, 我的微信:qq449245884,我會第一時間和你分享前端行業趨勢,學習途徑等等。
更多開源作品請看 GitHub https://github.com/qq449245884/xiaozhi ,包含一線大廠面試完整考點、資料以及我的系列文章。
快來免費體驗ChatGpt plus版本的,我們出的錢
體驗地址:https://chat.waixingyun.cn/#/home
可以加入網站底部技術群,一起找bug.
最近,每當元件的內容(插槽、子元件等)發生變化時,我需要更新它的狀態。對於上下文,它是一個表單元件,用於跟蹤其輸入的有效性狀態。
下面的程式碼片段是以Options
API格式編寫的,但除了指定的地方外可以在Vue2 和 Vue2中使用。
開始
先從控制表單狀態開始,根據狀態修改一個類,孩子內容使用<slot/>
填充:
<template>
<form :class="{ '--invalid': isInvalid }">
<slot />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
};
</script>
為了更新isInvalid
屬性,我們需要新增一個觸發的事件,可以使用 sumit
事件 ,但我更喜用 input
事件。
表單事件7個: focus, blur, input, select, change, reset, submit 等,具體詳解看這篇文章:https://blog.csdn.net/qq_43797996/article/details/103066452
表單不會觸發 input
事件,但我們可以使用 "事件委託"。我們將監聽器附加到父元素(<form>
)上,當事件發生在它的子元素(<input>
、<select>
、<textarea>
等)上時就會被觸發。
任何時候在這個元件的<slot>
中觸發input
事件,表單將捕獲該事件。
<template>
<form :class="{ '--invalid': isInvalid }" @input="validate">
<slot />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
methods: {
validate() {
// 驗證邏輯
}
}
};
</script>
驗證邏輯可以是簡單或複雜的。本文為了演示,用簡單的方法,使用form.checkValidity()
API 來檢視錶單是否基於HTML驗證屬性而有效。
為了訪問<form>
元素。可以用refs
或$el
屬性。為了簡單起見,本文使用$el
。
<template>
<form :class="{ '--invalid': isInvalid }" @input="validate">
<slot />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
methods: {
validate() {
this.isInvalid = !this.$el.checkValidity()
}
}
};
</script>
問題
這裡有一點問題。如果表單的內容改變了,會發生什麼?如果一個<input>
在表單載入被新增到DOM中,會發生什麼?
舉個例子,我們把這個表單元件稱為 "MyForm"
,在 App 中,內容如下:
// App.vue
<template>
<MyForm>
<input
v-model="showInput"
id="toggle-name"
name="toggle-name"
type="checkbox"
/>
<label for="toggle-name">顯示其它 input</label>
<template v-if="showInput">
<label for="name">Name:</label>
<input id="name" name="name" required />
</template>
<button type="submit">提交</button>
</MyForm>
</template>
<script>
import Form from "./components/form.vue";
export default {
name: "App",
components: {
MyForm: Form,
},
data: () => ({
showInput: false,
}),
};
</script>
當App.vue
透過條件來隱藏顯示某些 input
,我們的表單需要知道。在這種情況下,我們會想到在表單內容發生變化時跟蹤其有效性,而不僅僅是在 input
事件或mounted
生命週期鉤子上。否則,可能會顯示不正確的資訊。
熟悉 Vue的生命週期鉤子小夥伴,這裡可能會想到使用 update
來跟蹤變化。理論上,這聽起來不錯。在實踐中,它會創造一個無限的迴圈,然後瀏覽器掛了。
解決方法
經過一番研究和測試,最佳解決方案是使用MutationObserver
API。它是瀏覽器內建的方法,提供了監視對DOM樹所做更改的能力,如果節點的增減、屬性的變動、文字內容的變動,這個 API 都可以得到通知。
它是原生的方法,所以不受限於框架。
使用時,首先使用MutationObserver
建構函式,新建一個觀察器例項,同時指定這個例項的回撥函式。在每次 DOM 變動後呼叫,這個回撥都被呼叫。該回撥函式接受兩個引數,第一個是變動陣列,第二個是觀察器例項,將我們的 form
元件改寫成如下:
<template>
<form :class="{ '--invalid': isInvalid }" @input="validate">
<slot />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
mounted() {
const observer = new MutationObserver(this.validate);
observer.observe(this.$el, {
childList: true,
subtree: true,
});
this.observer = observer;
},
methods: {
validate() {
this.isInvalid = !this.$el.checkValidity();
},
},
beforeUnmount() {
this.observer.disconnect();
},
};
</script>
<style scoped>
</style>
這裡還需要使用 beforeUnmount
生命週期事件來斷開observer
的連線,這會清除它所分配的任何記憶體。
最後,我們將isInvalid
狀態傳遞給要訪問的內容的外掛槽,這也稱作用域的槽,它非常有用。
<template>
<form :class="{ '--invalid': isInvalid }" @input="validate">
<slot v-bind="{ isInvalid }" />
</form>
</template>
<script>
export default {
data: () => ({
isInvalid: false,
}),
mounted() {
const observer = new MutationObserver(this.validate);
observer.observe(this.$el, {
childList: true,
subtree: true,
});
this.observer = observer;
},
methods: {
validate() {
this.isInvalid = !this.$el.checkValidity();
},
},
beforeUnmount() {
this.observer.disconnect();
},
};
</script>
透過這樣的設定,可以在我們的表單元件中新增任意數量的 input
,並新增任何它需要的條件渲染邏輯。只要input
使用HTML驗證屬性,表單就會跟蹤它是否處於有效狀態。
此外,由於使用的是作用域槽,我們將表單的狀態提供給父級,所以父級可以對有效性的變化做出反應。
例如,在 App.vue
,我們想在表單無效時 "禁用" 提交按鈕,可以這麼來寫
<template>
<MyForm>
<template slot:default="form">
<label for="name">Name:</label>
<input id="name" name="name" required>
<button
type="submit"
:class="{ disabled: form.isInvalid }"
>
Submit
</button>
</template>
</MyForm>
</template>
nice~.
希望本文能對你未來的開必有所幫助。
~完,我是小智,準備來場按摩,秀起來!
作者:Dmitri Pavlutin 譯者:前端小智 來源:Dmitri Pavlutin
原文:https://austingil.com/watching-changes-vue-js-component-slot-...
程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug。
交流
有夢想,有乾貨,微信搜尋 【大遷世界】 關注這個在凌晨還在刷碗的刷碗智。
本文 GitHub https://github.com/qq449245884/xiaozhi 已收錄,有一線大廠面試完整考點、資料以及我的系列文章。