这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战
TIP 👉 呜呼!楚虽三户能亡秦,岂有堂堂中国空无人!____陆游《金错刀行》
前言
Web Component是前端界一直非常热衷的一个领域,用第三方组件化的框架去实现的话,你需要依赖框架本身很多东西,很多时候我们只是简单的几个组件,不是很大,也不是很多,所以为了保证组件的`轻量,简单`,其实这个时候我们并不想采用第三方的框架。Tree 树形控件
import
建议用tree2数据,通用后端给的json数据
import Tree from '@/components/Tree/Tree2';
Props
1. treeData
- 类型:array (必填)
- 默认值:[]
- 说明:树形数据
2. iconFolder
- 类型:boolean (必填)
- 默认值:true / false
- 说明:是否有文件夹的折起标志
3. iconStyle
- 类型:boolean (必填)
- 默认值:true / false
- 说明:是否有加减的折起标志
4. canSelected
- 类型:boolean (必填)
- 默认值:true / false
- 说明:是否可勾选
5. clickNodeGetInfo
- 类型:func
- 默认值:无
- 说明:点击触发回调函数,入参如:
- {obj} node 触发树的某个节点
6. parentCodeName
- 类型:string (必填)
- 默认值:'parentCode'
- 说明:参照后端数据查找父节点值字段,不固定值
7. codeName
- 类型:string (必填)
- 默认值:'code'
- 说明:参照后端数据查找子节点值字段,不固定值
实现Tree.js
import React from 'react';
import './Tree.scss';
/**
* Tree 组件所传属性描述
* treeList 树的所有数据 arr
* onClick 点击树的执行方法 函数
* loadDataAction 动态加载数据 函数
*/
class Tree extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
node: props.treeList,
}
}
handleClick(e,item) {
let Oi = e.target.parentNode.childNodes[0]
;
// Oi.style.transform = Oi.style.transform == "rotate(-90deg)" ? "rotate(0deg)" : "rotate(-90deg)";
this.digui(this.state.node,item);
this.props.onClick && this.props.onClick(item);
this.props.loadDataAction && this.props.loadDataAction(item);
}
checkAction(item){
item.checked = !item.checked;
this.setState({
node : this.state.node
});
// console.log(item);
}
digui(node,item){
let newNode = node;
for(let i=0; i<newNode.length; i++){
if(newNode[i].key == item.key){
if(newNode[i].child){
if(item.open){
newNode[i].open = false;
}else{
newNode[i].open = true;
}
}
}else{
if(newNode[i].child){
this.digui(newNode[i].child,item);
}
}
console.log(newNode);
this.setState({
node : newNode
});
}
}
itemTitle(item){
// 这个是返回title,因为有时候是点击一个链接,所以设置了两种情况,如果node节点里面有component这个节点,那就设置成可以点击跳转
if(item.component){
return (<Link to={ item.component } >
<span className="" onClick={this.handleClick.bind(this)}>{item.title}</span>
</Link>)
}else{
return (
<span className="tree-span-title" onClick={(e)=>{this.handleClick(e,item)}}>{item.title}</span>
)
}
}
tree(child){
let treeItem;
// 如果有子元素
if(child){
// 子元素是数组的形式,把所有的子元素循环出来
treeItem = child.map((item, key) => {
// 同理,设置样式
let itemStyle = {
paddingLeft: 20*parseInt(item.level.slice(5)-1)+'px',
position:'relative'
};
let wrapperStyle = {
left: 5*parseInt(item.level.slice(5)-1)+'px',
};
// 同理,设置➡️
let iconChevron;
if(item.child){
if(item.open){
iconChevron = 'icon icon-xiangxiazuocedaohang';
}else{
iconChevron = 'icon icon-xiangyouzuocedaohang';
}
}else{
iconChevron = 'icon tree-icon';
}
return (
<ul key={key}>
<li className={item.level} style={itemStyle}>
{ this.props.loadDataAction ?
(
(!(item.child && item.child.length)) ?
<i className={iconChevron} onClick={(e)=>{this.handleClick(e,item)}}></i> :
(
this.props.notice ?
<i className="tree-empty">
<div className="wrapper" data-anim="base wrapper">
<div className="circle" data-anim="base left"></div>
<div className="circle" data-anim="base right"></div>
</div>
</i> :
<i className={iconChevron} onClick={(e)=>{this.handleClick(e,item)}}></i>
)
):
<i className={iconChevron} onClick={(e)=>{this.handleClick(e,item)}}></i>
}
{
this.props.type == 'check' &&
<em className={!item.checked ? "tree-checkbox" : "tree-checkbox checkedbox"} onClick={this.checkAction.bind(this,item)}>
<i className={!item.checked ? "tree-i" : "tree-i checkedi"}></i>
</em>
}
{this.itemTitle(item)}
</li>
{/* 如果当前子元素还有子元素,就递归使用tree方法,把当前子元素的子元素渲染出来 */}
{item.open && this.tree(item.child)}
</ul>
)
})
}
return treeItem;
}
render() {
return (
<div className="tree">
{/*{this.tree(this.state.node)}*/}
{this.tree(this.props.treeList)}
</div>
);
}
}
export default Tree;
样式这块就先不放了
「欢迎在评论区讨论」