有个需求,是用vant的picker选择器组件来代替输入框,用于设置每个人的得分。
但是每个项得分都不同,有的满分10分,有的满分是30分,因此就需要为picker选择器来动态改变可选择的范围。
<!-- 分数选择弹窗 --> <van-popup v-model="showScore" position="bottom" :lazy-render='false'> <van-picker show-toolbar title="分数选择" :columns="scoreColumns" @cancel="showScore = false" /> </van-popup>
data() { return { showScore: false, scoreColumns: [ { values: [], // 需要动态设置整数的列 defaultIndex: 0 }, { values: ['.'], defaultIndex: 0 }, { values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], defaultIndex: 0 }, { values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], defaultIndex: 0 } ] } }, methods: { showScorePopup() { // 代码仅为展示用,已省略部分代码。下方变量maxScore是动态获取来的的最大值,可能是10也可能是30 this.scoreColumns[0].values = []; // 先清空后赋值 for(let i = maxScore; i >= 0; i --) { // 将所有分数遍历后添加进picker的第一列,例如:[30, 29, 28, ... , 2, 1, 0] this.scoreColumns[0].values.push(i); } this.showScore = true; // 显示分数选择弹窗 } }
修改picker的columns参数不会更新视图
起先是直接修改scoreColumns[0]里面的values(写法如上方展示),values确实修改成了新的数组,但是选择器中的选项并没有发生变化。
所以第一反应就觉得是更新视图的锅,所以使用了Vue提供的Api,Vue.$set,结果依旧是修改成了数据,选项却没更新。
接下来查阅了Vant官方文档,发现有一个picker.setColumnValues,这个picker很明显是获取到这个选择器实例,但是这个picker又是van-picker组件上的@change事件才有的参数,在其他事件中也没有这个参数。
而setColumnValues方法就是设置选择器指定列的选项。
在没办法获取到这个选择器的时候,我突然在文档中发现了一句被我忽略掉的话:
使用ref来获取picker组件
<van-picker ref="scoreSelect" />
console.log(this.$refs.scoreSelect);
如上所示,首先为picker组件添加一个ref的属性,然后在方法中使用this.$refs调用它。
但是,你会发现,控制台毫不留情输出了一个undefined,这是获取到了一个寂寞???
解决在popup中使用ref获取不到picker组件
popup弹层在打开前并没有提前渲染到页面上(dom加载时并没加载popup),所以导致ref获取不到它里面的picker选择器。
解决方法其实就是在popup组件上加个lazy-render参数,这样就可以使用$refs来获取了。
<van-popup :lazy-render="false" />
因此我将文中开头的showScorePopup方法改成了这样…
// 实例方法scoreSelect接收两个参数,(columnIndex, values),第一个参数是选择器需要修改的列的index,第二个参数是需要修改成的值 showScorePopup() { // 代码仅为展示用,已省略部分代码。下方变量maxScore是动态获取来的的最大值,可能是10也可能是30 // this.scoreColumns[0].values = []; let numArr = []; for(let i = maxScore; i >= 0; i --) { // this.scoreColumns[0].values.push(i); numArr.push(i); } // this.$refs.scoreSelect.setColumnValues(0, this.scoreColumns[0].values); this.$refs.scoreSelect.setColumnValues(0, numArr); this.showScore = true; // 显示分数选择弹窗 }