技术标签: 前端 vue.js javascript
1.统一样式,通过slot插槽而非json配置项的形式,来兼容原有table的template写法,方便改造
2.列的显示隐藏控制,默认根据接口数据是否有返回绑定prop对应的字段,来实现列的权限控制显隐,也可通过外部传tableHeader来自行控制
3.合并分页器
<!--
* @Description: 公共table组件,可含分页器
* @使用方法:将<el-table>标签名替换为<my-table>即可, v-loading 指令需改为 :loading 绑定,其他所有属性方法的绑定和使用都和element-plus的table一致
* @个别事项:
1. 使用分页器需绑定 showPagination, 并传一个json配置参数 paginationConfig, 除了 @size-change 和 @current-change 两个方法直接绑定在table上外,分页器的其他原有属性统一加到 paginationConfig
2. tableHeader:默认只会渲染显示列表接口有返回的字段对应的prop列, 传了 tableHeader 则只会渲染 tableHeader 里有定义的字段列
* @例:
<my-table
:loading="loading"
:data="data"
@selection-change="selectTableChange"
@cell-click="selectRowFun"
:multipleSelection="multipleSelection"
showPagination
:paginationConfig="paginationConfig"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
<el-table-column type="selection" width="55" />
<el-table-column prop="name" label="姓名" width="150"></el-table-column>
<el-table-column prop="ages" label="年龄" width="150"></el-table-column>
<my-table/>
-->
<template>
<el-table
v-bind="$attrs"
ref="table"
v-loading="loading"
:data="data"
:max-height="maxHeight"
:paginationConfig="null"
>
<children :key="key" />
</el-table>
<div class="operation-bar">
<div class="left-operation">
<div class="checkedCount" v-if="showCheckedCount">已选 {
{
multipleSelection.length }} 项</div>
<div class="operation-box">
<slot name="operation"></slot>
</div>
</div>
<div class="right-pagination">
<pagination v-if="showPagination" :pageConfig="_paginationConfig" @size-change="pageSizeChange" @current-change="currentPageChange" />
</div>
</div>
</template>
<script lang="ts" setup>
import {
cloneVNode,
Component,
computed,
reactive,
ref,
VNode,
readonly,
useSlots,
defineExpose,
watch,
defineProps,
defineEmits,
useAttrs,
nextTick,
onMounted,
onBeforeUnmount,
} from 'vue'
import pagination from './pagination.vue' // 分页组件
// import useVirtualScroll from './useVirtualScroll'
const props = defineProps({
loading: {
type: Boolean,
default: false,
},
maxHeight: {
type: [String, Number],
default: 720,
},
data: {
type: Array,
default: () => []
},
// 显示已选数量
showCheckedCount: {
type: Boolean,
default: false,
},
// 绑定的已选项数组
multipleSelection: {
type: Array,
default: () => []
},
// 可见的字段表头 ['filed1', 'filed2', 'filed3']
tableHeader: {
type: Object,
default: () => []
},
// 关闭自适应列宽 (用于解决列数小于3的表格在渲染时会出现数据抖动)
closeAutoCloumnWidth: {
type: Boolean,
default: false
},
// 使用分页器
showPagination: {
type: Boolean,
default: false
},
// 分页配置
paginationConfig: {
type: Object,
default: () => {
return {
total: 0,
currentPage: 1,
pageSize: 10,
pageSizes:[10, 30, 50, 100, 200, 500]
}
},
},
})
const emit = defineEmits([
"currentChange",
"sizeChange",
]);
interface IMyTableColumnProps {
prop?: string
label?: string
fixed?: 'left' | 'right' | boolean
visiable?: boolean
index?: boolean
}
function isElTableColumn(vnode: VNode) {
return (vnode.type as Component)?.name === 'ElTableColumn'
}
const table = ref()
let tableHeader:any = {
}
let headerCount: number = 0
const slotsOrigin = useSlots()
const attrs:any = useAttrs()
const slots = computed(() => {
/* 对 slot 进行分类 */
const main: VNode[] = [] // ElTableColumn 且存在 prop 属性
const left: VNode[] = [] // ElTableColumn 不存在 prop 属性,但 fixed="left" 或者为 selection选框
const other: VNode[] = [] // 其他
// 权限控制的可见列字段
let showKeys: string[] = [];
// 方式一:只显示接口返回的字段判断 (设置了字段可见权限,接口不会返回该相关字段)
if(props.data && props.data.length){
let tableDataItem: any = props.data[0]
showKeys = Object.keys(tableDataItem)
}
let isNullData = showKeys.length || props.tableHeader ? false : true; // 空数据时正常渲染表头
// 方式二:用外部传来的表头字段
console.log('外部props.tableHeader', props.tableHeader)
if(props.tableHeader){
tableHeader = JSON.parse(JSON.stringify(props.tableHeader));
}
if(JSON.stringify(tableHeader) !== '{}'){
showKeys = Object.keys(tableHeader).map(v=>v.replace(/^./, (L) => L.toLowerCase())) // 首字母转小写
}
slotsOrigin.default?.()?.forEach((vnode, index) => {
if(!vnode.props){
vnode.props = {
}
}
vnode.props.index = index; // 排序
if (isElTableColumn(vnode)) {
if(vnode.props && vnode.props.prop){
if(!isNullData){
vnode.props.visiable = showKeys.indexOf(vnode.props.prop) === -1 ? false : true;
}
// 构建可见列表头并缓存起来
if(props.data && vnode.props.visiable){
tableHeader[vnode.props.prop] = vnode.props.label
}else{
delete tableHeader[vnode.props.prop]
}
}
const {
prop, fixed, type } = vnode.props ?? {
}
if (prop !== undefined) return main.push(vnode)
// if (type === 'selection' && vnode.props) vnode.props.reserveSelection = true;
if (fixed === 'left' || type === 'selection') return left.push(vnode)
}
other.push(vnode)
})
console.log('实际tableHeader',tableHeader)
// 可见内容列少于3列则自适应宽度, 防止列数过少时撑不满table宽度出现断层
let showMain = main.filter(v=>{
return v.props && v.props.visiable !== false});
if(!props.closeAutoCloumnWidth && showKeys.length && showMain.length < 3){
main.forEach(vnode=>{
if(vnode.props) vnode.props.width = ''
})
key.value++
}
if(!props.closeAutoCloumnWidth && !showMain.length && other.length && other[0].props){
other[0].props.width = ''
key.value++
}
return {
main,
left,
other,
}
})
/* 列的排序与部分属性 */
const columns = reactive({
// slot 中获取的
slot: computed(() =>
slots.value.main.map(({
props }) => ({
prop: props!.prop,
label: props!.label,
fixed: props!.fixed,
visiable: props!.visiable ?? true,
}))
),
// 渲染使用的
render: computed(() => {
const res: IMyTableColumnProps[] = []
const slot = [...columns.slot]
res.push(...slot)
return res
}),
})
/* 重构 slot.main */
const refactorSlot = computed(() => {
const {
main } = slots.value
/* 对 slot.main 进行改写 */
const refactorySlot: VNode[] = []
columns.render.forEach(({
prop, visiable, fixed }) => {
if (!visiable) return
const vnode = main.find((vnode) => prop === vnode.props?.prop)
if (!vnode) return
const cloned = cloneVNode(vnode, {
fixed,
})
refactorySlot.push(cloned)
})
return refactorySlot
})
/* 强制更新 el-table-column */
const key = ref(0)
watch(refactorSlot, () => {
if(Object.keys(tableHeader).length !== headerCount){
// 初始表头已构建好则无需更新,否则数据刷新时会抖动闪烁
headerCount = Object.keys(tableHeader).length;
key.value += 1
nextTick(()=>{
table.value.doLayout()
})
}
})
/* 对外暴露的内容 */
defineExpose({
table, // el-table 实例的访问
columns: computed(() => readonly(columns.render)),
updateColumns(value: IMyTableColumnProps[]) {
},
})
const children = () => [...slots.value.left, ...refactorSlot.value, ...slots.value.other].sort((a: any, b: any)=>a.props.index - b.props.index)
console.log(children())
// 合并分页配置
const _paginationConfig = computed(() => {
const config = {
total: 0,
currentPage: 1,
pageSize: 10,
pageSizes: [10, 30, 50, 100, 200, 500],
layout: "total, sizes, prev, pager, next, jumper",
};
return Object.assign(config, props.paginationConfig);
});
// 切换分页
const currentPageChange = (pageIndex: number) => {
emit("currentChange", pageIndex);
}
const pageSizeChange = (pageSize: number) => {
emit("sizeChange", pageSize);
}
// 虚拟滚动
// const { visibleData, initVirtualScroll, handleSelectionAll, addListeners, removeListeners, getRowKeys} = useVirtualScroll();
// watch(()=>props.data, ()=>{
// initVirtualScroll(table, JSON.parse(JSON.stringify(props.data)))
// })
// onMounted(()=>{
// addListeners()
// })
// onBeforeUnmount(()=>{
// removeListeners()
// })
</script>
<style lang="less" scoped>
.operation-bar{
display: flex;
justify-content: space-between;
align-items: flex-end;
.left-operation{
text-align: left;
.checkedCount{
// padding-left: 10px;
font-size: 14px;
font-weight: 400;
color: #606266;
padding: 10px 0 10px 10px;
}
}
}
</style>
<template>
<el-pagination v-bind="pageConfig"></el-pagination>
</template>
<script lang="ts" setup>
import {
defineProps } from "vue";
defineProps({
pageConfig: {
type: Object,
default: () => ({
})
}
})
</script>
文章浏览阅读8k次,点赞2次,收藏6次。QT设置QLabel中字体的颜色其实,这是一个比较常见的问题。大致有几种做法:一是使用setPalette()方法;二是使用样式表;三是可以使用QStyle;四是可以在其中使用一些简单的HTML样式。下面就具体说一下,也算是个总结吧。第一种,使用setPalette()方法如下:QLabel *label = new QLabel(tr("Hello Qt!"));QP_qolable 字体颜色
文章浏览阅读3.7k次。使用C# 作为开发语言,将pb文件转换为cs文件的时候相信很多人都会遇到一个很棘手的问题,那就是protoc3环境下,import Timestamp的问题,在头部 import “google/protobuf/timestamp.proto”;的时候会抛异常:google/protobuf/timestamp.proto" was not found or had errors;解决办法【博主「pamxy」的原创文章的分享】:(注:之后才发现,不需要添加这个目录也可以,因为timestamp.p_import "google/protobuf/timestamp.proto" was not found or had errors.
文章浏览阅读4.1w次,点赞9次,收藏98次。一、准备工具: 1. app:VNET(抓包用)、京东; 安卓手机需要下载VNET软件。下载官网:https://www.vnet-tech.com/zh/ 2. 已安装部署好的青龙面板;二、抓包wskey: 1. 打开已下载的VNET软件,第一步先安装CA证书; 点击右下角三角形按钮(开始抓包按钮),会提示安装证书,点击确定即可,app就会将CA证书下载至手机里,随后在手机设置里进行安装,这里不同手机可能安装位置不同,具体..._jd_wsck
文章浏览阅读2.9k次,点赞7次,收藏3次。本文针对mybatis-plus自动填充第一次更新能正常填充,第二次更新无法自动填充问题。????mybatis-plus自动填充:当要填充的字段不为空时,填充无效问题的解决????先上一副官方的图:取自官方:https://mp.baomidou.com/guide/auto-fill-metainfo.html第三条注意事项为自动填充失效原因:MetaObjectHandler提供的默认方法的策略均为:如果属性有值则不覆盖,如果填充值为null则不填充以官方案例为例:```java_mybatisplus插入不放为空的字段
文章浏览阅读1w次,点赞25次,收藏94次。利用 Application Complier 完成MATLAB转exe文件_matlab exe
文章浏览阅读137次。近期项目需要研究paypal支付,官网上的指导写的过于复杂,可能是老外的思维和中国人不一样吧。难得是发现下面这篇文章:http://www.androidhive.info/2015/02/Android-integrating-paypal-using-PHP-MySQL-part-1/在这篇文章的基础上,查看SDK简化了代码,给出下面这个例子,..._paypal支付集成到anroid应用中
文章浏览阅读2.3k次,点赞29次,收藏52次。nuScenes 数据集 (pronounced /nu:ːsiː:nz/) 是由 Motional (以前称为 nuTonomy) 团队开发的自动驾驶公共大型数据集。nuScenes 数据集的灵感来自于开创性的 KITTI 数据集。nuScenes 是第一个提供自动驾驶车辆整个传感器套件 (6 个摄像头、1 个 LIDAR、5 个 RADAR、GPS、IMU) 数据的大型数据集。与 KITTI 相比,nuScenes 包含的对象注释多了 7 倍。_nuscense数据集
文章浏览阅读535次。我正在实现一个程序,该程序可以侦听特定主题,并在ESP8266发布新消息时对此做出反应.从ESP8266收到新消息时,我的程序将触发回调并执行一系列任务.我在回调函数中发布了两条消息,回到了Arduino正在侦听的主题.但是,仅在函数退出后才发布消息.谢谢您的所有宝贵时间.我试图在回调函数中使用loop(1),超时为1秒.该程序将立即发布该消息,但似乎陷入了循环.有人可以给我一些指针如何在我的回调..._python 函数里面 mqtt调用publish方法 没有效果
文章浏览阅读3.4w次,点赞16次,收藏81次。微软出来了win11预览版系统,很多网友给自己的电脑下载安装尝鲜,不过因为是测试版可能会有比较多bug,又只有英文,有些网友使用起来并不顺畅,因此想要将win11退回win10系统。那么win11怎么装回win10系统呢?今天小编就教下大家win11退回win10系统的方法。方法一:1、首先点击开始菜单,在其中找到“设置”2、在设置面板中,我们可以找到“更新和安全”3、在更新和安全中,找到点击左边栏的“恢复”4、恢复的右侧我们就可以看到“回退到上版本的win10”了。方法二:_安装win10后卸载win11
文章浏览阅读3.3k次,点赞2次,收藏3次。数据定义_sql server菜鸟教程
文章浏览阅读1.9k次。1. 两数之和给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。示例:给定 nums = [2, 7, 11, 15], target = 9因为 nums[0] + nums[1] = 2 + 7 = 9所以返回 [0, 1]方法一..._给定一个浮点数数组nums(逗号分隔)和一个浮点数目标值target(与数组空格分隔),请
文章浏览阅读152次。提高性能有如下方法1、Cython,用于合并python和c语言静态编译泛型2、IPython.parallel,用于在本地或者集群上并行执行代码3、numexpr,用于快速数值运算4、multiprocessing,python内建的并行处理模块5、Numba,用于为cpu动态编译python代码6、NumbaPro,用于为多核cpu和gpu动态编译python代码为了验证相同算法在上面不同实现..._np.array 测试gpu性能