记录一次参与项目开发后的前端技术方案总结

4 阅读6分钟

项目经验总结

本文内容概述

根据本文总结的通用解决方案,以后在项目初期就开始应用,随着项目的进展参与开发者会越来越感到轻松,只需对接需求,开发需求;基本常用的方法即时调用,项目维护也有迹可循,高效完成开发任务的同时,提高了生产力。

项目中频繁定义时间相关方法的问题解决方案

像类似这种项目,在web页面上展示的时间格式一般为:2023-08-12 12:20:00或者2023-08-12 12:20等;时间参数传给后端接口时可能是时间戳形式,也可能是其他。

在项目中几十个组件里都有定义格式化时间的函数,而且定义了很多种不同的函数,这些组件里都需要先引入moment.js后者day.js,很低效,维护起来很麻烦。

省心又可便捷使用的方案是,把这些方法统一定义在Vue实例的某个属性上,比如$utils

本项目中定义了如下通用时间相关方法:

import dayjs from 'dayjs'

// 格式化时间
function formatDate (t) {
  return dayjs(t || new Date()).format('YYYY-MM-DD HH:mm:ss')
}

// 格式化时间
function formatShortDate (t) {
  return dayjs(t || new Date()).format('YYYY-MM-DD')
}

// 最近一周
function recentWeek () {
  return [dayjs().subtract(1, 'week').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')]
}

// 最近一天
function recentDay () {
  return [dayjs().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), dayjs().format('YYYY-MM-DD HH:mm:ss')]
}
// 最近一天
function recentDayDate () {
  return [dayjs().subtract(1, 'day').format('YYYY-MM-DD'), dayjs().format('YYYY-MM-DD')]
}
// 获取当前年月日:2023-03-23
function getYearMonthDay () {
  return dayjs(new Date()).format('YYYY-MM-DD')
}
// 获取当前周几:星期五
function getWeeks () {
  const weekObj = {
    0: '星期日',
    1: '星期一',
    2: '星期二',
    3: '星期三',
    4: '星期四',
    5: '星期五',
    6: '星期六'
  }
  return weekObj[dayjs().day()]
}
// 获取24h制的时分:16:24
function getHourMinute () {
  return dayjs(new Date()).format('HH:mm')
}

然后挂载在Vue实例全局上

// 所有的公共方法挂载在Vue.prototype.$utils上
import * as utils from '@/utils/index.js'
Vue.prototype.$utils = utils

在组件中使用时,不用再次引入moment.jsday.js甚至不用引入对应的方法即可使用:

scanInBaginfo({ time: this.$utils.formatDate() }).then(res => {})

项目中频繁定义字体样式的问题解决方案

在项目进行Web开发复盘时,注意到有几百次定义类似css的地方:

font-family: PingFangSC-Semibold;
font-size: 18px;
color: rgba(0, 0, 0, 0.70);
font-weight: 600;

因为这个项目中有的页面是放在pc上,有的是大屏上,有的在PAD上,甚至有的是在明眸设备上展示,所以设计师设计的各种字体,这是需求决定的改变不了。

需求是没法改了,着手在开发上进行优化吧。

最终解决方案是使用Sass写一个全局的mixin,这个mixin可以传入字体、字号、颜色、字体粗细值;

// 文字样式
@mixin fontStyle ($family: MicrosoftYaHeiUI, $size: 16px, $opacity: 1, $weight: 400) {
  font-family: $family;
  font-size: $size;
  color: rgba(0, 0, 0, $opacity);
  font-weight: $weight;
}

使用时不需要任何的引入,直接@include使用,如下

@include fontStyle(PingFangSC-Semibold, 18px, 0.7, 600);

正常使用之前需要两个配置插件style-resources-loader、vue-cli-plugin-style-resources-loadervue.config.js文件中配置如下:

pluginOptions: {
  'style-resources-loader': {
    preProcessor: 'scss',
    patterns: [
      // 路径根据具体需求更改
      path.resolve(__dirname, 'src/style/mixin.scss')
    ]
  }
}

重启项目即可使用全局Sass minxin,需要传递参数的css片段都可才有此方式处理!

项目中其他频繁定义样式的解决方案-通用按钮、单行省略号、多行省略号、滚动条样式

项目中类似于处理字体样式的方案,还有通用按钮、单行省略号、多行省略号、滚动条样式等通用css片段,这些和字体样式不同的地方是,不需要传入参数变量;所以不需要使用@mixin,甚至不需要使用sass,直接全局定义css样式,组件内直接使用即可。

本项目中如下:

/* 文字超出省略号省略号 */
.ellipsis {
  text-overflow: ellipsis;
  word-break: break-all;
  white-space: nowrap;
  overflow: hidden;
}

/* 文字2行超出省略号 */
.ellipsis-two {
  overflow: hidden;
  text-overflow: ellipsis;
  display: box;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* 文字3行超出省略号 */
.ellipsis-three {
  overflow: hidden;
  text-overflow: ellipsis;
  display: box;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

/* 美化滚动条样式,添加class样式.scrollbar */
.scrollbar::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
.scrollbar::-webkit-scrollbar-track {
  background: #86a7bc;
  border-radius: 2px;
}
.scrollbar::-webkit-scrollbar-thumb {
  background: #177fd9;
  border-radius: 6px;
}
.scrollbar::-webkit-scrollbar-thumb:hover {
  background: #333;
}
.scrollbar::-webkit-scrollbar-corner {
  background: #179a16;
}
/* plain版 美化滚动条样式,添加class样式.scrollbar-plain */
.scrollbar-plain::-webkit-scrollbar {
  width: 2px;
  height: 2px;
}
.scrollbar-plain::-webkit-scrollbar-track {
  border-radius: 2px;
}
.scrollbar-plain::-webkit-scrollbar-thumb {
  border-radius: 2px;
}

/* 通用绿色按钮 */
.green-button {
  .el-button {
    max-width: 12.2rem;
  }
  .el-button--primary {
    border-color: #01ae97;
    background-color: #01ae97;
    border-radius: 4px;
  }
  .el-button--primary:hover {
    border-color: #1bc4ae;
    background-color: #1bc4ae;
  }
  .el-button--default {
    border: 1px solid #01ae97;
    border-radius: 4px;
    color: #01ae97;
  }
  .el-button--default:hover:not(.is-disabled) {
    border-color: #1bc4ae;
    background: #ffffff;
    color: #1bc4ae;
  }
  .el-button--primary:hover:not(.is-disabled) {
    border-color: #1bc4ae;
    background: #1bc4ae;
    color: #ffffff;
  }
  .el-button.is-disabled.el-button--default:not(.is-icon) {
    border-color: #01ae97;
    background-color: #ffffff;
    color: #01ae97;
    opacity: 0.4;
  }
}

// toast样式
.toast-tip-modify-style {
  width: 50% !important;
  font-size: 3.6rem !important;
  line-height: 4.8rem !important;
}

项目中数字千分位展示的通用方法

项目中大屏页面,会展示很多数字,有的数字的值会很大,为了方便清晰观看,设计师建议展示为千分位计数方式,由于有多个地方使用此方法,所以全局定义此方法,也是挂载在Vue.prototype.$utils

定义如下:

function toThousands (n) {
  let isFu = false
  let isSmall = false
  n = Number(n).toFixed(2)
  // 考虑负数的情况
  if (n < 0) {
    n = Math.abs(n)
    isFu = true
  }
  // 考虑小数情况(业务中保留两位)
  let s = ''
  n = n.toString()
  if (n.indexOf('.') !== -1) {
    isSmall = true
    s = n.slice(-3)
    n = n.slice(0, n.length - 3)
  }
  let num = n || '0'
  let result = ''
  while (num.length > 3) {
    result = ',' + num.slice(-3) + result
    num = num.slice(0, num.length - 3)
  }
  if (num) {
    result = num + result
  }
  if (isFu) {
    result = '-' + result
  }
  if (isSmall) {
    result += s
  }
  return result
}

组件内不需要引入,使用如下:

<span class="right-text" :title="`${$utils.toThousands(item.right)}元`">
  {{ $utils.toThousands(item.right) }}元
</span>

项目中使用vue-seamless-scroll插件滚动列表,造成点击失效问题的解决方案

在此项目中用到了vue-seamless-scroll插件,可以使列表无限滚动,给页面添加一些灵动感,并可滚动展示列表内容,用户不用使用鼠标手动滚动查看。

在使用了此插件的列表上,点击某行数据,添加点击事件时,发现失效了。

分析一下其生成的dom结构,发现是列表每行的domvue-seamless-scroll插件遮挡了,并且这个遮挡dom是随着列表的不断滚动动态刷新的。

在采用事件的冒泡捕获机制、事件代理以及用户自定义属性的方法解决:

dom上自定义属性 :data-item

<div class="t-body scrollbar-plain" @click="showVedio($event)">
  <vueSeamlessScroll :data="dataList" :class-option="classOption">
    <div class="item-line" v-for="(item, index) in dataList" :key="index" :data-item="JSON.stringify(item)">
      <div class="order-cls ellipsis">{{ index + 1 }}</div>
      ...
    </div>
  </vueSeamlessScroll>
</div>

在点击事件的回调方法中获取自定义属性的数据:

// 展示视频详情
showVedio (e) {
  // 解决vue-seamless-scroll滚动时,点击事件失效的问题;事件代理;
  if (e.target.parentElement.classList.contains('item-line')) {
    this.itemdata = JSON.parse(e.target.parentElement.dataset.item)
    ...
  }
}

使用repeat(auto-fill, minmax(320px, 1fr))方式解决页面内容自适应响应式布局问题

之前实现页面内容自适应页面尺寸变化的方案可能是如下几种:

  • 媒体查询
/* 小屏幕(平板,大于等于 768px) */
@media (min-width: @screen-sm-min) { ... }

/* 中等屏幕(桌面显示器,大于等于 992px) */
@media (min-width: @screen-md-min) { ... }

/* 大屏幕(大桌面显示器,大于等于 1200px) */
@media (min-width: @screen-lg-min) { ... }
  • bootstrap
<!-- Columns start at 50% wide on mobile and bump up to 33.3% wide on desktop -->
<div class="row">
  <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
  <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
  <div class="col-xs-6 col-md-4">.col-xs-6 .col-md-4</div>
</div>
  • elementUI
<el-row :gutter="10">
  <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1"><div class="grid-content bg-purple"></div></el-col>
  <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11"><div class="grid-content bg-purple-light"></div></el-col>
  <el-col :xs="4" :sm="6" :md="8" :lg="9" :xl="11"><div class="grid-content bg-purple"></div></el-col>
  <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="1"><div class="grid-content bg-purple-light"></div></el-col>
</el-row>
  • 此项目中使用了Grid布局系统中方案repeat(auto-fill, minmax(320px, 1fr))
.assemble-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 16px;
  margin-top: 16px;
}

到这里本文就结束了,感谢阅读,希望能对你有所帮助!