ElementUI

219 阅读5分钟

PS: 修改 Element 中的内置样式时,需要在该组件上定义一个类名,然后在该类名中使用穿透样式覆盖内部样式。

1. Cascader

部分问题总结

2. Input

当给 v-model 绑定 number 修饰符时,不知为何,效果总是不尽人意,于是乎,自己总结了两种方案以此来解决某些输入框只输入数字。

  1. type=“number”

包含三部分操作:

  • 指定类型为 number;
  • css 去除 input 输入框中的上下小箭头,指定 input__inner 行高,消除输入非数字字符时鼠标指针上浮问题;
  • 由于指定类型为 number,此时用鼠标滚轮会改变数字,此种效果并不是我们期望的,于是使用自定义指令阻止鼠标默认行为
// html
<el-input type="number" v-disable-wheel></el-input>

// css
/*去除在Chrome中type=number的input输入框中的上下小箭头*/
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  appearance: none;
}
.el-input__inner {
  padding: 0 10px;
  line-height: 1 !important;
}

// js
directives: {
  'disable-mousewheel': {
      bind(el) {
        el.addEventListener('wheel', (e) => e.preventDefault())
      },
      update(el) {
        el.addEventListener('wheel', (e) => e.preventDefault())
      },
    },
}
  1. 监听 input 事件

可以根据需求动态的变化正则表达式中的条件。

// utils
export const removeExtraCharacterOfNumber = (value) => {
  return value
    .replace(/[^-0-9.]/g, '')
    .replace(/^\./g, '')
    .replace('.', '$#$')
    .replace(/\./g, '')
    .replace('$#$', '.')
    .replace('.', '')
}
export const removeExtraCharacterOfNumberWithDot = (value) => {
  return value
    .replace(/[^-0-9.]/g, '')
    .replace(/^\./g, '')
    .replace('.', '$#$')
    .replace(/\./g, '')
    .replace('$#$', '.')
}
<el-input v-model="inputValue" @input="handleInput"></el-input>

data() {
  return {
    inputValue: null
  }
},

methods: {
  ...
  // 由于此方法多处会用到,所以抽离成一个公共方法
  handleInput(value) {
    this.inputValue = removeExtraCharacterOfNumber(value)
  },
  
  // 仅输入正负数
  // input event
const formatPositiveAndNegativeNumber = (value: string) => {
  let tempValue = value
  const char1 = value.charAt(0)
  tempValue = tempValue.replace(/[^\d]/g, '')
  if (tempValue && tempValue[0] === '0') {
    tempValue = tempValue.substring(1)
  }
  if (char1 === '-') {
    tempValue = '-' + tempValue
  }
  this.inputValue = tempValue
}

// change event
const changePositiveAndNegativeNumber = () => {
  if (this.inputValue === '-') {
    this.inputValue = null
  }
}

3. DatePicker

有关日期的组件需求往往格式固定,形如 "YYYY-MM-DD",格式验证,结束日期是开始日期的后多少天,遇到此类问题时往往总是去查组件库,然后每次都要重新写,因此在这里总结一下方便后期使用。

  <el-form :model="form" :rules="formRules">
    <el-form-item label="开始日期:" label-width="120px" prop="startDate">
      <el-date-picker
        style="width: 100%;"
        v-model="startDate"
        type="date"
        placeholder="请选择开始日期"
        value-format="yyyy-MM-dd"
        @change="startDateChange"
    /></el-form-item>
    <el-form-item label="结束日期:" label-width="120px" prop="endDate">
      <el-date-picker
        style="width: 100%;"
        v-model="endDate"
        type="date"
        placeholder="请选择结束日期"
        value-format="yyyy-MM-dd"
    /></el-form-item>
  </el-form>
  
  // js
  form: {
    startDate: "",
    endDate: ""
  },
  formRules: {
    startDate: [
      { type: 'string', required: true, message: '请选择留样开始日期', trigger: 'change' }
    ],
    endDate: [
      { type: 'string', required: true, message: '请选择留样开始日期', trigger: 'change' }
    ]
  }
  
  openDateInfo() {
    this.startDate = formatDate(this.startDate)
    this.endDate = formatDate(this.endDate)
  },
  
  startDateChange() {
    // 这里默认90天
    this.endDate = new Date(new Date().setDate(new Date(val).getDate() + 90))
    this.endDate = formateDate(this.endDate)
  }
  
  // utils.js
  const formatDate = date => {
    const d = new Date(date)
    const year = d.getFullYear()
    let month = '' + (d.getMonth() + 1)
    let day = '' + d.getDate()
    if (month.length < 2) month = '0' + month
    if (day.length < 2) day = '0' + day
    return [year, month, day].join('-')
  }
  
  // 感觉上述的方法太过繁琐,直接使用 dayjs 即可
  this.startDate = dayjs(new Date()).format('YYYY-MM-DD')
  this.endDate = dayjs(new Date(new Date().setDate(new Date(val).getDate() + 90))).formate('YYYY-MM-DD')

4. Layout

4.1 自定义 span 宽度

<el-col :xl="{ span: '4-5' }">
</el-col>

<style lang="less" scoped>
@media only screen and (min-width: 1920px) {
  .el-col-xl-4-5 {
    width: 13%;
  }
  .el-col-xl-offset-4-5 {
    margin-left: 13%;
  }
  .el-col-xl-pull-4-5 {
    position: relative;
    right: 13%;
  }
  .el-col-xl-push-4-5 {
    position: relative;
    left: 13%;
  }
}
</style>

5. Loading

5.1 v-loading conflict with el-table binding ref

image.png 解决方法:重新自定义v-loading

image.png

具体详情请见

5.2 CSS style

  • 方案一(只在父节点有宽高的情况下生效)

    <div>
      <div class="mongolia" v-if="loadingCharts">
        <el-icon class="loading-icon"><Loading /></el-icon>
      </div>
    </div>
    
    const loadingCharts = ref(false)
    setTimeout(() => {
      loadingCharts.value = true
    }, 100)
    
    .mongolia {
      width: 100%;
      height: 100%;
      background-color: rgba(0, 0, 0, 0.7);
      display: flex;
      justify-content: center;
      align-items: center;
    
      z-index: 9999;
    }
    .loading-icon {
      position: relative;
      top: 5px;
      animation: spin 2s linear infinite;
    }
    @keyframes spin {
      from {
        transform: rotate(0);
      }
      to {
        transform: rotate(360deg);
      }
    }
    
  • 方案二 整个页面添加 loading 效果

    <div class="mongolia" v-if="requestNextPageLoading">
      <i class="el-icon-loading loading-icon" />
      <p>loading...</p>
    </div>
    
    // css
    .mongolia { 
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(255, 255, 255, 0.9);
      display: flex;
      justify-content: center;
      align-items: center;
      font-size: 1.5rem;
      color: #409eff;
      z-index: 9999;
    }
    .loading-icon {
      color: #409eff;
      font-size: 32px;
    }
    
  • 方案三:在局部页面添加 loading 效果 此种方案只需要将 loading 相关的 html 放到高度为 100% 的元素内部即可。

// html
<div v-if="waitLoading">
  ...
</div>
<div class="mongolia" v-else-if="waitLoading">
  <el-icon class="el-icon-loading loading-icon"> <Loading /> </el-icon>
  <p class="text-loading">loading...</p>
</div>

// css
.mongolia {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.5);
  color: #409eff;
}
.loading-icon {
  font-size: 32px;
  animation: spin 2s linear infinite;
}
.text-loading {
  position: relative;
  left: 5px;
}
@keyframes spin {
  from {
    transform: rotate(0);
  }
  to {
    transform: rotate(360deg);
  }
}

6. Tabs

需求:每个 tab 都是一个单独的页面文件,点击不同的 tab 发送不同的请求从而渲染不同的页面。

6.1 v-if

使用不同的 flag 绑定在不同的子组件上,有些场景失效。

6.2 Flags

如果子页面无法正确监听,可以在页面失活时重置 Flag。

PS:在 Vue2 中,要确保 router 中的 name 名称和组件中的 name 保持一致。

// parent
<el-tabs @tab-click='changeTab'>
<el-tab-pane name='child1' label='child1'>
  <Child1 :active-flag='activeChild1' />
</el-tab-pane>

<el-tab-pane name='child2' label='child2'>
  <Child2 :active-flag='activeChild2' />
</el-tab-pane>
</el-tabs>

// script
const changeTab = () => {
  switch (activeName) {
    case 'child1':
      this.activeChild1 = true
      this.activeChild2 = false
      break
    case 'child2':
      this.activeChild1 = false
      this.activeChild2 = true
      break
    default:
      break
  }
}
const resetFlag = () => {
  this.activeChild1 = false
  this.activeChild2 = false
}

// 如果发现子组件无法正确监听,可以在 deActivated 中重置一下
deActivated() {
  resetFlag()
}

// Child
watch: {
  activeFlag: {
    handler(val) {
      val && this.getRequest()
    }
  }
}

6.3 props

当不使用方式二中的 deActivated 重置方法,可以在子组件中进行操作。

此页面刷新触发条件有两种:1. 从别的页面切换到当前页面(activated);2. 点击 tab 切换。

如果当前页面不是 tab 的第一个,那么当停留在当前页面时,如果从别的页面切换到当前页面,那么执行的就是 activated 中的 else 方法;如果点击 tab,那么执行的就是 watch 中的方法,如果 watch 和 firstFlag 同时执行的话,会发送两次请求,此时禁止掉第一次请求即可。

PS:如果是 tab 的第一个页面那么需要在 watch 的时候加上 immediate 。

// child
activated() {
  if (this.firstFlag) {
    this.firstFlag = false
  } else {
    this.activeFlag && this.getRequest()
  }
},

// 区别:
// child1
activeFlag: {
    handler(val) {
      val && this.getRequest()
    },
    immediate: true
  }
  
  // child2
  activeFlag: {
    handler(val) {
      val && this.getRequest()
    }
  }

7. Table

7.1 修改表格的一些样式

.el-table {
  --el-table-border-color: var(--custom-global-table-border-color) !important;
  --el-fill-color-blank: var(--custom-global-bg-color) !important;
  --el-table-row-hover-bg-color: var(--custom-global-table-row-hover-color) !important;

  .el-table-fixed-column--right {
    background: var(--custom-global-bg-color) !important;
  }

  .el-table__body .el-table__row.hover-row td {
    background: var(--custom-global-table-row-hover-color) !important;
  }
}