工作台笔记

一、企业数据库优化

1、点击跳转位置

<div id="business" class="main">
handleSelect(url, index) {
  this.activeIndex = index
  this.$el.querySelector(url).scrollIntoView({
    behavior: 'smooth' // 平滑过渡
  })
}

用户点击tab,如果在请求api时显示Loading,完成后滑倒相应位置

<template>
  <div class="infos-container">
    <div v-loading="loading">
      <div v-if="!isDataEmpty" class="infos-main">
        <div id="business" class="main">1</div>
        <div id="members" class="main">2</div>
      </div>
    </div>
  </div>
</template>
<script>
let loadingTime = null
export default {
  methods: {
    handleSelect(url, index) {
      this.activeIndex = index
      if (this.loading) {
        clearTimeout(loadingTime)
        loadingTime = setTimeout(() => {
          this.handleSelect(url, index)
        }, 500)
      } else {
        this.$el.querySelector(url).scrollIntoView({
          behavior: 'smooth' // 平滑过渡
        })
        clearTimeout(loadingTime)
      }
    },
  }
}
</script>

2、爷、父,孙子组件-$attrs

详细讲解vue中祖孙组件间的通信之使用 a t t r s 和 attrs和 attrslisteners的方式
https://zhuanlan.zhihu.com/p/388016979
爷爷.vue
在这里插入图片描述
父.vue(v-bind=“ a t t r s " 、 v − o n = " attrs"、v-on=" attrs"von="listeners”)
在这里插入图片描述
·子·.vue(inheritAttrs: false,)
在这里插入图片描述

二、建筑模块

1、CSS绝对定位元素内文本自动换行问题

在这里插入图片描述在这里插入图片描述

子元素不换行white-space: nowrap;
定位不确定自身宽度用transform: translateX(100%);
参考: https://segmentfault.com/q/1010000004073386

.record-li-text {
  position: relative;

  .tag {
    position: absolute;
    top: -4px;
    right: -8px;
    transform: translateX(100%);
    padding: 4px 6px;
    font-size: 12px;
    line-height: 13px;
    white-space: nowrap;
    color: #14aa4c;
    border-radius: 2px;
    border: 1px solid #14aa4c;
  }
}

2、父组件修改子组件传过来的data数据,子组件数据也被修改

3、单文件不设置name: 'QueriesDetails’属性不触发activated钩子

4、表格封装

在这里插入图片描述

<template>
  <div class="tabel-box">
    <DetailsTableScreen ref="detailsTableScreen" v-bind="$attrs" v-on="$listeners" />
    <el-table
      ref="indexTable"
      v-loading="loading"
      :data="tableData"
      border
      :header-cell-style="headerCellStyle"
      class="elTable"
      :span-method="objectSpanMethod">
      <el-table-column type="index" label="序号" width="70" align="center">
        <template slot-scope="scoped">
          <span v-if="scoped.row.index">{{ (Number(currentPage) - 1) * pageSize + Number(scoped.row.index) + 1 }}</span>
          <span v-else>{{ (Number(currentPage) - 1) * pageSize + scoped.$index + 1 }}</span>
        </template>
      </el-table-column>
      <template v-for="col in columns">
        <template v-if="!col.slot">
          <el-table-column :key="col.prop" :prop="col.prop" :label="col.label" v-bind="{ ...col.options }">
            <template slot-scope="scope">
              <div>{{ scope.row[col.prop] ? scope.row[col.prop] : '-' }}</div>
            </template>
          </el-table-column>
        </template>
        <template v-else>
          <el-table-column :key="col.prop" :label="col.label" v-bind="{ ...col.options }">
            <template slot-scope="scope">
              <slot :name="col.prop" :scope="scope" />
            </template>
          </el-table-column>
        </template>
      </template>
      <template slot="empty">
        <slot name="empty" />
      </template>
    </el-table>
  </div>
</template>
<script>
export default {
  props: {
    pageSizes: {
      type: Array,
      default: () => []
    },
    loading: {
      type: Boolean,
      default: false
    },
    border: {
      type: Boolean,
      default: true
    },
    headerCellStyle: {
      type: Object,
      default: () => {
        return {
          background: '#f6f6f6',
          color: '#333333',
          fontWeight: 'normal',
          textAlign: 'center !important',
          paddingLeft: '0 !important',
          paddingRight: '0'
        }
      }
    },
    pageSize: {
      type: Number,
      default: 10
    },
    tableData: {
      type: Array,
      default: () => []
    },
    total: {
      type: [Number, String],
      default: 0
    },
    currentPage: {
      type: Number,
      default: 1
    },
    // 分页展示
    isShowPaging: {
      type: Boolean,
      default: true
    },
    // 表格类型,匹配prop.js里的数据
    type: {
      type: String,
      default: ''
    },
    tableMerge: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      columns: []
    }
  },
  mounted() {
    if (this.type == '') return
    import('./prop').then((res) => {
      this.columns = res[this.type]
    })
  },
  methods: {
    // 表格合并
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      if (this.tableMerge) {
        if (row.celShow[columnIndex]) {
          return row.celShow[columnIndex].type
        }
      }
    }
  }
}
</script>
<style scoped lang="scss">
.tabel-box {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.elTable {
  flex: 1;
  font-size: 14px;

  ::v-deep .el-table__body {
    color: $color33;
  }
}

::v-deep {
  .el-table__fixed::before,
  .el-table__fixed-right::before {
    background-color: #e5e5e5;
  }

  .el-table::before,
  .el-table--group::after,
  .el-table--border::after {
    background-color: #e5e5e5;
  }
}
</style>

<IndexTable
   type="qualification"
   :table-data="qualification.list"
   :current-page="qualification.pageIndex"
   :total="qualification.total"
   :page-size="qualification.pageSize">
   
qualification: { list: [], pageIndex: 1, pageSize: 10, total: 0 }

5、筛选框封装

在这里插入图片描述
需求:选择框的宽度要随着内容的变化而变化
我的方法:
1、写一个父元素div(宽度仅设置min-width,定位position: relative;)
2、选择框el-select(宽、高度设置100%,定位position: absolute;)
3、写一个隐藏的div,放回显的内容,内容长就会撑开父元素,选择框自然就撑开啦
在这里插入图片描述
在这里插入图片描述

<template>
  <div :class="['screen', isShowScreen ? 'has-screen' : 'not-screen']">
    <div class="screen-label">
      <span class="title">{{ subtitle }} </span>
      <span class="num">{{ num }}</span>
    </div>
    <div v-if="isShowScreen" class="screen-item">
      <div v-for="(v, k) in screenArr" :key="k">
        <template v-if="v.type === 'input'">
          <div class="screen-search marl-10">
            <el-input v-model="value[k]" :placeholder="v.placeholder" />
            <el-button class="search" type="primary" @click="changeValue(value[k], k)">
              <img class="search_icon" src="@/assets/images/svg/search_icon.svg" />
            </el-button>
          </div>
        </template>

        <template v-if="v.type === 'single-select'">
          <div class="select-box marl-10">
            <el-select
              v-model="value[k]"
              popper-class="cu-select-build"
              :placeholder="v.placeholder"
              clearable
              @change="changeValue($event, k)">
              <el-option v-for="(item, i) in v.options" :key="item.value + i" :label="item.label" :value="item.value">
              </el-option>
            </el-select>
            <span class="control-width">{{ control[k] }}</span>
          </div>
        </template>
      </div>
      <el-button class="screen-reset marl-10" @click="resetValue">重置</el-button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'DetailsTableScreen',
  props: {
    subtitle: {
      type: String,
      default: ''
    },
    num: {
      type: [Number, String],
      default: 0
    },
    // {属性: { prop: '属性', value: '默认值', type: 'single-select', options: []},}
    screenArr: {
      type: Object,
      default: () => {}
    },
    isShowScreen: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      value: {},
      control: {}
    }
  },
  watch: {
    screenArr: {
      handler(val) {
        // 赋默认值
        for (const k in val) {
          if (val[k].options && val[k].options.length && this.value[k]) {
            const p = val[k].options.filter((op) => {
              return op.value.includes(this.value[k])
            })
            this.control[k] = p[0].label
            this.value[k] = p[0].value
          }
        }
      },
      deep: true
    }
  },
  computed: {
    formValue() {
      const value = JSON.parse(JSON.stringify(this.value))
      for (const k in value) {
        if (value[k].includes('全部') || !value[k]) delete value[k]
      }
      return value
    }
  },
  mounted() {
    for (const k in this.screenArr) {
      this.$set(this.value, k, this.screenArr[k].value)
    }
  },
  activated() {
    document.querySelector('body').setAttribute('style', 'overflow:hidden;')
  },
  deactivated() {
    document.querySelector('body').setAttribute('style', '')
  },
  methods: {
    changeValue(e, prop) {
      const el = this.screenArr[prop]
      // 下拉框
      if (el.options && el.options.length) {
        if (e) {
          el.options.forEach((op) => {
            if (op.value == e) {
              this.control[prop] = op.label
            }
          })
        } else {
          // 点击清除 x
          this.control[prop] = ''
        }
      }
      this.$emit('changeScreenValue', this.formValue)
    },
    resetValue() {
      // 重置为默认值
      for (const k in this.screenArr) {
        const el = this.screenArr[k]
        if (el.options && el.options.length && el.value) {
          const p = el.options.filter((op) => {
            return op.value.includes(el.value)
          })
          this.value[k] = p[0].value
          this.control[k] = p[0].label
        } else {
          this.value[k] = ''
          this.control[k] = ''
        }
      }
      this.$emit('changeScreenValue', this.formValue)
    }
  }
}
</script>

<style scoped lang="scss">
.marl-10 {
  margin-left: 10px;
}
.screen {
  width: 100%;
  font-size: 16px;

  &.has-screen {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 44px;
  }

  &.not-screen {
    height: 30px;
  }

  .screen-label {
    font-weight: bold;

    .title {
      color: #333333;
    }
    .num {
      color: $theme-color;
    }
  }

  .screen-item {
    position: absolute;
    top: 0;
    right: 0;
    display: flex;
    align-items: center;

    .screen-search {
      display: flex;
      align-items: center;
      width: 300px;

      ::v-deep .el-input__inner {
        padding-left: 12px;
        width: 100%;
        height: 32px;
        line-height: 32px;
        border: 1px solid #e5e5e5;
        color: #333333;
        border-radius: 4px 0px 0px 4px;
        // outline: none;

        &::placeholder {
          color: #999999;
        }
        &:hover {
          border-color: $theme-color;
        }
      }
    }

    .select-box {
      position: relative;
      min-width: 103px;
      height: 32px;
      line-height: 32px;

      ::v-deep {
        .el-select {
          position: absolute;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;

          .el-input__inner {
            &::placeholder {
              color: #999999;
            }
          }
          &:hover .el-input__inner {
            border-color: $theme-color !important;
          }
          &:focus .el-input__inner {
            border-color: $theme-color !important;
          }
          .el-select-dropdown {
            position: absolute !important;
            transform: translateX(-5px);
          }
          .el-input--small .el-input__inner {
            padding-left: 12px;
            height: 32px;
            color: #333;
            border-color: #e5e5e5;
          }
          .el-icon-arrow-up:before {
            content: '\e6e1' !important;
            color: #999999;
            font-weight: unset !important;
            font-size: 14px;
          }
        }
      }

      .control-width {
        display: inline-block;
        min-width: 103px;
        height: 32px;
        line-height: 32px;
        padding: 0 35px 0 12px;
        font-size: 14px;
        color: #333333;
        border-radius: 4px;
        border: 1px solid #e5e5e5;
      }
    }
  }
}
.cu-select-build {
  .el-select-dropdown__item.selected {
    color: #3083eb;
    font-weight: unset;
  }
}

::v-deep .el-button {
  width: 60px;
  height: 32px;
  line-height: 1;
  background: $theme-color;
  border-radius: 0px 4px 4px 0px;

  &.search {
    position: relative;
    width: 40px;
    .search_icon {
      position: absolute;
      top: 9px;
      left: 12px;
      width: 14px;
      height: 14px;
    }
  }
  &.screen-reset {
    color: $theme-color;
    background: #edf5ff;
    border: none;
    border-radius: 4px;
  }
}
</style>

<DetailsTableScreen subtitle="企业资质"
            		:num="qualification.total"
            		:screen-arr="qualificationScreen"
            		@changeScreenValue="changeQualificationScreen">
</DetailsTableScreen>

qualificationScreen: {
	keyword: { value: '', type: 'input', placeholder: '请输入资质名称' },
    qualificationCategory: { value: '', type: 'single-select', placeholder: '资质类别', options: [] }
}
changeQualificationScreen(v) { }

6、el-table表格合并

6.1示例详解

“饿了么”官网 对于 表格合并列或行 三言两语就解释完了??研究完做个简单的记录

在这里插入图片描述

通过给table传入span-method方法可以实现合并行或列,方法的参数是一个对象,里面包含当前行row、当前列column、当前行号rowIndex、当前列号columnIndex四个属性。该函数可以返回一个包含两个元素的数组,第一个元素代表rowspan,第二个元素代表colspan。 也可以返回一个键名为rowspan和colspan的对象。

<el-table :data="tableData" :span-method="objectSpanMethod">
   <el-table-column prop="id" label="ID"  width="180"> </el-table-column>
   <el-table-column prop="name" label="姓名"></el-table-column>
   <el-table-column prop="amount1" label="数值 1(元)"></el-table-column>
   <el-table-column prop="amount2" label="数值 2(元)"></el-table-column>
   <el-table-column prop="amount3" label="数值 3(元)"></el-table-column>
</el-table>
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
  if (columnIndex === 0) { // 第一列
    if (rowIndex % 2 === 0) { // 偶数行
      return { // 该单元格隐藏:跨两行、列不变
        rowspan: 2,
        colspan: 1
      };
    } else { // 奇数行
      return { // 该单元格:隐藏
        rowspan: 0,
        colspan: 0
      };
    }
    // { rowspan: 1,colspan:1 } 该单元格:照常显示
  }
}

在这里插入图片描述

6.2使用方法

需求: 表格数据需要做合并处理
我的方法:
1、每条数据添加一个celShow对象
对象属性"0" 、"1"表示第几列,rowIndex表示第几行,type里写合并或隐藏的类型
tableTitle说明方法
2、在objectSpanMethod里 拿到 每条数据的row.celShow[columnIndex].type

celShow: {
    "0": {
        rowIndex: 1,
        type: { rowspan: 2, colspan: 1 }
    },
    "1": {
        rowIndex: 1,
        type: { rowspan: 2, colspan: 1 }
    },
    "2": {
        rowIndex: 1,
        type: { rowspan: 2, colspan: 1 }
    },
    "3": {
        rowIndex: 1,
        type: { rowspan: 2, colspan: 1 }
    }
}

objectSpanMethod({ row, column, rowIndex, columnIndex }) {
  if (row.celShow[columnIndex]) {
    return row.celShow[columnIndex].type
  }
}

在这里插入图片描述
在这里插入图片描述

三、十一期

1、巧用捕获事件 @click.capture

<div class="content">
  <div class="left-title">
     <span>发布时间:</span>
   </div>
   <div class="role" @click.capture="clickByhand()">
     <commonScreen
       ref="yearScreen"
       components-type="year"
       :multiple="false"
       default-value-not-first
       :options="dayOptions"
       :checked-item="checkedYear"
       :current-value="currentTime"
       :current-time="currentTime"
       drop-type="usualYears"
       time-rang-type
       v-bind="$attrs"
       v-on="$listeners"
       @yearChange="yearChange"></commonScreen>
   </div>
 </div>

1、三角形阴影

&::before {
  content: '';
   position: absolute;
   display: inline-block;
   top: -8px;
   left: 22px;
   width: 0;
   height: 0;
   border-left: 7px solid transparent;
   border-right: 7px solid transparent;
   border-bottom: 7px solid #eee;
 }
 &::after {
   content: '';
   position: absolute;
   display: inline-block;
   top: -6.6px;
   left: 22px;
   width: 0;
   height: 0;
   border-left: 7px solid transparent;
   border-right: 7px solid transparent;
   border-bottom: 7.5px solid #ffffff;
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值