element-ui源码分析:剖析el-tree源码,看看实现一个树组件有多么复杂(1)

elment-ui中tree木块相关文件如下图:

下图梳理一下各个文件之间的引用关系(箭头的方向表示使用)

1 uti.js

1.1 markNodeData 标记节点

export const NODE_KEY = '$treeNodeId';

export const markNodeData = function(node, data) {if (!data || data[NODE_KEY]) return;Object.defineProperty(data, NODE_KEY, {value: node.id,enumerable: false,configurable: false,writable: false});
}; 

定义常量NODE_KEY; 判断节点是否存在NODE_KEY 属性,存在则返回;否则使用Object.defineProperty定义节点的NODE_KEY 属性,属性是只读的。

1.2 getNodeKey 获取节点NODE_KEY属性

export const getNodeKey = function(key, data) {if (!key) return data[NODE_KEY];return data[key];
}; 

如果没有指定key, 则返回NODE_KEY 。

1.3 findNearestComponent 寻找最近的组件

export const findNearestComponent = (element, componentName) => {let target = element;while (target && target.tagName !== 'BODY') {if (target.__vue__ && target.__vue__.$options.name === componentName) {return target.__vue__;}target = target.parentNode;}return null;
}; 

如果target存在__vue__属性(代表对应的vue组件),并且组件名等于componentName则返回这个vue组件,否则向上判断target的父节点。

__vue__属性是在vue源码中定义的属性:

if (prevEl) {prevEl.__vue__ = null
}
if (vm.$el) {vm.$el.__vue__ = vm
} 

详见vue源码 (路径为: src\core\instance\lifecycle.js)

2.node.js分析

node.js中定义了Node类和获取子节点状态、重新初始化节点选中状态以及获取节点属性的方法,我们逐一了解一下:

2.1 getChildState 获取子节点状态

export const getChildState = node => {let all = true;let none = true;let allWithoutDisable = true;for (let i = 0, j = node.length; i < j; i++) {const n = node[i];if (n.checked !== true || n.indeterminate) {all = false;if (!n.disabled) {allWithoutDisable = false;}}if (n.checked !== false || n.indeterminate) {none = false;}}return { all, none, allWithoutDisable, half: !all && !none };
}; 

代码中的单词indeterminate表示“不确定的”,getChildState判断一个节点的子节点状态, all代表全部都勾选;none代表一个都没勾选;allWithoutDisable代表所有的都禁用;half表示有勾选的有没勾选的。

all, none, allWithoutDisable初始值全是true; 循环遍历子节点列表,如果有一个节点的checked不为true或者为indeterminate则all为false;如果某个节点没有禁用则allWithoutDisable为false; 如果某个节点勾选了或者indeterminate则none为假。

2.2 reInitChecked 根据子节点状态重置节点勾选状态

const reInitChecked = function(node) {if (node.childNodes.length === 0) return;const {all, none, half} = getChildState(node.childNodes);if (all) {node.checked = true;node.indeterminate = false;} else if (half) {node.checked = false;node.indeterminate = true;} else if (none) {node.checked = false;node.indeterminate = false;}const parent = node.parent;if (!parent || parent.level === 0) return;if (!node.store.checkStrictly) {reInitChecked(parent);}
}; 

如果子节点列表为空则直接返回;否则获取子节点状态进行判断:如果子节点全选了,那么设置当前节点为选中状态(checked为true, indeterminate为false);如果子节点为half即有选的有没选的则设置当前节点为不选中状态(checked为false, indeterminate为true);如果子节点全都没选中,则设置当前节点为不选中状态(checked为false, indeterminate为false)。

设置完当前节点后则要处理当前节点的父节点,如果父节点不存在或者层级为第0层(根节点)则返回,否则判断父子节点之间是否严格不关联,如果不是的话,则递归检查父节点。关于checkStrictly,文档中有如下说明:

下图reInitChecked方法的调用关系(箭头方向表示被调用):

2.3 getPropertyFromData从数据中获取属性

const getPropertyFromData = function(node, prop) {const props = node.stor
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个使用element-ui的v-for循环el-form-item的组件代码示例: ```vue <template> <el-form> <el-form-item v-for="(field, index) in fields" :key="index" :label="field.label"> <el-input v-model="field.value" :placeholder="field.placeholder"></el-input> </el-form-item> </el-form> </template> <script> export default { props: { fields: { type: Array, required: true, default: () => [], }, }, }; </script> ``` 在上述代码中,我们使用了一个props属性来接收一个名为fields的数组,该数组中包含了每个表单项的label、placeholder和value属性。我们使用v-for循环该数组,并将其作为el-form-item的子组件,每个el-form-item包含了一个el-input组件,用于输入表单项的值。最后,我们将整个表单包裹在一个el-form组件中。 使用该组件时,我们只需要传递一个包含所有表单项的数组即可: ```vue <template> <my-form :fields="fields"></my-form> </template> <script> import MyForm from "@/components/MyForm.vue"; export default { components: { MyForm, }, data() { return { fields: [ { label: "姓名", placeholder: "请输入姓名", value: "", }, { label: "邮箱", placeholder: "请输入邮箱", value: "", }, { label: "电话", placeholder: "请输入电话", value: "", }, ], }; }, }; </script> ``` 在上述代码中,我们引入了刚才创建的MyForm组件,并将fields数组传递给该组件的props属性。fields数组中包含了三个表单项,分别是姓名、邮箱和电话。我们可以通过该组件来快速创建包含多个表单项的表单。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值