一个step组件
问题描述
开发一个step组件,发现当页面放缩后step的步骤之间间隙变大,不能自动伸缩,于是想到监听元素宽度变化,重新设置step的宽度。
解决方法
- 使用
element-resize-detector
// 首先安装 `element-resize-detector`
// 引入
const Detector = require('element-resize-detector')
// 使用
mounted () {
this.handleStep()
},
methods: {
// 监听step元素宽度变化
handleStep() {
let vm = this
let detector = Detector()
detector.listenTo(document.querySelector('.j-steps'), el => {
vm.$nextTick(() => {
vm.stepWidth = el.offsetWidth / this.curSteps.length + 'px'
})
})
},
}
- 衍生问题--无法触发以下css发生变化
li:not(:first-child) {}
li:first-child {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
.left-arrow {
display: none;
}
}
li:last-child {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
.right-arrow {
display: none;
}
}
- 使用指令监听
directives:{
resize: { // 指令的名称
bind(el, binding) { // el为绑定的元素,binding为绑定给指令的对象
console.log(el,"绑定",binding);
let width = '', height = '';
function isReize() {
const style = document.defaultView.getComputedStyle(el);
if (width !== style.width || height !== style.height) {
binding.value({width:style.width,height:style.height}); // 关键(这传入的是函数,所以执行此函数)
}
width = style.width;
height = style.height;
}
el.__vueSetInterval__ = setInterval(isReize, 300);
},
unbind(el) {
console.log(el,"解绑");
clearInterval(el.__vueSetInterval__);
}
}
},
<div id="Chart1" v-resize="domResize"></div>
domResize(data){
let {width, height} = data; // 这里返回的宽高都是带单位的
console.log("width:",width,"height:",height," dom尺寸方式改变");
},
- 这个方法是可行的。
最终解决方法
最终发现使用flex布局后,如果盒子内部的元素宽度足够大且相等,就能实现实时等分布局,于是直接设置每一个盒子内的 元素长度为1000px
解决了[ganga]。
step组件
<template>
<ul class="j-steps" ref="stepRef">
<li class="step"
:class="[index <= curVal?'isActive':'']"
:style="{width: '1000px'}"
v-for="(item, index) in curSteps"
:key="item">
<div class="right-arrow"></div>
<div class="left-arrow"></div>
<span class="cur-step" v-html="index<curVal?'✓':index+1"></span>
<span class="step-info">{{ item }}</span>
</li>
</ul>
</template>
<script>
export default {
name: 'Step',
props: {
value: {
type: [String, Number],
default: ''
},
steps: {
type: Array,
default: () => {
return []
}
}
},
watch: {
value(val) {
this.curVal = val
},
steps(val) {
this.curSteps = val
}
},
data() {
return {
curVal: this.value,
curSteps: this.steps,
stepWidth: 0
}
}
}
</script>
<style lang="scss">
@mixin j-step-arrow {
content: '';
width: 0;
height: 0;
border-top: 24px solid transparent;
border-bottom: 24px solid transparent;
position: absolute;
top: -1px;
}
.j-steps{
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
li:not(:first-child) {
margin-left:8px
}
li.step {
position: relative;
width: 238px;
height: 48px;
background: #F7F8FA;
line-height: 48px;
text-align: center;
}
.right-arrow:after {
@include j-step-arrow;
border-left: 12px solid #F7F8FA;
right: -13px;
z-index: 9;
}
.right-arrow:before {
@include j-step-arrow;
border-left: 12px solid #F7F8FA;
right: -12px;
z-index: 10;
}
.left-arrow:after{
@include j-step-arrow;
border-left: 12px solid #fff;
left: -1px;
z-index: 7;
}
.left-arrow:before{
@include j-step-arrow;
border-left: 12px solid #fff;
left: -2px;
z-index: 8;
}
li:first-child {
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
.left-arrow {
display: none;
}
}
li:last-child {
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
.right-arrow {
display: none;
}
}
.cur-step {
display: inline-block;
width: 18px;
height: 18px;
background: #C1C1C1;
border-radius: 9px;
color: #fff;
line-height: 18px;
text-align: center;
margin: 0 6px 0 0;
}
.isActive {
border: 1px solid #4260DB;
.cur-step {
background: #4260DB;
}
.step-info{
color: #4260DB;
font-weight: 600;
}
.left-arrow:after,
.right-arrow:after {
border-left: 12px solid #4260DB;
}
}
}
</style>
<Step :steps="steps" v-model="curStep"></Step>
data() {
return {
curStep: 0,
steps: ['step1', 'step2'],
};
}
handleNext() {
let len = this.steps.length - 1
if(++this.curStep > len) this.curStep = 0
},