prop传值给组件
// 页面的wxml,aa是组件 tabs是页面传给aa的prop,除此之外还会传过来一个vue-id的prop
// 还会绑定一个__l方法,在子组件的attached钩子内部会触发来建议vue实例之间的父子关系
<aa vue-id="8dd740cc-1" tabs="{{tabs}}" bind:__l="__l"></aa>
// 组件的js 第一节的componentOptions中
attached () {
// 在这里可以获取到自身的data和prop传过来的值,
const properties = this.properties;
const options = {
mpType: isPage.call(this) ? 'page' : 'component',
mpInstance: this,
propsData: properties
};
// 把prop的vueid赋值给mp上
initVueIds(properties.vueId, this);
// 处理父子关系,利用向页面触发的__l方法,让父mp的里的vm挂载到options里的parent属性上
initRelation.call(this, {
vuePid: this._$vuePid,
vueOptions: options
});
// 初始化 vue 实例
this.$vm = new VueComponent(options);
// 触发首次 setData
this.$vm.$mount();
}
vue的$ref是如何实现的
// 页面的wxml vue的很简单 <aa ref="fe"/>,注意vue-ref和data-ref
<aa class="vue-ref" vue-id="8dd740cc-1" data-ref="fe" bind:__l="__l"></aa>
// js 代码简单清晰,对vm的$refs做了一个代理,利用vm的selectAllComponents功能配合页面上的data-ref和“vue-ref”这个class来实现
function initRefs (vm) {
const mpInstance = vm.$scope;
Object.defineProperty(vm, '$refs', {
get () {
const $refs = {};
selectAllComponents(mpInstance, '.vue-ref', $refs);
// TODO 暂不考虑 for 中的 scoped
const forComponents = mpInstance.selectAllComponents('.vue-ref-in-for');
forComponents.forEach(component => {
const ref = component.dataset.ref;
if (!$refs[ref]) {
$refs[ref] = [];
}
$refs[ref].push(component.$vm || component);
});
return $refs
}
});
}
vue的$children是如何实现的
// 上文提到的这里把父vm设置在parent属性上,然后实例化的时候,uni改了vue的源码
initRelation.call(this, {
vuePid: this._$vuePid,
vueOptions: options
});
this.$vm = new VueComponent(options);
// 源码如下
function initLifecycle (vm) {
var options = vm.$options;
// locate first non-abstract parent
var parent = options.parent;
if (parent && !options.abstract) {
while (parent.$options.abstract && parent.$parent) {
parent = parent.$parent;
}
parent.$children.push(vm);
}
vm.$parent = parent;
}