基于Vue2的ElementUI组件总结
element
A Vue.js 2.0 UI Toolkit for Web
项目地址:https://gitcode.com/gh_mirrors/eleme/element
免费下载资源
·
基于Vue2的ElementUI组件总结
主要包括以下组件
穿梭框组件
一、树形穿梭框组件
因为项目需求是: 穿梭框左右两边数据都是树形结构。所以ElementUI和Ant Design Vue 本身自带的穿梭框已经不再适配项目需求。所以需要使用第三方穿梭框插件el-tree-transfer
1、使用方法
- 安装el-tree-transfer依赖
npm i -S el-tree-transfer
- 具体使用
<template>
<div>
<!--
openAll: 开启全部自动打开
node_key="id" 唯一标志 没体会到有啥用
title : 左右两边数据的名称 Array
:from_data : 保存左边树结构数据 必须含有pid 且如果parentId为null,则需要设置pid为0
:to_data : 保存右边的树结构数据 必须含有pid 且如果parentId为null,则需要设置pid为0
(pid一般是后端返回的parentId,需要前端处理,方法有:1、加属性(可参考其他博主);2、递归遍历,添加属性)
:defaultProps="{ label: 'name' }" 设置默认属性 展示的名字的字段
:mode="mode" 模式 mode指的是 穿梭框
filter : 开启自带的过滤功能
@add-btn="add" 左边数据移向右侧
@remove-btn="remove" 右侧数据移向左侧
// 左右数据复选框触发事件(不包括全选框)
// 解决过滤后全选导致的bug
@left-check-change="onLeftChange"
@right-check-change="onRightChange"
-->
<tree-transfer
node_key="id"
:title="tit"
ref="transfer"
:from_data="fromData"
:to_data="toData"
:defaultProps="{ label: 'name' }"
:mode="mode"
filter
height="487px"
@add-btn="add"
@remove-btn="remove"
@left-check-change="onLeftChange"
@right-check-change="onRightChange"
class="permission__tree-transfer">
</tree-transfer>
</div>
</template>
<script>
// 局部引入
import treeTransfer from 'el-tree-transfer'
export default {
// 注册组件
components: {
treeTransfer
},
props: {
// 后端接口返回的左侧数据
fromData: {
type: Array
},
// 后端接口返回的右边数据
toData: {
type: Array
},
// 父组件传的穿梭框标题
tit: {
type: Array
},
// 已选用户
selectedUsers: {
type: Object
},
// 当前角色
currentRoleType: {
type: String
}
},
watch: {
fromData: {
handler() {
if (this.fromData && this.fromData.length > 0) {
if (this.tit[0] === "可选用户") {
this.dealUserRoleTypeTreeData(this.fromData);
} else {
this.dealSourceTreeData(this.fromData);
}
}
},
// immediate : true
}
},
data() {
return {
// 树形穿梭框数据
mode: 'transfer', // 现有树形穿梭框模式transfer 和通讯录模式addressList
// title: ['可选资源', '已选资源'],
selectedKeys: [], // 选择的keys
removedKeys: [], // 移除的keys
saveSelectedSourceIds: [], // 保存已选资源的底层id
}
},
methods: {
// 当el-traee-transfer onLeftChange onRightChange 搜索过滤后选择全选进行穿梭发现把原数据都带过去了,而不是搜索出来的。
onLeftChange(nodeObj, treeObj) {
this.filterNotDisabled(this.fromData);
const treeTransfer = this.$refs.transfer.$refs['wl-transfer-component'];
const fromTree = treeTransfer.$refs['from-tree'];
const fromTreeCheckedKeys = fromTree.getCheckedKeys(true);
const _fromTreeCheckedKeys = fromTreeCheckedKeys.filter(node => {
return fromTree.getNode(node).visible;
});
fromTree.setCheckedKeys(_fromTreeCheckedKeys);
},
onRightChange(nodeObj, treeObj) {
const treeTransfer = this.$refs.transfer.$refs['wl-transfer-component'];
const toTree = treeTransfer.$refs['to-tree'];
const toTreeCheckedKeys = toTree.getCheckedKeys(true);
const _toTreeCheckedKeys = toTreeCheckedKeys.filter(node => {
return toTree.getNode(node).visible;
});
toTree.setCheckedKeys(_toTreeCheckedKeys);
},
// 全选时 过滤出 禁止选中的节点被右移
filterNotDisabled(nodeArr) {
// 因为this.selectedKeys只会push 没有children的node 所以只需要过滤一级
// return nodeArr.filter(item => item.disabled !== true);
nodeArr.forEach(item=>{
if(item.disabled && item.checked) {
item.checked = false;
}
});
console.log(nodeArr);
},
add(fromData, toData, obj) {
if (this.tit[0] === "可选用户") {
// let notDisabled = this.filterNotDisabled(obj.nodes);
// console.log(notDisabled,'notDisabled');
if (obj.nodes && obj.nodes.length > 0) {
obj.nodes.forEach(item => {
if (!(item.children && item.children.length > 0)) {
this.selectedKeys.push(item.id);
}
})
}
} else {
// 分配资源
// harfKeys 存储所有父级
// this.selectedKeys = [...obj.harfKeys,...obj.keys];
this.selectedKeys.push(...obj.harfKeys, ...obj.keys);
// this.selectedKeys = this.filterArr(this.selectedKeys);
}
},
remove(fromData, toData, obj) {
if (this.tit[0] === "可选用户") {
if (obj.nodes && obj.nodes.length > 0) {
obj.nodes.forEach(item => {
if (!(item.children && item.children.length > 0)) {
this.removedKeys.push(item.id);
}
})
}
this.dealUserTreeData(this.fromData);
} else {
// 分配资源
this.removedKeys.push(...obj.keys);
// this.removedKeys = this.filterArr(this.removedKeys);
this.dealSourceTreeData(this.fromData);
}
this.$message.success("移除成功!");
// 将之前已经选中的 移除到左边 左边禁用的 需要重新 可选
console.log(this.removedKeys, '移除成功!', obj);
},
// 触发remove事件时,从右边移除到左边时,改变被操作的数据的禁用状态
dealUserTreeData(treeData) {
treeData && treeData.length > 0 && treeData.forEach(item => {
if (item.children && item.children.length > 0) {
this.dealUserTreeData(item.children);
} else {
// 这块逻辑必须和过滤系统、业务的 规则 区别开
// 右边移除到左边的数据可以再次点击
if (this.toData && this.toData.length > 0) {
let ids = this.toData.map(toItem => toItem.id);
// this.collectBottomIds(this.toData);
if (ids.includes(item.id)) {
item.disabled = true;
} else {
item.disabled = false;
}
} else {
item.disabled = false;
}
}
})
},
// 根据不同角色类型处理 已选角色的是否禁用状态
dealUserRoleTypeTreeData(treeData) {
treeData && treeData.length > 0 && treeData.forEach(item => {
if (item.children && item.children.length > 0) {
this.dealUserRoleTypeTreeData(item.children);
} else {
// 系统或者业务已选的禁用规则
if (this.currentRoleType === "系统") {
this.selectedUsers.SYSTEM && this.selectedUsers.SYSTEM.length > 0 && this.selectedUsers.SYSTEM.forEach(sysItem => {
if (sysItem.sysUserId === item.id) {
item.disabled = true;
}
});
this.selectedUsers.BUSINESS && this.selectedUsers.BUSINESS.length > 0 && this.selectedUsers.BUSINESS.forEach(sysItem => {
if (sysItem.sysUserId === item.id) {
item.disabled = true;
}
});
} else if (this.currentRoleType === "业务") {
this.selectedUsers.SYSTEM && this.selectedUsers.SYSTEM.length > 0 && this.selectedUsers.SYSTEM.forEach(sysItem => {
if (sysItem.sysUserId === item.id) {
item.disabled = true;
}
});
}
}
})
},
dealSourceTreeData(treeData) {
treeData && treeData.length > 0 && treeData.forEach(item => {
if (item.children && item.children.length > 0) {
this.dealSourceTreeData(item.children);
} else {
if (this.toData && this.toData.length > 0) {
this.saveSelectedSourceIds = []; // 这块需要清空
this.collectBottomIds(this.toData);
if (this.saveSelectedSourceIds.includes(item.id)) {
item.disabled = true;
} else {
item.disabled = false;
}
} else {
item.disabled = false;
}
}
})
},
// 收集已选资源底层id
collectBottomIds(treeData) {
treeData.forEach(item => {
if (item.children && item.children.length > 0) {
this.collectBottomIds(item.children);
} else {
this.saveSelectedSourceIds.push(item.id);
}
});
}
}
}
</script>
<style>
/*处理自带的穿梭触发按钮样式 开始*/
.wl-transfer .transfer-center {
left: 48% !important;
width: auto !important;
}
.wl-transfer .transfer-left,
.wl-transfer .transfer-right {
width: 44% !important;
}
.el-button.is-circle {
border-radius: 0 !important;
width: 25px !important;
height: 32px !important;
padding: 0px !important;
}
.transfer-center-item {
width: 25px !important;
height: 32px !important;
text-align: center;
line-height: 32px;
padding: 0px !important;
}
/*处理自带的穿梭触发按钮样式 结束*/
/* 取消穿梭框的 全选复选框 */
/* .permission__tree-transfer.wl-transfer .transfer-title .el-checkbox {
display: none;
} */
</style>
- 注意事项
1、左右两侧的数据必须添加属性值和parentId属性值一样的pid属性,否则渲染失败;且如果parentId为null,则需要设置pid为0
2、过滤后,全选操作的bug处理(上面代码可见)
3、点击全选后,是可以选中前端处理禁用的数据的,所以这块再次禁用的,不可选中的数据需要后端接口过滤掉。(这块有过同样问题的兄弟可以一起探讨下。其实也可以改源码,我没找到~)
- 递归处理接口数据,添加pid
dealTreeData(treeData) {
treeData && treeData.length > 0 && treeData.forEach(item=>{
if(item.children && item.children.length > 0) {
if(item.parentId === null || item.parentId === "null") {
item.pid = 0;
} else {
item.pid = item.parentId;
}
this.dealTreeData(item.children);
} else {
if(item.parentId === null || item.parentId === "null") {
item.pid = 0;
} else {
item.pid = item.parentId;
}
}
})
},
树组件
一、改变树组件自带的展开收缩图标
1、效果图如下
2、代码如下
/* // 树形列表 */
.el-tree .el-tree-node__expand-icon.expanded {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
/* //有子节点 且未展开 */
.el-tree .el-icon-caret-right:before {
/* background: url("./assets/img/add-icon.png") no-repeat 0 3px; */
content: "+";
display: block;
width: 18px;
height: 18px;
font-size: 16px;
background-size: 16px;
border-radius: 50%;
border: 1px solid #999;
display: flex;
justify-content: center;
align-items: center;
font-weight: 700;
}
/* //有子节点 且已展开 */
.el-tree .el-tree-node__expand-icon.expanded.el-icon-caret-right:before {
/* background: url("./assets/img/jian-icon.png") no-repeat 0 3px; */
content: "-";
display: block;
width: 18px;
height: 18px;
font-size: 16px;
background-size: 16px;
border-radius: 50%;
border: 1px solid #999;
display: flex;
justify-content: center;
align-items: center;
font-weight: 700;
/* color: #1890FF; */
}
/* //没有子节点 */
.el-tree .el-tree-node__expand-icon.is-leaf::before {
background: transparent no-repeat 0 3px;
content: "";
display: block;
width: 0px;
height: 0px;
font-size: 0px;
background-size: 0px;
border: none;
/* margin-left: 16px; */
}
二、树组件不同层级的不同样式展示
1、效果图如下
2、代码如下
<el-tree node-key="id" ref="geoFileTree" :data="fileTreeData" :props="defaultProps"
class="file_tree">
<div class="file_tree-node" slot-scope="{ node, data }" style="width: 100%;">
<div v-if="node.level === 1 || node.level === 2" style="display: flex;align-items: center;">
<img src="../../assets/img/geoProjectPreview/first_level.png" alt="">
<span style="color: #595959;font-weight: 700;margin-left:6px;">{{ node.label }}</span>
</div>
<div class="file-item" v-if="node.level !== 1 && node.level !== 2"
style="display: flex;align-items: center;justify-content: space-between;">
<div v-if="data.children">
<img src="../../assets/img/geoProjectPreview/folder.png" alt="">
<span style="margin-left:6px;">{{ node.label }}</span>
</div>
<div v-if="data.coverUrl" @click="newWindowOpen(data.coverUrl)" class="file-name">
<img v-if="!data.coverUrl.includes('.JPG')"
src="../../assets/img/geoProjectPreview/file_icon.png" alt="">
<img v-if="data.coverUrl.includes('.JPG')"
src="../../assets/img/geoProjectPreview/img_icon.png" alt="">
<span style="margin-left:6px;">{{ node.label }}</span>
</div>
<div v-if="node.level === 3 || data.coverUrl"
style="flex: 1;border-bottom: 1px dashed #C4C4C4;margin: 0px 32px;"></div>
<div v-if="node.level === 3">{{ data.createTime }}</div>
<div @click="checkFileInfo(data)" class="file-info" v-if="data.coverUrl">详情</div>
</div>
</div>
</el-tree>
三、通过点击外部按钮,实现树结构的不同层级或者所有层级的收缩和展开
1、效果图如下
2、实现代码如下
//遍历树的所有子节点,展开的时候给子节点展开状态赋值true,折叠时候赋值false
buildData(level = 0) {
this.$nextTick(() => {
// geoFileTree : 绑定到树组件上的ref值
const nodeArr = this.$refs.geoFileTree.store._getAllNodes();
for (let i = 0; i < nodeArr.length; i++) {
if (level === 0) {
// 全部折叠
nodeArr[i].expanded = false;
} else if (level === "all") {
// 全部展开
nodeArr[i].expanded = true;
} else if (level === "1") {
// 第一级展开
nodeArr[i].expanded = nodeArr[i].level === 1;
} else if (level === "2") {
// 第二级展开
nodeArr[i].expanded = nodeArr[i].level === 1 || nodeArr[i].level === 2;
}
}
});
},
GitHub 加速计划 / eleme / element
54.06 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:3 个月前 )
c345bb45
7 个月前
a07f3a59
* Update transition.md
* Update table.md
* Update transition.md
* Update table.md
* Update transition.md
* Update table.md
* Update table.md
* Update transition.md
* Update popover.md 7 个月前
更多推荐
已为社区贡献3条内容
所有评论(0)