「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」。
前言
上一篇我们说到了整体的构思和参数考量,我们就来看看具体的实现吧!
通过本章我们可以学习到:
1、flex布局。
2、createSelectorQuery()应用。
DOM
很简单没啥说的,主要就是下面。
1、主要分为scroll滑动和不滑动两种。
2、通过<slot>
暴露后备内容
3、<view class="link-p" :style="{ width:
{LeftPx}px, transition:
left ${sec}s ease-in-out }"></view>
这段主要是我们胶囊滑动的实现。很简单通过:transition实现。坐标移动目前采用最简单的left。看代码:
<template>
<view>
<view class="scroll-view-x" v-if="scroll">
<view :id="'the-' + index" v-for="(item, index) in option" :key="item.id" class="scroll-view-item " @tap="calculator(index)">
<slot name="scroll" :item="item" :active="idx == index">
<!-- 后备内容 -->
{{ item.name }}
</slot>
</view>
<view class="link-p" :style="{ width: `${width}upx`, background: colour, left: `${LeftPx}px`, transition: `left ${sec}s ease-in-out` }"></view>
</view>
<view class="scroll-view-x no-scroll" v-else>
<view :id="'the-' + index" v-for="(item, index) in option" :key="item.id" class="scroll-view-item " @tap="calculator(index)">
<slot :item="item" :active="idx == index">
<!-- 后备内容 -->
{{ item.name }}
</slot>
</view>
<view class="link-p" :style="{ width: `${width}upx`, background: colour, left: `${LeftPx}px`, transition: `left ${sec}s ease-in-out` }"></view>
</view>
</view>
</template>
复制代码
css
这部分最重要的就是felx布局中的justify-content: space-between;属性的使用。通过它可以做到内容的自动适应。对flex还不了解我们可以查看Flex 布局语法教程,有图有说明很清楚。好了看代码:
<style scoped>
.scroll-view-x {
display: flex;
flex-direction: row;
height: 88upx;
white-space: nowrap;
width: 100%;
background-color: #ffffff;
box-sizing: border-box;
position: relative;
justify-content: space-between;
overflow: auto;
}
.no-scroll{
overflow: hidden;
}
.scroll-view-x .scroll-view-item {
display: inline-block;
text-align: center;
font-size: 30upx;
padding: 0 25upx;
color: #787878;
height: 88upx;
line-height: 88upx;
}
.scroll-view-x .tapitem {
color: #ff8c39;
position: relative;
}
.scroll-view-x .link-p {
position: absolute;
height: 5upx;
border-radius: 4upx;
bottom: 10upx;
transition: left 0.25s ease-in-out;
width: 40upx;
background: rgba(243, 152, 0, 1);
}
.scroll-view-x .link-p .link {
display: block;
margin: 0 auto;
height: inherit;
border-radius: 4px;
}
</style>
复制代码
script部分
这部分分为两点:
1、props的确定,昨天我们设计的时候已经说了,确定好类型就行。
2、因为我们的内容是不确定的也是不等宽的,所以我们要获取到节点的位置信息。我们这边使用uni.createSelectorQuery()
。还不了解我们查看链接。通过boundingClientRect(callback)可以得到节点位置信息。我们保存起来就可以了。
note:注意第二步节点获取要在this.$nextTick
中。
3、通过点击选项的事件,我们改变胶囊LeftPx参数值就大功告成了,其实挺简单的。
看代码:
export default {
name: 'duNav',
props: {
/**
* 是否滑动
*/
scroll: {
type: Boolean,
default: true
},
/**
* 样式类型
*/
classType: {
type: [Number],
default: 0
},
/**
* 胶囊速度
*/
sec: {
type: [Number, String],
default: 0.25
},
/**
* 胶囊宽
*/
width: {
type: [Number, String],
default: 40
},
/**
* 胶囊颜色
*/
colour: {
type: String,
default: 'rgba(243, 152, 0, 1)'
},
/**
* 选项
*/
option: {
type: [Array],
default: () => [{ name: '全部' }]
}
},
data() {
return {
idx: 0,
LeftPx: 0
};
},
created() {
this.initialPra();
},
methods: {
initialPra() {
this.$nextTick(() => {
for (let i in this.option) {
const query = uni.createSelectorQuery().in(this);
query
.select('#the-' + i)
.boundingClientRect(data => {
let { left, width } = data;
this.option[i].left = left;
this.option[i].width = data.width;
if (Number(i) === 0) {
this.LeftPx = this.option[0].width / 2 - this.width / 4;
}
})
.exec();
}
});
},
calculator(i) {
let initial = this.option[0].left;
let left = this.option[i].left;
let width = this.option[i].width;
this.idx = i;
this.LeftPx = left + width / 2 - this.width / 4 - initial;
this.$emit('feedback', i);
}
}
};
</script>
复制代码