问题出现
需求需要实现一个单选下拉列表,选项在一屏显示不完,做了滚动条overflow:auto
, 设置了height
高度。
那就出现了一个问题,当我点击某一个item选项时,如果这个item选项不在第一屏,而在滚动后才能看到的区域,那么再次点开这个下拉菜单时无法重新定位到被选中的item所在的这一屏,所以我们需要让下拉单选菜单再次打开时自己定位到这一屏。
查阅资料
问了一下同组的有经验的姐姐,说我可以使用window.scroll这些方法,详见
https://developer.mozilla.org/zh-CN/docs/Web/API/Window/scroll
但是这些都需要定位坐标x,y,要么就是距离下拉单选弹框顶部/底部的像素值,我觉得计算的方式都太麻烦了于是继续找方法。
后来查到了这篇文章VUE移动到指定位置(scrollIntoView)这不正是我想要的方法吗!!
应用到我的项目中的大概步骤就是
- 为我的v-for循环出来的每一个item绑定一个唯一的id,可以选择动态绑定
:id = 'id'+item.value
(value值对于每个item是唯一的,所以选用了这个参数做id值) - 在每个item绑定的点击事件函数中,把这个id值传出去,传给父组件(因为这里我的按钮在父组件中,下拉单选弹框单独写了一个子组件)
- 然后在父组件的按钮绑定的事件中,使用documet.getElementById每次获取点击了item之后的某个item的id值,然后使用scrollIntoView函数,让这个item定位在视野屏中。
实现代码
父组件index.vue
<template>
<div class="fixed-icon">
<img v-else :src="..." @click="showPicker(dialogItemID)"/>
</div>
<SelectRouteDialog
id="myDropdown"
:route-select-click="onLiClick"
:route-info="data"
:is-checked="isChecked"
:show-dialog="isShowRouteDropdown"
@closeDialog="isShowRouteDropdown=false"/>
</template>
<script>
export default {
data() {
return {
dialogItemID: '', //从子组件中传过来的元素的id值
}
},
methods:{
/* 按钮绑定的方法 */
showPicker(e) {
this.isShowRouteDropdown = true; //控制对话框显示
document.getElementById(e).scrollIntoView(); // 根据传过来的item的id,滚动到id所在视野中
},
/*每个item绑定的方法
itemId —— 子组件传入的id值 */
onLiClick(selectedVal,itemId){
const valArr = [];
valArr.push(selectedVal);
this.isShowRouteDropdown = false;
this.isChecked = valArr[0];
this.dialogItemID = itemId; // 点击对话框中某个item获取到它的id值存入dialogItemID
// console.log("dialogItemID",this.dialogItemID);
}
}
}
</script>
子组件selectRouteDialog.vue
<template>
<div name="dialog">
<!--就是这里之前用的v-if,导致document.getElementById(e)一直获取不到对象-->
<div v-show="showDialog"
id="dialog-bg"
:data="routeInfo"
:checked="isChecked"
@touchMove.prevent>
<div id="dialog">
<!-- 对话框的头部区域 -->
<div class="dialog-header">
<img :src="..." @click="close" class="dialog-closed">
</div>
<div style="overflow: auto;height: 100%">
<ul>
<li class="liStyle"
v-for="(item,index) in routeInfo"
:key="index"
:checked="isChecked"
@click="routeSelectClick(item.value,'id'+item.value)"
:id="'id'+item.value">
<div class="routeNameStyle">
<div class="textStyle">{{item.text}}</div>
<img v-if="item.value===isChecked" src="~/..." class="nor-active-icon"/>
<img v-else src="~/..." class="nor-active-icon">
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script>
import LANGUAGE from '../../../common/js/language'
export default {
name: "selectRouteDialog",
props:{
showDialog:{
type: Boolean
},
isChecked:{
type: String
},
title:{
type: String
},
message:{
type: String
},
routeInfo: {
type: Array
},
routeSelectClick:{
type: Function
},
},
methods:{
close: function (){
this.$emit("closeDialog")
}
}
}
</script>
过程中出现的问题小记
明明通过父子组件传参,showPicker(e)
能拿到每一个item
的id
。但document.getElementByID(e)
却始终显示对象为null
后来我想着点开这个选择框之后,直接在控制台去看 document.getElementByID(e)
能否拿到某个item
的对象
果然是可以的!就说明这个id
是拿得到的。这个方法也是可行的,就是代码逻辑或许有错。
然后去问同组的姐姐,她说这就说明你的这个组件的dom
没有渲染完的时候,你调用了这个方法,肯定就拿不到。然后让我去判断什么时候整个线路选择组件渲染完了之后,再去获取,就可以了。
我本想问涛哥dom
渲染如何判断彻底渲染完成。涛哥说那就长久的把这个dom
挂载在页面上面就好。
然后瞬间想到了v-show
! 我原本是用的v-if
的
然后改成了v-show
来判断选择框的显示与否之后立马好了!