前言:
數據變更之后,vue如何渲染dom?
實際場景:
更新數據之后,再設置滾動條的位置為什么設置無效?
為什么將隱藏的元素設置為顯示狀態之后,讀取元素狀態讀取不到?
改變了對象/數組中的值,頁面沒有更新最新的值?
關於vue中的數據改變沒有觸發視圖更新的現象:
需要知道的一些細節
vue中data中定義的變量,vue才能監聽到其的變化。
vue中無法監聽到對象的屬性的添加、修改和刪除。
vue中對數組,通過下標修改的屬性值無法響應(不能觸發視圖更新)。
˙針對上面的一些解決方案
1、給對象添加屬性,通過$set(obj, propname, propvalue)或Object.assign({},obj,{...})添加
2、對數組中的對象屬性做修改,比如要給一個定義在data中的數組(響應式變量)中的值(一個對象類型的值)添加一個屬性,
直接通過點或[]的方式添加這個屬性,這個屬性值修改之后也可以觸發視圖更新。
3、對於數組,在給數組通過push、shift、splice等方法給數組添加/刪除值,可以觸發視圖更新,但是通過下標方式去給數組添加值,是不能觸發視圖更新的。
還有一種情況:變量是響應式的卻還是沒有觸發視圖更新。因為vue中數據的更新是異步的,如果希望數據變化之后及時更新dom可以放在this.$nextTick()中。
這里舉個數據變化但不觸發視圖更新的一個例子:
組件中之間傳遞值時數據不觸發視圖更新問題
1、限制輸入框字符數的功能,通過:value給表單框初始化值,
<input class="remark-modify" maxlength="32" type="text" :value="username" @blur="saveRemark" @keypress.enter="saveRemark" @keyup="limitLength" autofocus v-else>
2、keyup監聽輸入,當字符串達到32時,將32后的字符串裁剪掉,因為不能直接修改組件中props中的變量,所以只能通過向父組件拋事件或通過sync標識符來修改父組件中變量的值然后再傳到子組件中。子組件中接受了父組件中的變量的值但是卻沒有渲染。
limitLength(e) { const input = e.target; const value = input.value const split = value.split(''); const map = split.map((s, i) => { return (value.charCodeAt(i) >= 0 && value.charCodeAt(i) <= 128) ? 1 : 2; }); let n = 0; const charLength = map.length > 0 && map.reduce((accumulator, currentValue, index) => { const count = accumulator + currentValue; if (count === 31 || count === 32) { n = index; } if (count > 32) { this.$emit('update:username',split.slice(0, n+1).join('') ) this.$emit("setUserName",split.slice(0, n+1).join('')); } return count }); },
這里的沒有渲染和vue中的值修改是異步渲染的有關。
解決方案:
1、input的值通過v-model來綁定值,v-model相當於:value賦值和oninput事件的集合
<input class="remark-modify" maxlength="32" type="text" v-model="name" @blur="saveRemark" @keypress.enter="saveRemark" @keyup="limitLength" autofocus v-else>
2、computed定義name變量,用於在輸入框中顯示內容,通過定義set()和get()方法來修改值和讀取值(props中定義username)
computed: { name: { set(value) { this.$emit("setUserName", value); }, get(value) { return this.username } } },
3、限制字符數的方法里面裁剪內容之后直接將新值賦值給name變量,會觸發name中的set方法
limitLength(e) { const input = e.target; const value = input.value const split = value.split(''); const map = split.map((s, i) => { return (value.charCodeAt(i) >= 0 && value.charCodeAt(i) <= 128) ? 1 : 2; }); let n = 0; const charLength = map.length > 0 && map.reduce((accumulator, currentValue, index) => { const count = accumulator + currentValue; if (count === 31 || count === 32) { n = index; } if (count > 32) { this.name = split.slice(0, n+1).join('') // this.$emit('update:username',split.slice(0, n+1).join('') ) // this.$emit("setUserName",split.slice(0, n+1).join('')); } return count });
vue系列日志中我會總結如下內容:
1、vue中異步渲染數據問題
2、computed定義變量,變量中定義set/get方法和沒有定義的區別
3、vue中的響應式數據機制
4、javascript中的定義對象屬性的Object.definedProperty()