工作台笔记
一、企业数据库优化
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和
attrs和listeners的方式
https://zhuanlan.zhihu.com/p/388016979
爷爷.vue
父.vue(v-bind=“
a
t
t
r
s
"
、
v
−
o
n
=
"
attrs"、v-on="
attrs"、v−on="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;
}