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)人名;(德)拉齐