1. 程式人生 > 其它 >vue.js提供的各種API的內部實現原理

vue.js提供的各種API的內部實現原理

全域性API和例項方法不同,後者是在Vue的原型上掛載方法,也就是在Vue.prototype上掛載方法,而前者是直接在Vue上掛載方法。示例:

vue.extend = function(extendOption) {
  ...
}

Vue.extend

引數:Vue.extend({})
用法:使用基礎Vue構造器建立一個"子類",引數是包含元件選項的物件
data選項是特例,在Vue.extend中,它必須是函式,完整程式碼:

    let cid = 1
    Vue.extend = function (extendOptions) {
        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') {
            if(!/^[a-zA-Z][\w-]*$/.test(name)) {
                warn(
                    'invalid component name:"' + name + '". Component name' + 
                    'can only contain alphaumeric characters and the hyphen, ' +
                    'and must start with a letter.'
                )
            }
        }
        const Sub = function VueComponent(options) {
            this._init(options)
        }
        Sub.prototype = Object.create(Super.prototype)
        Sub.prototype.constructor = Sub
        Sub.cid = cid++

        Sub.options = mergeOptions(
            Super.options,
            extendOptions
        )
        Sub['super'] = Super

        if(Sub.options.props) {
            initProps(Sub)
        }

        if(Sub.options.computed) {
            initComputed(Sub)
        }

        Sub.extend = Super.extend
        Sub.mixin = Super.mixin
        Sub.use = Super.use

        ASSET_TYPES.forEach(function(type) {
            Sub[type] = Super[type]
        })

        if(name) {
            Sub.options.components[name] = Sub
        }

        Sub.superOptions = Super.options
        Sub.extendOptions = extendOptions
        Sub.sealedOptions = extend({}, Sub.options)

        //快取建構函式
        cachedCtors[SuperId] = Sub
        return Sub
    }

Vue.directive(id, [definition])

引數:{String} id,{function | Object} [definition]
用法:註冊或獲取全域性指令。


    //註冊
    Vue.directive('my-directive', {
        bind: function() {},
        inserted: function() {},
        update: function() {},
        componentUpdated: function() {},
        unbind: function() {}
    })

    //註冊(指令函式)
    Vue.directive('my-directive', function() {
        //這裡將會被bind和updata呼叫
    })

    //getter方法,返回已註冊的指令
    let myDirective = Vue.directive('my-directive')

Vue.directive方法的作用是註冊或獲取全域性指令,而不是讓指令生效。
註冊指令程式碼實現:

    //用於儲存指令的位置
    Vue.options = Object.create(null)
    Vue.options['directives'] = Object.create(null)

    Vue.directive = function (id, definition) {
        if(!definition) {
            //直接返回之前儲存好了的
            return this.options['directives'][id]
        } else {
            if(typeof definition === 'function') {
                //預設監聽並給definition重新賦值
                definition = { bind: definition, update: definition}
            }
        }
        //儲存到options中
        this.options['directives'][id] = definition
        return definition
    }

首先在Vue建構函式上建立了options熟悉來存放選項,並在選項上新增directive方法。
這個方法接收兩個引數,它可以用來註冊和獲取指令,當definition為空的時候,根據id直接返回指令。當definition存在時,說明是註冊指令,檢查definition的型別,如果為函式的話就將bind,undate兩個函式預設監聽,並用這個物件去覆蓋definition,然後在options中儲存,最後返回definition;如果不是函式說明是使用者自定義的指令,直接儲存在options上不進行操作。

Vue.filter(id, [definition])

引數:{string} id,{Function | Object} [definition]
用法:註冊或獲取全域性過濾器。

    //註冊
    Vue.filter('my-filter', value => {
        //返回處理後的值
    })

    // getter的方法,返回已註冊的過濾器
    let myFilter = Vue.filter('my-filter')

過濾器可以用在兩個地方:雙花括號插值和v-bind表示式:

//在雙花括號裡
{{ message | my-filter}}

//在v-bind中
<div v-bind:id = 'rawId | my-filter'></div>

與Vue.directive類似,Vue.filter的作用僅僅是註冊或獲取全域性過濾器。它們倆的註冊過程也很類似,將過濾器儲存在Vue.options['filters']中即可。程式碼實現:

    Vue.options['filters'] = Object.create(null)

    Vue.filter = function (id, definition) {
        if(!definition) {
            //直接返回之前儲存的
            return this.options['filters'][id]
        } else {
            //註冊過濾器
            this.options['filters'][id] = definition
            return definition
        }
    }