-
offsetTop:元素到offsetParent顶部的距离
-
offsetParent:距离元素最近的一个具有定位的祖宗元素(relative,absolute,fixed),若祖宗都不符合条件,offsetParent为body。如下图所示:获取child的offsetTop,图1的offsetParent为father,图2的offsetParent为body。
-
注意:只有元素show(渲染完成)才会计算入offsetTop,若是中间有元素数据需要异步获取,会导致最终获取的offsetTop值偏小
-
offsetTop:获取当前滚动条滚动的距离
tips:一定要在有属性 overflow:auto; 上绑定 ,否则无效
例如:
document.getElementById('testContent')
testContent.addEventListener('scroll', function (e) {
const { scrollTop } = e.target
console.log('scrollTop', parseInt(scrollTop))
})
最终效果
checkList.vue
<template>
<el-dialog
id="check-list"
:visible.sync="show"
height="600px"
width="958px"
:before-close="close"
>
<template slot="title">
<span>检查项设置</span>
</template>
<div class="check-list-body" id="constScroll">
<el-form
:model="ruleForm"
:rules="rules"
ref="ruleForm"
size="small"
label-width="150px">
<div class="label">
<span>a</span>
</div>
<el-row>
<el-checkbox v-model="ruleForm.checked1" true-label="true" false-label="false">a</el-checkbox>
</el-row>
<el-row>
<el-checkbox v-model="ruleForm.checked2" true-label="true" false-label="false">b</el-checkbox>
<el-checkbox v-model="ruleForm.checked3" true-label="true" false-label="false">c</el-checkbox>
</el-row>
<el-row>
<el-checkbox v-model="ruleForm.checked4" true-label="true" false-label="false">d</el-checkbox>
</el-row>
<div v-for="(item,index) in fromItems" :key="item.prop" :id="'leftTop'+ index">
<div class="label">
<span>{{item.label}}</span>
<el-switch
v-model="ruleForm[item.switch]"
active-value="true"
inactive-value="false"
active-color="#13ce66"
inactive-color="#ff4949">
</el-switch>
</div>
<el-form-item
:label="inputItem.label"
prop="name"
v-for="inputItem in item.children"
:key="inputItem.prop">
<el-input
v-model="ruleForm[inputItem.prop]"
style="width:255px;"
placeholder=""
readonly>
</el-input>
</el-form-item>
</div>
</el-form>
<div class="check-list-body-right">
<el-steps direction="vertical" finish-status="" process-status="">
<el-step
v-for="(item,index) in stepData"
:key="index"
@click.native="handleClickStep(index)"
>
<template slot="icon">
<div :class="['step-icon', currentIndex === index ? 'select-style' : 'default-style']"></div>
</template>
<template slot="title">
<span>{{item}}</span>
</template>
</el-step>
</el-steps>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="close">取 消</el-button>
<el-button type="primary" @click="determine">保 存</el-button>
</span>
</el-dialog>
</template>
<script>
import {
RULE_FORM,
FORM_ITEMS,
STEP_DATA
} from './config.js'
export default {
name: 'check-list',
props: {
show: {
type: Boolean,
default: false
}
},
data() {
return {
fromItems: FORM_ITEMS,
ruleForm: RULE_FORM,
stepData: STEP_DATA,
rules: [],
leftTopArr: [],
_scrollTop: 0,
currentIndex: 0,
isClickStep: false
}
},
watch: {
show(newVal) {
this.getScrollTop()
this.getLeftOffSetTop()
}
},
mounted() {
},
methods: {
handleClickStep(index) {
this.currentIndex = index
this.isClickStep = true
// 点击右侧记录一个开关,当同步事件都执行完以后,恢复默认值
setTimeout(() => {
this.isClickStep = false
})
if (!index) {
this.setScrollTop(0)
}
if (this.leftTopArr && this.leftTopArr.length > 0) {
this.setScrollTop(this.leftTopArr[index])
return
}
this.getLeftOffSetTop()
this.setScrollTop(this.leftTopArr[index])
},
handleScrollTop() {
if (this.leftTopArr && this.leftTopArr.length > 0) {
for (let i = 0; i < this.leftTopArr.length; i ++) {
const start = this.leftTopArr[i],
end = this.leftTopArr[i + 1]
if (this._scrollTop >= start && this._scrollTop <= end) {
this.currentIndex = i
return
}
}
return
}
},
determine() {
this.$emit('close')
this.isClickStep = false
},
close() {
this.$emit('close')
this.isClickStep = false
},
//设置窗口滚动条高度
setScrollTop(top){
if(!isNaN(top)) {
document.getElementById('constScroll').scrollTop = top
}
},
//获取系统参数内滚动高度
getScrollTop(){
this.$nextTick(() => {
const testContentDom = document.getElementById('constScroll')
testContentDom.addEventListener('scroll', (e) => {
//点点击右侧时不触发滚动条事件
if (!this.isClickStep) {
const { scrollTop } = e.target
this._scrollTop = parseInt(scrollTop)
this.handleScrollTop()
}
})
})
},
// 获取左侧每个div具体头部的高度
getLeftOffSetTop(){
this.$nextTick(() => {
this.leftTopArr = [0]
for(let index in this.fromItems) {
const leftDoM = document.getElementById('leftTop'+ index)
let offsetTopHeight = +(leftDoM.offsetTop) - 62 // 62高度是减去的表头
this.leftTopArr.push(offsetTopHeight)
}
})
}
},
destroyed() {
// this.$nextTick(() => {
// const testContent = document.getElementById('constScroll')
// testContent && testContent.removeEventListener('scroll')
// })
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus">
#check-list{
.el-dialog{
height: 600px;
overflow: hidden;
margin-top:unset;
.el-dialog__header{
text-align: left;
}
.el-dialog__body{
overflow: hidden;
height: calc(100% - 116px);
padding: 10px 0 10px 20px;
}
.el-dialog__footer{
border-top: 2px solid #f6f6f6;
}
}
.check-list-body{
display: flex;
height: 100%;
overflow: auto;
.label{
margin-bottom: 15px;
span{
margin-right: 10px;
}
}
&-right{
height: 300px;
position: absolute;
right: 100px;
width: 130px;
overflow: hidden;
.step-icon{
width: 10px;
height:10px;
border-radius:50%;
}
.default-style{
background-color:#C0C4CC;
}
.select-style{
width: 20px;
height: 20px;
border-radius:50%;
background-color:#409eff;
}
.el-step__icon{
height: 10px;
}
.el-step__line{
height: 60px;
}
.el-step.is-vertical{
align-items: center;
}
.el-step__icon.is-text{
border: 0;
border-color: #FFF;
border-radius: 50%;
}
}
}
}
</style>
config.js
export const RULE_FORM = {
checked1: 'false',
checked2: 'false',
checked3: 'false',
checked4: 'false',
checked5: 'false',
checked6: 'false',
switch1: 'false',
subjectName1: '',
subjectName2: '',
subjectName3: '',
subjectCode1: '',
subjectCode2: '',
}
export const FORM_ITEMS = [
{
label: 'b',
switch: 'switch1',
children: [
{
prop: 'subjectName1',
code: 'subjectCode1',
label: 'b1'
},
{
prop: 'subjectName2',
code: 'subjectCode2',
label: 'b2'
}
]
},
{
label: 'c',
switch: 'switch1',
children: [
{
prop: 'subjectName1',
code: 'subjectCode1',
label: 'c1',
isSelect: true
},
{
prop: 'subjectName2',
code: 'subjectCode2',
label: 'c2'
},
{
prop: 'subjectName3',
code: 'subjectCode3',
label: 'c3',
isSelect: true
}
]
},
{
label: 'd',
switch: 'switch1',
children: [
{
prop: 'subjectName1',
code: 'subjectCode1',
label: 'd1'
}
]
},
{
label: 'e',
switch: 'switch1',
children: [
{
prop: 'subjectName1',
code: 'subjectCode1',
label: 'e1'
},
{
prop: 'subjectName2',
code: 'subjectCode2',
label: 'e2'
},
{
prop: 'subjectName3',
code: 'subjectCode3',
label: 'e3'
},
{
prop: 'subjectName4',
code: 'subjectCode4',
label: 'e4'
}
]
},
{
label: 'f',
switch: 'switch1',
children: [
{
prop: 'subjectName1',
code: 'subjectCode1',
label: 'f1',
isSelect: true
},
{
prop: 'subjectName2',
code: 'subjectCode2',
label: 'f2'
},
{
prop: 'subjectName2',
code: 'subjectCode2',
label: 'f3'
}
]
},
{
label: 'g',
switch: 'switch1',
children: [
{
prop: 'subjectName1',
code: 'subjectCode1',
label: 'g1'
},
{
prop: 'subjectName2',
code: 'subjectCode2',
label: 'g2'
}
]
}
]
export const STEP_DATA = [
'a',
'b',
'c',
'd',
'e',
'f',
'g'
]