起因
因为部门前端系统越来越多,为了项目稳定运行、统计汇总、及时定位线上bug,急需前端埋点系统,并且对项目代码侵入性越小越好。所以急需一套react透明埋点方式。
组件写法 函数组件和类组件两种形式常用形式,还有就是createElement的写法,多用于写一些类库或者UI组件库使用。且前两种打包的时候也会转成后者。
侵入性最小且能在全局作用,只能从react入手了。劫持一波createElement。so,让我们先来撸一波源码。
ReactElement.createElement = function (type, config, children) {
var propName;
// 用于存储后面的属性
var props = {};
var key = null; // 元素的key
var ref = null; // 元素的ref
var self = null;
var source = null;
if (config != null) {
// 判断是否有ref,有就赋值一下
if (hasValidRef(config)) {
ref = config.ref;
}
// 同理
if (hasValidKey(config)) {
key = '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// 把config里面的属性都一个一个挪到props中
for (propName in config) {
// 判断是不是原型链上的属性
if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
props[propName] = config[propName];
}
}
}
// children 可能是一个也可能是多个
var childrenLength = arguments.length - 2;
if (childrenLength === 1) {
// 只有一个children
props.children = children;
} else if (childrenLength > 1) {
// 遍历一下,把children放到 childArray上
var childArray = Array(childrenLength);
for (var i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (process.env.NODE_ENV !== 'production') {
if (Object.freeze) {
Object.freeze(childArray);
}
}
// 把这个数组赋值给props.children
props.children = childArray;
}
// 有type并且type有defaultProps属性 type是一个组件
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
// 同样的遍历
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
if (process.env.NODE_ENV !== 'production') {
if (key || ref) {
if (typeof props.typeof === 'undefined' || props.typeof !== REACT_ELEMENT_TYPE) {
var displayName = typeof type === 'function' ? type.displayName || type.name || 'Unknown' : type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
}
}
// props里面存的是config的属性值,然后还有children的属性
// return一个 调用ReactElement执行方法,并传入刚才处理过的参数
return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
};
比较简单的代码,所以我们可以从props上入手,如果props上有onCLick属性的,那么我们就在onClick触发前调用我们的埋点方法。目测可行。 具体的埋点方案,下次再说。
文章评论