开发背景
在智能巡检项目开发中,资产类型的展示为目前未封装过的组件,需要自己进行开发。
需求
主要思路
- 使用el-radio-group组件,实现主要数据渲染
- 宽度不够时,显示左右滑动按钮(需要监听容器大小)
- 使用绝对定位功能,实现左右滑动逻辑
代码实现
<template>
<div
class="property-type-list"
id="property-type-list-eque"
>
<div class="property-type-list-wrapper">
<el-button
icon="h-icon-angle_left"
:disabled="leftBtnDisable"
class="h-btn left-btn"
@click="handleMoveFn('left')"
v-if="moveBtnShow"
>
</el-button>
<div
class="camera-list"
id="camera-list"
>
<el-radio-group
class="checkboxgroup"
id="checkboxgroup"
v-model="checkedChannel"
:gutter="8"
>
<el-radio-button
class="camera-item"
v-for="(item) in channelList"
:key="item.AssetClassName+'-'+item.AssetClassID"
:label="item.AssetClassID"
:max-width="200"
:title="item.AssetClassName"
>{{ item.AssetClassName }}
</el-radio-button>
</el-radio-group>
</div>
<el-button
icon="h-icon-angle_right"
class="h-btn right-btn"
:disabled="rightBtnDisable"
@click="handleMoveFn('right')"
v-if="moveBtnShow"
>
</el-button>
</div>
</div>
</template>
<script>
import eventBus from '@/Common/service/event/eventBus.js';
let that = null;
function debounce(fn, duration = 100) {
let timer = null;
return (...arg) => {
clearTimeout(timer);
timer = setTimeout(() => {
fn(...arg);
}, duration);
};
}
export default {
name: '',
components: {},
props: {
assetClassList: {
type: Array,
default: () => {
return [];
}
}
},
data() {
return {
leftBtnDisable: true,
rightBtnDisable: true,
moveBtnShow: false,
checkedChannel: '',
channelList: [],
windowWidth: document.body.clientWidth,
isFinish: true
};
},
computed: {},
watch: {
assetClassList: {
handler(val) {
this.channelList = JSON.parse(JSON.stringify(val));
this.channelList.unshift(
{
AssetClassName: this.$t('hcp_inspection_all_name'),
AssetClassID: ''
}
);
},
deep: true,
immediate: true
},
checkedChannel(val) {
this.checkedChannelUpdate(val);
},
windowWidth() {
this.checkPage();
},
channelList: {
handler() {
this.$nextTick(()=>{
this.checkPage();
});
},
deep: true
}
},
mounted() {
eventBus.$emit('assetClassChange-inspection', '');
eventBus.$on('assetClassCheck-inspection', this.checkedChannelUpdate);
that = this;
window.onresize = () => {
return (() => {
this.windowWidth = document.documentElement.clientWidth; // 宽
})();
};
},
beforeDestroy() {
window.onresize = null;
eventBus.$off('assetClassCheck-inspection');
},
methods: {
checkedChannelUpdate(val) {
if (val) {
let item = this.channelList.find(item => item.AssetClassID === val);
if (item) {
// 如果是新增,并且一行显示补下,行业栏自动移动到最后
if (val === this.channelList[this.channelList.length - 1].AssetClassID) {
this.checkedChannel = val;
this.$nextTick(()=>{
this.moveLast();
});
} else {
this.checkedChannel = this.checkedChannel || val;
}
return eventBus.$emit('assetClassChange-inspection', item);
}
}
this.checkedChannel = '';
eventBus.$emit('assetClassChange-inspection', '');
},
moveLast() {
if (!this.moveBtnShow || !this.isFinish) {
return;
}
this.isFinish = false;
let boxLong = document.getElementById('camera-list').offsetWidth;
let element = document.getElementById('checkboxgroup');
let channelLong = element.offsetWidth;
let left = Number(element.style.left.split('px')[0]);
let needMove = channelLong - Math.abs(left) - boxLong + 2;
this.timer = setInterval(() => {
if (needMove < 50) {
left = left - needMove;
} else {
left = left - 50;
}
element.style.left = left === 0 ? '1px' : left + 'px';
needMove = needMove - 50;
if (needMove <= 0) {
this.isFinish = true;
clearInterval(this.timer);
this.isFinish = true;
if (Math.abs(left) + boxLong === channelLong) {
this.rightBtnDisable = true;
} else {
this.rightBtnDisable = false;
}
if (Math.abs(left) > 0) {
this.leftBtnDisable = false;
} else {
this.leftBtnDisable = true;
}
}
}, 1);
},
// 检测是否显示分页按钮
checkPage() {
if (!document.getElementById('camera-list') || !document.getElementById('checkboxgroup')) {
return;
}
// let channelLong = this.channelList.length * 128 - 8;
let boxLong = document.getElementById('camera-list').offsetWidth;
let element = document.getElementById('checkboxgroup');
let channelLong = element.offsetWidth;
let left = Number(element.style.left.split('px')[0]);
if (boxLong < channelLong) {
this.moveBtnShow = true;
} else {
element.style.left = '1px';
this.moveBtnShow = false;
}
if (left < 0 && (Math.abs(left) + boxLong === channelLong)) {
this.rightBtnDisable = true;
} else {
this.rightBtnDisable = false;
}
if (left < 0) {
this.leftBtnDisable = false;
} else {
this.leftBtnDisable = true;
}
},
handleMoveFn: debounce((direction) => {
that.handleMove(direction);
}, 100),
// 移动通道
handleMove(direction) {
let element = document.getElementById('checkboxgroup');
let channelLong = element.offsetWidth;
let left = Number(element.style.left.split('px')[0]);
// let channelLong = this.channelList.length * 128 - 8;
let boxLong = document.getElementById('camera-list').offsetWidth;
if (direction === 'right') {
if (!this.isFinish) {
return;
}
this.isFinish = false;
let needMove = boxLong;
if (channelLong - Math.abs(left) - boxLong < boxLong) {
needMove = channelLong - Math.abs(left) - boxLong + 2;
}
this.timer = setInterval(() => {
if (needMove < 10) {
left = left - needMove;
} else {
left = left - 10;
}
element.style.left = left === 0 ? '1px' : left + 'px';
needMove = needMove - 10;
if (needMove <= 0) {
clearInterval(this.timer);
this.isFinish = true;
if (Math.abs(left) + boxLong === channelLong) {
this.rightBtnDisable = true;
} else {
this.rightBtnDisable = false;
}
if (Math.abs(left) > 0) {
this.leftBtnDisable = false;
} else {
this.leftBtnDisable = true;
}
}
}, 1);
} else {
if (!this.isFinish) {
return;
}
this.isFinish = false;
let needMove = boxLong;
if (Math.abs(left) < boxLong) {
needMove = Math.abs(left);
}
this.timer = setInterval(() => {
if (needMove < 10) {
left = left + needMove;
} else {
left = left + 10;
}
element.style.left = left === 0 ? '1px' : left + 'px';
needMove = needMove - 10;
if (needMove <= 0) {
clearInterval(this.timer);
this.isFinish = true;
if (Math.abs(left) >= channelLong) {
this.rightBtnDisable = true;
} else {
this.rightBtnDisable = false;
}
if (left < 0) {
this.leftBtnDisable = false;
} else {
this.leftBtnDisable = true;
}
}
}, 1);
}
}
}
};
</script>
<style lang='less'>
@theme-color: #f00;
.property-type-list {
.camera-list {
flex: 1;
width: 10px;
height: 32px;
overflow: hidden;
position: relative;
.checkboxgroup {
top: 0;
left: 1px;
display: flex;
flex-flow: row nowrap;
position: absolute;
}
}
}
</style>
<style lang='less' scoped>
.property-type-list {
width: 100%;
height: 100%;
.property-type-list-wrapper {
width: 100%;
height: 32px;
display: flex;
align-items: center;
.h-btn.left-btn,.h-btn.right-btn{
flex-shrink: 0;
min-width: 24px;
max-width: 24px;
}
.right-btn{
margin-left: 10px;
border: none;
}
.left-btn{
margin-right: 10px;
border: none;
}
}
}
</style>