Uniapp中关于props的传参问题

  • Post author:
  • Post category:uniapp




uniapp中父组件向子组件传递prop时,如果prop是对象,对象内部不能包含function属性


例子如下



father.vue

<template>
    <view class="uni-container">
		<child :fatherData="fatherData" :fatherFcuntion="fatherFcuntion" :fatherMethod="fatherMethod"></child>
	</view>
</template>
<script>
	import child from './child.vue'
	export default {
        components: {
			child
        },
        data() {
            return {
				fatherData: {
					a: 1,
					b: {
						isShow: function() {
							console.log("data定义对象属性函数");
						}
					}
				},
				fatherFcuntion: function() {
					console.log("data定义函数变量");
				},
			}
		},
		methods: {
			fatherMethod() {
				console.log("method的定义函数");
			},
		}
	}
</script>



child.vue

<template>
	<view>
		child
	</view>
</template>

<script>
	export default({
		name: "child",
		props: {
			fatherData: {
				type: Object,
				default: function() {
					return {};
				}
			},
			fatherFunction: {
				type: Function,
				default: function() {
					return function() {}
				}
			},
			fatherMethod: {
				type: Function,
				default: function() {
					return function() {}
				}
			}
		},
		mounted() {
			console.log("父组件data定义的变量包含函数", this.fatherData);
			console.log("父组件data定义的函数变量", this.fatherFunction);
			console.log("父组件method定义的函数", this.fatherMethod);
		}
	})
</script>

结果

在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200702173033111.png

可以看到展示数据

1.data定义的变量包含函数,函数属性直接被删除了

2.data定义的函数变量,可以正常传递

3.method定义的函数,可以正常传递

总结:uniapp的prop传递的变量为对象时,对象内部含有函数属性,该函数属性会直接被删除

Vue中的测试截图

在这里插入图片描述

Vue中是可以正常传递



原因

uniapp中父组件进行初始化时,会经过

initMixin(Vue);
stateMixin(Vue);
eventsMixin(Vue);
lifecycleMixin(Vue);
renderMixin(Vue);

在initMixIn(Vue)中会执行

function initMixin (Vue) {
  Vue.prototype._init = function (options) {
  	.......
	if (vm.$options.el) {
      vm.$mount(vm.$options.el);
    }
  };
}

_init方法中的$mount函数如下

// public mount method
Vue.prototype.$mount = function(
    el ,
    hydrating 
) {
    return mountComponent$1(this, el, hydrating)
};

mountComponent$1函数如下,会new Watcher,函数为updateComponent,函数updateComponent会执行_update

function mountComponent$1(
  vm,
  el,
  hydrating
) {
  ..........
  var updateComponent = function () {
    vm._update(vm._render(), hydrating);
  };

  // we set this to vm._watcher inside the watcher's constructor
  // since the watcher's initial patch may call $forceUpdate (e.g. inside child
  // component's mounted hook), which relies on vm._watcher being already defined
  new Watcher(vm, updateComponent, noop, {
    before: function before() {
      if (vm._isMounted && !vm._isDestroyed) {
        callHook(vm, 'beforeUpdate');
      }
    }
  }, true /* isRenderWatcher */);
  hydrating = false;
  return vm
}

在lifecycleMixin函数内部会定义一个_update属性函数

Vue.prototype._update = function (vnode, hydrating) {
    .......
    if (!prevVnode) {
      // initial render
      vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
    } else {
      // updates
      vm.$el = vm.__patch__(prevVnode, vnode);
    }
    ......
  };

_update函数中有一个__patch__函数,主要比较newData与oldData的差异进行差量更新

var patch = function(oldVnode, vnode) {
  ............
  if (this.mpType === 'page' || this.mpType === 'component') {
    var mpInstance = this.$scope;
    var data = Object.create(null);
    try {
      data = cloneWithData(this);
    } catch (err) {
      console.error(err);
    }
    data.__webviewId__ = mpInstance.data.__webviewId__;
    var mpData = Object.create(null);
    Object.keys(data).forEach(function (key) { //仅同步 data 中有的数据
      mpData[key] = mpInstance.data[key];
    });
    var diffData = this.$shouldDiffData === false ? data : diff(data, mpData);
    ..........
};

上述有一个cloneWithData方法,最后会返回深度克隆的值,但是该方法会有问题,丢失value值为function的key,并且可能存在循环依赖问题。

function cloneWithData(vm) {
  .....
  return JSON.parse(JSON.stringify(ret))
}

上述可以看到,使用cloneWithData采用了JSON.parse(JSON.stringify(ret)),导致this中的data中会识别到对象如果包含function,会直接丢失到该属性,并且diff算法会识别到b:{}的差异,直接影响到子组件。



版权声明:本文为py_boy原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。