1、背景
最近項目有個需求,需要使用vant的picker選擇器,並且搭配彈出層使用,並且picker的數據是異步獲取的,但是在測試的過程中,數據已經正確獲取到,頁面也實現了響應式,但是picker選擇器的數據卻沒有更新,這是為什么呢???
- 代碼:
- html
<van-popup position="bottom" v-model:show="showPicker"> <!-- loading:是否顯示加載狀態,默認為false columns:對象數組,配置每一列顯示的數據 value-key已經棄用,所以需要columns-field-names自定義 Columns 的結構 show-toolbar:是否顯示頂部欄,默認為true confirm:點擊完成按鈕時觸發 cancel:點擊取消按鈕時觸發 --> {{ sourceData }} <van-picker default-index="0" :loading="loading" :columns="sourceData" :columns-field-names="customFieldName" show-toolbar @confirm="onConfirm" @cancel="onCancel" /> </van-popup>
- js:
let res = await initSelectData({ data: {}, method: 'GET', url: codeId }); // sourceData = res.data; //直接賦值丟失了響應性 res.data ? res.data.forEach(el => { sourceData.push(el); }) : '';
- html
- 加載數據的現象:
- 加載數據成功后的現象:
2、分析
官網地址:https://vant-contrib.gitee.io/vant/v3/#/zh-CN/picker
剛開始的時候我認為是vue的響應式數據問題引起的,后來在popup中打印了數據源sourceData之后,發現頁面的數據已經響應式更新了,但是picker中的下拉選項數據卻並沒有發生變化,所以接下來我查閱了一下vant-picker的官方文檔,發現picker實例上有一個方法 setColumnValues 可以設置對應列中所有的選項,所以我給picker設置了一個ref
- html
<van-picker default-index="0" ref="picker" :loading="loading" :columns="sourceData" :columns-field-names="customFieldName" show-toolbar @confirm="onConfirm" @cancel="onCancel" />
- js
/** * @description: onMounted 可以用來加載頁面的初始化數據 * @author: wangxinghua1 */ onMounted(async () => { console.log(picker.value, '.....'); });
- 問題:在onMounted中的結果為:null '.....'。 這就導致頁面加載選擇器數據的時候,沒有辦法獲取到實例,而導致調用 setColumnValues 報錯,這是因為popup彈層在打開前並沒有提前渲染到頁面上(dom加載時並沒加載popup),所以導致ref獲取不到它里面的picker選擇器,解決方法:
<van-popup :lazy-render="false" />
- 最終結果是
- html
<!-- lazy-render:是否在顯示彈層時才渲染節點,默認為true,防止popup彈出層 在打開前並沒有提前渲染到頁面上(dom加載時並沒加載popup), 所以導致ref獲取不到它里面的picker選擇器(picker.value), 從而使得picker.value.setColumnValues報錯 --> <van-popup :lazy-render="false" position="bottom" v-model:show="showPicker"> <!-- loading:是否顯示加載狀態,默認為false columns:對象數組,配置每一列顯示的數據 value-key已經棄用,所以需要columns-field-names自定義 Columns 的結構 show-toolbar:是否顯示頂部欄,默認為true confirm:點擊完成按鈕時觸發 cancel:點擊取消按鈕時觸發 --> {{ sourceData }} <van-picker default-index="0" ref="picker" :loading="loading" :columns="sourceData" :columns-field-names="customFieldName" show-toolbar @confirm="onConfirm" @cancel="onCancel" /> </van-popup>
- js
// 定義是否顯示彈出層 let showPicker = ref(false); // 定義選擇器的數據 let sourceData = reactive([]); // 選擇器數據是異步獲取的,可以通過 loading 屬性顯示加載提示 let loading = ref(false); // 獲取picher的dom節點,即picker的實例 let picker = ref(null); /** * @description: onMounted 可以用來加載頁面的初始化數據 * @author: wangxinghua1 */ onMounted(async () => { // 當選擇器的數據來源於后端時,判斷是否有請求地址,進行初始化數據 if (codeId) { loading.value = true; await loadData(); } }); /** * @description: loadData 獲取select的數據 * @author: wangxinghua1 */ const loadData = async () => { try { let res = await initSelectData({ data: {}, method: 'GET', url: codeId }); // sourceData = res.data; //直接賦值丟失了響應性 res.data ? res.data.forEach(el => { sourceData.push(el); }) : ''; res.data ? (loading.value = false) : (loading.value = false); console.log('9999999', picker.value); picker.value.setColumnValues(0, sourceData); console.log('initSelectData', res, sourceData); } catch (e) { console.log('select-loaddata', e.errmsg); } };
- html
3、vue3使用ref的步驟
- 給元素添加ref屬性<div ref="box"></div>
- 在setup函數中,可以使用ref函數,用於創建一個響應式數據const box = ref(null)
- 在setup函數中,使用return返回box數據
- 在onMounted函數里面訪問
基本翻譯
adj. 懶惰的;懶洋洋的;怠惰的;慢吞吞的
n. (Lazy)人名;(德)拉齊