动态传参时间轴组件的页面实现

  • 上一篇写到实现该组件的核心思考,主要是要得出每个时间节点位置,再放到相应的位置上。

链接:动态传参的时间轴组件-CSDN博客

  • 本篇目标:将相应的元素放到页面的正确位置,代码在文章最后

(最终实现效果)

  • 实现前提:通过上篇 setPosition(timeArr) 函数已经得出:
  1. intervalArr: 每个时间节点占总时间长度的占比数组,

  2. betweenToday: 当前进度时间节点在总时间长度中的占比,

  3. cardPosition: 阶段标题所在位置数组

  • 页面实现思路:
  1. 创建一层底层div填充底色
  2. 当前进度时间节点div填充亮色
  3. 红框圈出来的小图标和时间节点通过定位放到轴上,定位的位置以算出来的占比乘以轴的长度。当然如果没有小图标自己纯手工画也可以,就是css多写点,多画点三角形。
  4. 创建阶段小标题div,同步骤三一样将其定位到页面的具体位置
  • 遇到的一些问题和思考

0、优化思考:把太多的关于位置的计算放在了html代码里,其实在前面的setPosition(timeArr)函数中可以多做一步,直接将位置数据计算出来,而不是只做占比计算,可以节省一点页面资源吧。

1、当两个时间节点间隔很近的时候,这个时候文字在页面的渲染会重叠,给用户感官不好,需要优化兼容。

像这样:

解决思考:比如:在计算的时候就判断一下彼此的距离,如果太近返回一个最小值,以确保最后渲染每个时间文字的渲染有足够的位置。或者,让时间文字一个在轴上方一个在下方,直接错开,这个方法比较简单,我使用的也是这个方法。

​​​​​2、小标题上的小三角形是个线框,不是实心的。

        没想到别的办法,只好先画一个大一点的三角形在画一个小一点的三角形去覆盖实现线框的效果,如果有好的方法欢迎赐教。

        我最开始使用的是伪元素去搞,后来发现伪元素并不好动态控制颜色,我们没有办法直接选中伪元素改变它的样式,只能新增伪元素来覆盖样式。具体可以看看这个:JavaScript修改CSS伪元素:after和:before的样式_css怎么在行内样式里改::before的属性-CSDN博客

最终选择的还是自己写一个triangle的div,好控制样式。如果有别的思路也欢迎探讨。

3、前面在写实现的计算函数的时候,我发现我的小标题卡片始终不在中间位置上,有所偏移。我以为是我的计算思路哪个地方有点偏差。后序测了一遍代码,发现其实是卡片本身有宽度,在对卡片定位的时候不能单纯只依靠时间计算出来的占比,还得和该元素的自宽有关,这是值得注意的一点。

 <!-- 阶段小标题 -->
<div
     v-for="(item, j) in timeLine.cardPosition"
     :key="j"
     class="card"
     :style="{
     left: `${item * props.barWidth - 30}px`,
          zIndex: j + 1,
          borderColor: cardData[j]?.color
     }"
     :title="cardData[j]?.title"
>
</div>

具体HTML和CSS代码参考如下

<div class="progress-bar" :style="{ width: `${props.barWidth ? props.barWidth : 500}px` }">
    <!-- 底色层 -->
    <div
        class="bottom-layer"
        :style="{ width: `${props.barWidth ? props.barWidth : 500}px`, ...props.position }"
    >
        <!-- 当前进度亮色层 -->
        <div
            class="color-layer"
            :style="{ width: `${props.barWidth * timeLine.betweenToday}px` }"
        ></div>
    </div>
    <!-- 循环渲染时间节点,用计算得出的数据动态的将每个时间节点放到相应的位置上 -->
    <!-- 箭头icon -->
    <div
        v-for="(item, i) in timeLine.intervalArr"
        :class="['icon', i > 0 && i < timeLine.intervalArr.length - 1 ? 'bg' : '']"
        :key="i"
        :style="{ left: `${item * props.barWidth}px` }"
    >
        <!-- 时间文字 -->
        <div :class="['time', i % 2 ? 'above' : 'below']">
            {{ props.date[i] }}
        </div>
    </div>
    <!-- 阶段小标题 -->
    <div
        v-for="(item, j) in timeLine.cardPosition"
        :key="j"
        class="card"
        :style="{
            left: `${item * props.barWidth - 30}px`,
            zIndex: j + 1,
            borderColor: cardData[j]?.color
        }"
        :title="cardData[j]?.title"
    >
        <!-- 小标题上的三角形 -->
        <div class="triangle" :style="{ borderTopColor: cardData[j]?.color }"></div>
        {{ cardData[j]?.title }}
    </div>
</div>
.progress-bar {
    position: relative;
    margin-top: 50px;
    .bottom-layer {
        position: absolute;
        top: 0;
        // right: 0;
        float: right;
        // width: 436px;
        height: 10px;
        background-color: #103c6a;
    }
    .color-layer {
        position: absolute;
        top: 0;
        left: 0;
        // width: 309px;
        height: 10px;
        background: linear-gradient(90deg, rgba(68, 169, 255, 0.3) 0%, #44a9ff 100%);
    }
    .icon {
        position: absolute;
        top: 0;
        width: 9px;
        height: 10px;
        z-index: 1;

        .time {
            position: absolute;
            left: -15px;
            width: 56px;
            font-family:
                PingFangSC,
                PingFang SC;
            font-weight: 400;
            font-size: 12px;
            color: rgba(255, 255, 255, 0.7);
            line-height: 17px;
            text-align: left;
        }
        .above {
            bottom: 15px;
        }
        .below {
            top: 15px;
        }
    }
    .card {
        position: absolute;
        bottom: 20px;
        display: inline-block;
        width: 65px;
        height: 35px;
        border: 1px solid red;
        text-align: center;
        padding: 3px;

        .triangle {
            position: absolute;
            width: 0;
            height: 0;
            top: 33px;
            left: 25px;
            border-top: solid 9px transparent;
            border-right: solid 7px transparent;
            border-left: solid 7px transparent;
        }
    }

    .card::after {
        position: absolute;
        content: '';
        width: 0;
        height: 0;
        top: 33px;
        left: 27px;
        border-top: solid 7px #073864;
        border-right: solid 5px transparent;
        border-left: solid 5px transparent;
    }

    .bg {
        background: url('@/assets/images/right-icon.png') no-repeat;
    }
}

当然,以下是对uni-app中布局、组件和交互三个板块内容的进一步补充: ## 布局 在uni-app中,布局是构建页面的基础,它决定了页面中元素的排列和分布。 ### 1. 定位(Positioning) - **相对定位(Relative Positioning)**:元素的位置相对于其在文档流中的原始位置进行偏移。使用`top`、`right`、`bottom`、`left`属性。 - **绝对定位(Absolute Positioning)**:元素的位置相对于其最近的已定位(非static)祖先元素进行定位。如果没有这样的祖先元素,则相对于初始化包含块(通常是文档的`<html>`元素)。 ### 2. 盒子模型(Box Model) - **边框(Border)**:围绕内边距的边框,可以设置宽度、样式和颜色。 - **内边距(Padding)**:元素内容和边框之间的空间,内边距会将元素的尺寸扩大。 - **外边距(Margin)**:元素与其他元素之间的空间,用于分隔元素。 ### 3. Flexbox 弹性布局 - **主轴(Main Axis)**:沿着主轴的排列方向(`row`或`column`)。 - **侧轴(Cross Axis)**:垂直于主轴的轴。 - **空间分配**:使用`justify-content`和`align-items`属性来控制项目在主轴和侧轴上的对齐方式。 - **项目排列**:使用`flex-direction`属性来控制项目的排列方向。 ## 组件 uni-app提供了丰富的组件,用于构建用户界面。 ### 1. 视图容器组件 - **`view`**:类似于HTML中的`div`,用于页面布局。 - **`cover-view`**:覆盖在原生组件上的容器,可以覆盖在`map`、`video`等组件上。 - **`swiper`**:滑块视图容器,用于创建滑动效果。 - **`scroll-view`**:可滚动视图容器,用于区域滚动。 ### 2. 表单组件 - **`input`**:输入框,用于文本输入。 - **`button`**:按钮,用于触发事件。 - **`checkbox`**:复选框,用于多项选择。 - **`radio`**:单选框,用于单项选择。 - **`switch`**:开关,用于切换状态。 - **`slider`**:滑块,用于选择一个范围值。 ### 3. 选择器组件 - **`picker`**:选择器,用于选择信息,如日期、时间等。 - **`picker-view`**:多列选择器,用于复杂的选择场景。 ### 4. 媒体组件 - **`audio`**:音频组件,用于播放音频。 - **`video`**:视频组件,用于播放视频。 - **`camera`**:相机组件,用于拍照或录像(部分平台支持)。 - **`live-player`**:直播播放组件(部分平台支持)。 - **`live-pusher`**:直播推流组件(部分平台支持)。 ### 5. 地图组件 - **`map`**:地图组件,用于显示地图和标记位置。 ### 6. 图标组件 - **`icon`**:图标组件,使用`type`属性指定图标类型,`size`属性指定图标大小。 ## 交互 在uni-app中,交互是用户与应用之间沟通的桥梁。 ### 1. 组件间交互 - **事件绑定**:通过`@`符号绑定事件,如`@click`、`@change`等。 - **数据绑定**:使用`v-bind`或简写`:`绑定数据。 ### 2. 页面间交互 - **页面跳转**:使用`uni.navigateTo`、`uni.redirectTo`等API实现页面跳转。 - **页面传参**:通过`url`参数传递数据。 ### 3. 前后端交互 - **网络请求**:使用`uni.request`发起网络请求,与后端进行数据交互。 - **数据缓存**:使用`uni.setStorageSync`和`uni.getStorageSync`进行数据缓存。 ### 4. 表单提交 - **提交表单**:使用`form`组件的`@submit`事件处理表单提交。 ### 5. 用户反馈 - **加载提示**:使用`uni.showLoading`和`uni.hideLoading`显示和隐藏加载提示。 - **模态弹窗**:使用`uni.showModal`显示模态弹窗。 --- 以上是对uni-app布局、组件和交互板块内容的补充,希望能够帮助您更全面地理解和掌握uni-app开发。如果您有任何疑问或需要进一步的帮助,请随时提问。生成思维导图
03-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值