前端实习生开发过程中的问题总结(一)

注:该文档主要是笔者在实习过程中遇到的一些具有代表意义的问题总结及解决方案,希望对大家在开发过程中遇到的问题能有所帮助!

一、时间轴组件的封装

  • 背景:实习第一周接手的项目需求里面有一个“时间轴”的组件,看到UI图的第一眼想到是借助Elementui的步骤条进行需求的定制化,但是后续进行可行性分析的过程中发现,由于Elementui这个组件的封装性较深,再度进行定制化的话,需要写一个较为复杂的渲染函数,代码的可读性会变得较低,于是,笔者就采用原生的html+css从头绘制这个组件。

  • 关键技术点:css伪元素的使用,vue2组件间传值(父传子)

  • 代码:

//html部分
<template>
  <div class="timeline-wrap">
    <div class="timeline-header">
      <span>{{ title }}</span>
    </div>
    <div class="timeline-content">
      <div v-for="(item, index) in dataList" :key="index" class="timeline-item">
        <div class="item-year">
          <span>{{ item.year }}</span>
          <span><i class="year-icon"></i></span>
        </div>
        <div class="timeline-item-content">
          <div
            v-for="(subItem, subIndex) in item.body"
            :key="subIndex"
            class="subItem-content"
          >
            <div class="timeline-date">
              <span class="subItem-date">{{ subItem.month }}</span>
              <span class="subItem-year">{{ subItem.year }}</span>
            </div>
            <div class="timeline-score">
              <span>总分:</span>
              <span>{{ subItem.score }}</span>
            </div>
            <div class="timeline-name">
              <span>{{ subItem.levels }}</span>
            </div>
            <div class="timeline-trend">
              <div class="trend-title">
                <span>{{ subItem.trend }}</span>
              </div>
              <div class="trend-icon">
                <span><i class="icon"></i></span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
//js部分
<script>
export default {
  name: 'Timeline',
  props: {
    title: {
      type: String,
    },
    dataList: {
      type: Array,
    },
  },
  data() {
    return {}
  },
}
</script>
//css部分,采用了scss预编译工具
<style lang="scss" scoped>
$base-color: #84b9e5;
​
//设置时间轴元素的滑动条的样式
.timeline-content::-webkit-scrollbar {
  width: 10px;
  border-radius: 10px;
}
​
.timeline-content::-webkit-scrollbar-track {
  background-color: #f5fbff;
  border-radius: 10px;
}
​
.timeline-content::-webkit-scrollbar-thumb {
  height: 60px;
  border-radius: 10px;
  background-color: $base-color;
}
​
.timeline-wrap {
  width: 30%;
  min-width: 490px;
  height: 500px;
  box-sizing: border-box;
  border: 1px solid #ececec;
​
  .timeline-header {
    width: 100%;
    height: 40px;
    padding-left: 20px;
    line-height: 40px;
    border-bottom: 2px solid $base-color;
​
    span {
      font-size: 18px;
      font-weight: bold;
    }
  }
​
  .timeline-content {
    width: 100%;
    height: calc(100% - 60px);
    padding: 20px 20px 0;
    overflow-x: hidden;
    overflow-y: auto;
​
    .timeline-item {
      .item-year {
        width: 100%;
        height: 34px;
        line-height: 34px;
        margin-bottom: 16px;
        font-size: 16px;
        background-color: #f5fbff;
​
        .year-icon {
          width: 10px;
          height: 5px;
          line-height: 34px;
          margin-left: 10px;
          display: inline-block;
          background-image: url('图标路径');
        }
      }
​
      .timeline-item-content {
        font-size: 16px;
        padding: 0px 10px 0px 20px;
        border-left: 2px dashed #d1caca;
​
        .subItem-content {
          display: flex;
          justify-content: space-between;
          align-items: center;
          width: 385px;
          height: 65px;
          margin-bottom: 10px;
          background-image: url('图标路径');
          position: relative;
​
          &::before {
            content: '';
            display: inline-block;
            width: 16px;
            height: 16px;
            position: absolute;
            left: -30px;
            top: 23px;
            border: 2px solid $base-color;
            border-radius: 50%;
            background: #fff;
          }
​
          .timeline-date {
            width: 70px;
            padding: 10px;
            text-align: center;
​
            .subItem-date {
              display: block;
              color: #fff;
              font-size: 18px;
              font-weight: bold;
            }
​
            .subItem-year {
              display: block;
              font-size: 14px;
              font-weight: 400;
              color: #ffffff;
            }
          }
​
          .timeline-name {
            width: 82px;
            height: 26px;
            background-image: url('图标路径');
​
            span {
              display: block;
              width: 100%;
              color: #ffffff;
              line-height: 26px;
              text-align: center;
              font-weight: bold;
            }
          }
​
          .timeline-trend {
            display: flex;
            justify-content: space-around;
            align-items: center;
            width: 60px;
            height: 32px;
​
            .trend-title {
              display: block;
              color: #333;
              line-height: 32px;
              text-align: center;
              font-weight: bold;
            }
​
            .trend-icon {
              .icon {
                display: inline-block;
                width: 10px;
                height: 6px;
                background-image: url('图标路径');
              }
            }
          }
        }
      }
    }
  }
}
</style>
//父组件引用组件
<Timeline :title="title" :data-list="dataList"></Timeline>

二、tabs标签栏组件的封装+动态组件

  • 背景:项目模块需要通过一个tabs标签栏组件控制下方渲染不同的组件,最开始笔者采取的方案是通过点击不同的tab标签跳转到不同的路由,下方利用<view-router></view-router>来渲染组件。这种方案存在一个很难解决的问题:当路由跳转后,会再次刷新tabs传递的参数,导致点击标签栏后会出现不跳转的现象。笔者尝试了利用地址栏传递参数、Vuex传递参数都没有解决这个问题,当笔者准备尝试利用缓存传递参数的方案时,我的导师给我提供了一个很好的解决方案:利用动态组件:<component :is="currentComponent"></component>。很好的解决了这个问题,但是还是存在一个问题,那就是当地下的组件需要跳转到其他路由,再返回tabs栏页面时,不经过优化只能返回到tabs的默认组件。笔者的优化方案是在每次需要跳转到其他路由时,把当前tabs的索引放入参数里面一同传过去,返回tabs栏页面时,再次设置tabs栏的索引。

  • 关键技术点:vue2组件间传值(子传父)、vue2动态组件

  • 代码:

//tabs组件
<template>
  <div class="my-tabs">
    <div class="evaluate-result-header">
      <div class="header-tabs">
        <ul>
          <li
            v-for="(item, index) in tabsData"
            :key="index"
            :class="{ active: index === activeIndex }"
            @click="chooseIndex(index)"
          >
            <span class="tabs-icon"><i :class="item.iconClass"></i></span>
            <span class="tabs-text">{{ item.tabsText }}</span>
          </li>
        </ul>
      </div>
      <div class="header-button">
        <el-button type="primary" style="border-radius: 4px" @click="toEvaluateManage">
          返回
        </el-button>
      </div>
    </div>
  </div>
</template>
​
<script>
export default {
  data() {
    return {
      activeIndex: 0,
      tabsData: [
        {
          tabsText: '评价结果',
          iconClass: 'el-icon-s-claim',
        },
        {
          tabsText: '交通违法记录',
          iconClass: 'el-icon-s-cooperation',
        },
        {
          tabsText: '修复记录',
          iconClass: 'el-icon-s-tools',
        },
        {
          tabsText: '异议记录',
          iconClass: 'el-icon-s-order',
        },
      ],
    }
  },
  methods: {
    chooseIndex(index) {
      this.activeIndex = index
      this.$emit('change-component', index);
    },
    toEvaluateManage() {
      this.$router.go(-1)
    },
  },
}
</script>
​
<style lang="scss" scoped>
$base-color: #409eff;
.evaluate-result-header {
  padding: 0 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
​
  .header-tabs {
    ul {
      display: flex;
      align-items: center;
​
      li {
        width: 190px;
        height: 50px;
        display: flex;
        justify-content: center;
        align-items: center;
        border-radius: 4px;
        background-color: #fff;
​
        .tabs-icon {
          display: inline-block;
          width: 24px;
          height: 24px;
          text-align: center;
          line-height: 24px;
          border-radius: 4px;
          background-color: $base-color;
​
          i {
            display: inline-block;
            width: 20px;
            height: 20px;
            color: #fff;
          }
        }
        .tabs-text {
          margin-left: 10px;
          font-size: 16px;
          color: #333;
        }
      }
      li.active {
        background-color: $base-color;
        .tabs-icon {
          background-color: #fff;
          i {
            color: $base-color;
          }
        }
        .tabs-text {
          color: #fff;
        }
      }
​
      li:hover {
        background-color: $base-color;
        .tabs-icon {
          background-color: #fff;
          i {
            color: $base-color;
          }
        }
        .tabs-text {
          color: #fff;
        }
      }
    }
  }
}
</style>
 
//index组件,用于渲染几个组件
<template>
  <div class="home">
    <EvaluateResuktTabs @change-component="updateCurrentComponent"></EvaluateResuktTabs>
    <component :is="currentComponent"></component>
  </div>
</template>
​
<script>
import Timeline from './components/Timeline.vue'
//下方需要渲染的组件
import EvaluateResuktTabs from './components/evaluateResuktTabs.vue'
import EvaluateResultManageInfo from '@/views/enterprise-risk/evaluateResultManageInfo/evaluateResultManageInfo'
import TrafficViolationRecords from './trafficViolationRecords.vue'
import RepairRecords from '@/views/enterprise-risk/evaluateResultManageInfo/repairRecords'
import ObjectionRecords from '@/views/enterprise-risk/evaluateResultManageInfo/objectionRecords'
export default {
  name: 'EvaluateResultManageInfoIndex',
  components: {
    Timeline,
    EvaluateResuktTabs,
    EvaluateResultManageInfo,
    TrafficViolationRecords,
    RepairRecords,
    ObjectionRecords
  },
  data() {
    return {
      currentComponent: 'EvaluateResultManageInfo',
    }
  },
  methods: {
    updateCurrentComponent(index) {
      if(index === 0) {
        this.currentComponent = 'EvaluateResultManageInfo'
      }else if(index === 1) {
        this.currentComponent = 'TrafficViolationRecords'
      }else if(index === 2) {
        this.currentComponent = 'RepairRecords'
      }else {
        this.currentComponent = 'ObjectionRecords'
      }
    }
  },
}
</script>
​总结:该系列主要是笔者在实习过程中遇到一些自认为比较典型的问题以及解决方案,希望大佬们能针对案例进行指正和优化,谢谢!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java丶Sunday

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值