简单调试 node_modules 源码
最近在修改自己封装的组件 bug
时, 发现需要调试一下 ElementUI
源码, 就想着趁次机会记录一下如何简单调试 node_modules
的源码
由 bug
截图可知是由于调用 form
的 resetFields
(重置) 方法触发的, 所以我们需要在源码中找到 resetFields
方法
在 node_modules/element-ui/packages/form/src/form.vue
中找到如下代码:
resetFields() {
if (!this.model) {
console.warn('[Element Warn][Form]model is required for resetFields to work.');
return;
}
this.fields.forEach(field => {
field.resetField();
});
}
2
3
4
5
6
7
8
9
所以我们现在需要找 resetField
方法
在当前目录中的 form-item.vue
中找到如下代码:
resetField() {
this.validateState = '';
this.validateMessage = '';
let model = this.form.model;
let value = this.fieldValue;
let path = this.prop;
if (path.indexOf(':') !== -1) {
path = path.replace(/:/, '.');
}
let prop = getPropByPath(model, path, true);
this.validateDisabled = true;
if (Array.isArray(value)) {
prop.o[prop.k] = [].concat(this.initialValue);
} else {
prop.o[prop.k] = this.initialValue;
}
// reset validateDisabled after onFieldChange triggered
this.$nextTick(() => {
this.validateDisabled = false;
});
this.broadcast('ElTimeSelect', 'fieldReset', this.initialValue);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
由以上代码我们可以简单得知首先重置了提示信息及状态, 然后关闭验证: this.validateDisabled = true
, 防止重置初始值时验证, 接着重置初始值, 在 $nextTick
中打开验证
再结合咱们自己封装的代码可以做如下推理: ElementUI
关闭验证并重置初始化, 并且使用 $nextTick
将打开验证放入队列中等待执行; 而在重置初始化后, 咱们组件同时 watch
到 value
改变, 从而执行 init
方法, 而 init
中调用了 $nextTick
, 所以其实 init
中的处理也放到了队列中等待执行了, 但是是排在打开验证之后执行; 接着主线程执行完成, 执行队列中的任务, 由于打开验证在前, 所以先是打开验证, 再执行 init
中的处理, 而 init
中处理后调用了 emit
和 blur
, 触发验证, 而此时是重置后的初始值(空串), 所以会出现必填提示
猜想如上, 接下来就需要验证一下了
首先在源码的 validateDisabled
改变后输出一下该值, 并在组件相应的地方输出一下, 简略代码如下:
源码 node_modules/element-ui/packages/form/src/form-item.vue
resetField() {
// do something
this.validateDisabled = true;
console.log('this.validateDisabled', this.validateDisabled)
// do something
this.$nextTick(() => {
this.validateDisabled = false;
console.log('this.validateDisabled', this.validateDisabled)
});
}
2
3
4
5
6
7
8
9
10
组件 SelectTree
watch: {
value () {
console.log(this.value, 'value')
// 为了检测 v-model 的变化
if (this.value + '' !== this.selectData + '') {
console.log('value change')
this.treeKey = Math.random()
this.init()
}
}
},
methods: {
init () {
console.log('init')
this.$nextTick(() => {
if (this.isMultiple) {
this.handleCheckChange()
} else {
this.handleCurrentChange()
}
})
},
emitBase () {
console.log('emitBase')
this.$emit('input', this.selectData)
this.$emit('change', this.selectData, this.selectNode)
},
// 单选, 节点被点击时的回调, 返回被点击的节点数据
handleCurrentChange () {
// do something
console.log('current change')
// 由于只验证重置, 所以只保留以下部分代码
const currentNode = this.$refs.tree.getCurrentNode()
// 当前传入的值在 tree 中无法找到, 需要清空 select 值
if (!currentNode) {
this.selectData = ''
this.selectNode = null
if (this.isFirst) {
this.isFirst = false
} else {
console.log('空串')
this.emitBase()
this.$refs.select.blur()
}
return
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
重启服务(改源码后必须重启服务) 后发现只有组件的输出, 并没用源码的输出, 难道是找错位置了吗?
在网上查找后, 原来是要在 lib
中的源码输出: 在 vue 项目的 node_modules/element-ui 目录下加 console.log 打印, 为什么没有效果? - SegmentFault 思否 (opens new window)
因为你实际上使用的 element 组件是经过压缩编译过后的文件, 也就是 lib 文件夹中的文件. 所以你在 node_modules 文件夹下的 src 中的 console.log 没有作用.
在 node_modules/element-ui/lib/form-item.js
中添加输出并重启服务后, 发现还是没有输出
后经过微信群大佬指点:
你看看入口文件是哪个, 在那个文件里面加
终于在 package.json
中找到了: "main": "lib/element-ui.common.js"
在 node_modules/element-ui/lib/element-ui.common.js
中添加输出后终于看到结果了:
由上图输出可以看出和猜测的完全一致
至此本次愉快的调试之旅就结束了
什么? 你说问题还没有解决? 本次之旅只是负责调试并找到问题的原因, 并不提供解决方案; 如需解决方案, 你看看是不是开头漏了什么 ^_^