This is the fourth day of my participation in the August Text Challenge.More challenges in August
Vue.extend
Case analysis
Extending a component is similar to the use of mixins, except that only one can be inherited
<! -- TestA-->
<script>
export default {
created() {
console.log('Base class, component for inheritance')}},</script>
Copy the code
<! --Demo--> <template> <div></div> </template> <script> import TestA from './test1.vue' export default { name: 'Dashboard', extends: TestA, // Single data() {return {visible: true, bar: 'ABC ',}}, created() {console.log(' shows the use of extends ')},} </script>Copy the code
When inherited, the component of extends takes precedence, so the result is run
Source code analysis
// core/global-api/extend.js
Vue.extend = function (extendOptions: Object) :Function {
extendOptions = extendOptions || {}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
if(process.env.NODE_ENV ! = ='production' && name) {
validateComponentName(name)
}
const Sub = function VueComponent (options) {
this._init(options)
}
// Inherit the Vue prototype object
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub // Set the constructor
Sub.cid = cid++
// Merge the root instance with the component option. The effect is that the global component can be used in this component
Sub.options = mergeOptions(
Super.options,
extendOptions
)
// Keep references to parent classes in child components
Sub['super'] = Super
// The props option is set in the sub component to initialize
if (Sub.options.props) {
initProps(Sub)
}
// The computed option is set in the child component to deinitialize
if (Sub.options.computed) {
initComputed(Sub)
}
// Save Vue's global API
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
////////
// enable recursive self-lookup
if (name) {
Sub.options.components[name] = Sub
}
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
// cache constructor
cachedCtors[SuperId] = Sub
// Returns the constructor of the child component
return Sub
}
}
Copy the code
Vue.mixin
Case analysis
var mixin = {
data () {
return {
message: 'hello'.foo: 'abc'}},created: function () {
console.log('Mixin object's hook is called')},methods: {
foo: function () {
console.log('foo')},conflicting: function () {
console.log('from mixin')}}}new Vue({
mixins: [mixin], // Array, indicating that multiple can be mixed
data() {
return {
message: 'goodbye'.bar: 'def'}},created: function () {
console.log('Component hook called')},methods: {
bar: function () {
console.log('bar')},conflicting: function () {
console.log('from self')}}})// => "Mixin hook is called"
// => "Component hook is called"
// => { message: "goodbye", foo: "abc", bar: "def" }
// vm.foo() // => "foo"
// vm.bar() // => "bar"
// vm.conflicting() // => "from self"
Copy the code
Source code analysis
Merges the mixin defined with options of the current component or global options. Note that the component has a higher priority when merging
// core/global-api/mixin.js
export function initMixin (Vue: GlobalAPI) {
Vue.mixin = function (mixin: Object) {
this.options = mergeOptions(this.options, mixin) //
return this}}Copy the code
-
MergeOptions () is used in both mixin and extend. Its main function is to merge two options. Its merge strategy is as follows:
-
For optons such as Data, Methods, Components, and directives, the component data takes precedence
-
The hook functions with the same name are merged into an array, and the hooks mixed into the object are called before the component’s own hooks
-
// core/util/options.js
export function mergeOptions(
parent: Object,
child: Object, vm? : Component) :Object {
// Check whether the component name is valid
if(process.env.NODE_ENV ! = ="production") {
checkComponents(child);
}
if (typeof child === "function") {
child = child.options;
}
// Standardize the treatment of props inject,directives, and add some default properties set in their own code to unify their code structure
normalizeProps(child, vm);
normalizeInject(child, vm);
normalizeDirectives(child);
// Use the _base attribute to determine whether the merge has been performed
if(! child._base) {// With extends, recursive merge continues
if (child.extends) {
parent = mergeOptions(parent, child.extends, vm);
}
// Use mixins to continue recursive merge
if (child.mixins) {
for (let i = 0, l = child.mixins.length; i < l; i++) { parent = mergeOptions(parent, child.mixins[i], vm); }}}const options = {};
let key;
// First traverses the parent options to determine which merge strategy needs to be executed based on the key, and then merges
for (key in parent) {
mergeField(key);
}
// Iterate over sub-options, key section, merge strategy logic
// Parent options are the options of the component
for (key in child) {
// There is no child options key in parent options. Merge child options keys
// The parent options key takes precedence
if(! hasOwn(parent, key)) {// Perform merge for child optionsmergeField(key); }}// Strats represents a collection of merge strategies for some of vue's options
function mergeField(key) {
// Check whether the merge policy is in the strats set by key. If not, add a default merge policy defaultStrat
const strat = strats[key] || defaultStrat;
// Execute the merge strategy for this key and add it to the new merged Options object
options[key] = strat(parent[key], child[key], vm, key);
}
return options;
}
Copy the code
defaultStrat
Default merge policy. The values of suboptions take precedence
// core/util/options.js
const defaultStrat = function (parentVal: any, childVal: any) :any {
return childVal === undefined ? parentVal : childVal;
};
Copy the code
The articles
- [Vue source]–$nextTick and asynchronous rendering (line by line comments)
- [Vue source]–mixin and extend (line by line)
- [Vue source]–Diff algorithm (line by line comment)
- [Vue source]– How to listen for array changes (line by line comment)
- [Vue source]– Reactive (bidirectional binding) principle (line by line comment)
- [Vue source]– what is done for each lifecycle (line by line comments)
- [Vue source]– How to generate virtual DOM (line by line comment)