Uniapp中关于props的传参问题

    技术2022-07-29  83

    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:{}的差异,直接影响到子组件。

    Processed: 0.009, SQL: 9