Decided to follow huang Yi teacher vue2 source course to learn the source of vue2, learning process, as far as possible output their income, improve learning efficiency, the level is limited, wrong words please correct ~
Clone the vue source code locally and switch to branch 2.6.
Introduction
Unknown Custom Element (vue) Unknown Custom Element (Vue) Unknown Custom Element (VUE)
There are two ways to register vUE:
- Global registration
- Local registration
To see a demo
There are two ways to register and use components:
<div id="app"></div>
<script src="/Users/zhm/mygit/vue/dist/vue.js"></script>
<script>
/ / child component
let Hello = {
name: "Hello".template: "<div>hello</div>"};// Global components
let appComponent = {
name: "app".// Registry component
components: { Hello },
// Use local components
template: `
{{msg}}
`.data: () = > ({ msg: "App" }),
created() {
console.log('Component of $options.components'.this.$options.components); }};// Register the global component
Vue.component(appComponent.name, appComponent);
console.log("Options.com ponents on Vue classes", Vue.options.components);
// Root component instance
let vueInstance = new Vue({
el: "#app".template: `<app></app>`});</script>
Copy the code
Take a look at the print:
To register global components, use Vue.com Ponent (name,componentOptions) to register local components using {components:{hello:hello}}
Register global component: Vue.com Ponent
See Vue.component how to define, do what, directly find a little difficult to find, directly paste source code:
InitAssetRegisters is register three properties on the Vue, components/filters/directives.
// src/core/global-api/assets.js
export function initAssetRegisters(Vue: GlobalAPI) {
/** * Create asset registration methods. * ASSET_TYPES = [ 'component', 'directive', 'filter' ] */
ASSET_TYPES.forEach((type) = > {
Vue[type] = function (
id: string,
definition: Function | Object
) :Function | Object | void {
if(! definition) {return this.options[type + "s"][id];
} else {
/* istanbul ignore if */
if(process.env.NODE_ENV ! = ="production" && type === "component") {
validateComponentName(id);
}
if (type === "component" && isPlainObject(definition)) {
definition.name = definition.name || id;
definition = this.options._base.extend(definition);
}
if (type === "directive" && typeof definition === "function") {
definition = { bind: definition, update: definition };
}
this.options[type + "s"][id] = definition;
returndefinition; }}; }); }Copy the code
Look at the source code skull pain place is, even if it is a simple function, but in order to consider the overall, it seems to feel more than a layer of window paper, vague, the content of the above simplification:
// component for cp
Vue.components = function (cpName, cpOptions) {
// Make sure component has a name attribute on it
cpOptions.name = cpOptions.name | cpName;
// Vue. Extend turns cpOptions into a subclass of Vue.
const cpClass = Vue.extend(cpOptions);
// So the global component must be in Vue.options.components
Vue.options.components[cpName] = cpClass;
return cpClass;
};
Extend turns cpOptions into a Vue subclass, simplifying the code below
Vue.extend = function (cpOptions) {
const Sub = function VueComponent(options) {
this._init(options);
};
Sub.prototype = Object.create(Vue.prototype);
// Different field merge strategies are different
Sub.options = mergeOptions(Vue.options, cpOptions);
return Sub;
};
Copy the code
Vue.options.components[cpName] = cpClass; Vue.options.components[cpName] = cpClass;
Using global components
Component classes have merged the Vue. The options on the options, and the component instantiation phase, will be executed again mergeOptions operation, incorporating VueComponent.options.com ponents to vm.$options.com ponents.
The _createElement method is then executed during the vNode creation process. Let’s review the logic of this section again. It is defined in SRC /core/vdom/create-element.js: SRC /core/vdom/create-element.js
export function _createElement (context: Component, tag? : string | Class<Component> |Function | Object, data? : VNodeData, children? : any, normalizationType? : number) :VNode | Array<VNode> {
// ...
let vnode, ns
if (typeof tag === 'string') {
let Ctor
if (isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
// component
vnode = createComponent(Ctor, data, context, children, tag)
}
}
Copy the code
This is how a vNode resolveAsset will find a Ctor based on the tag and then create a vNode resolveAsset based on the tag.
// src/core/utils/options.js
export function resolveAsset(
options: Object, type: string, id: string, warnMissing? : boolean) :any {
// Type is components or filters etc
const assets = options[type];
// id refers to the component name, or the component tag
if (hasOwn(assets, id)) return assets[id];
const camelizedId = camelize(id);
// Hump form
if (hasOwn(assets, camelizedId)) return assets[camelizedId];
// Uppercase
const PascalCaseId = capitalize(camelizedId);
// It is a hyphen
if (hasOwn(assets, PascalCaseId)) return assets[PascalCaseId];
// fallback to prototype chain
const res = assets[id] || assets[camelizedId] || assets[PascalCaseId];
if(process.env.NODE_ENV ! = ="production"&& warnMissing && ! res) { warn("Failed to resolve " + type.slice(0, -1) + ":" + id, options);
}
return res;
}
Copy the code
I’m going to use id, I’m going to use hump ID, I’m going to use capital, I’m going to use hyphen, I’m going to use all three forms of ID, I’m going to return Ctor
Register local components
{hello} from the new component options. The mergeOptions must be merged into the new component’s vm.quarrels. Components. Get the corresponding Ctor from resolveAsset
Local components, of course, can only be used within components. Global components can be used by all components because Vue.options.com Ponents are merged into VM.options.com Ponents when the component is instantiated.
reference
- Huang Yi teacher vuE2 source decryption course
- Vue. Js technology revealed