On vue package custom plug-in

  In use vue process, often used Vue.use, but the most superficial knowledge of it, do not know when to call specific to do what, therefore, a brief overview of the next article in vue, how to package custom plug-ins.

  Before starting, first add that, in fact, the use of essentially vue package custom plug is defined process Public property methods of the component instantiation process or instructions and the like , a relatively large difference is that the package widget require manual intervention, are some examples of the method requires manual call, Vue instantiation, a lot of internal logic has been disposed of to help. After the plug-in component with respect to the advantages of plug-ins is a good package, out of the box, while the component is dependent on the project . The component initialization process is not very familiar with can refer to this blog post .

    We vue from the source, you can see Vue.use method is defined as follows: 

= Vue.use function (plugin: Function | Object) { 
    const installedPlugins = ( the this ._installedPlugins || ( the this ._installedPlugins = []))
     // existing plug, plug-in object directly returns 
    IF (installedPlugins.indexOf (plugin) > -1 ) {
       return  the this 
    } 

    // Additional Parameters 
    const args = toArray (arguments,. 1 ) 
    args.unshift ( the this )
     // VUE plug-ins may be an object, may be a method, a default constructor is passed as Vue parameters 
    IF ( typeof plugin.install === 'function' ) {
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
  }

  From the above code, we can see that, Vue.use code is relatively simple, not a lot of processing logic. We used Vue.use (xxx), xxx may be a method, it can be an object. In Vue.use by calling the plug-apply method, passing a parameter, Vue constructor. For chestnut, simple plug-Vue package as follows:

// 方法
function vuePlugins (Vue) {
    Vue.directive('test', {
        bind (el) {
            el.addEventListener('click', function (e) {
                alert('hello world')
            })
        }
    })
}

// 对象
const vuePlugins = {
    install (Vue) {
        Vue.directive('test', {
            bind (el) {
                el.addEventListener('click', function (e) {
                    alert('hello world')
                })
            }
        })
    }
}

  Both packages are the above methods, plainly, is to package instructions to a global registration method, called when Vue.use. This comparison is clear and easy to understand. Now give a slightly more complex example, tooltip often used in front-end development, the method can be called directly via the display to prevent the introduction of unnecessary components registered, a tooltip if we individually packaged components, how to package it? Such packages need to know the initialization assembly process. When the difference is packaged as a plug assembly, the assembly template can not be mounted to instantiate the real DOM, this step requires manual component instance to call the corresponding methods of the life cycle. Specific codes are as follows:  

// component
let toast = {
    props: {
        show: {
            type: Boolean,
            default: false
        },
        msg: {
            type: String
        }
    },
    template: '<div v-show="show" class="toast">{{msg}}</div>'
}

  Component initialization process:

// the JavaScript initialization logic 
// Get configuration example toast 
const = TempConstructor Vue.extend (toast)
 // instantiate toast 
the let instance = new new TempConstructor ()
 // create a manual loading container toast 
let div = document.createElement ( 'div ' )
 // parse mounted toast 
instance. $ Mount (div)
 // will toast the body mount 
document.body.append (instance. $ EL)
 // calls toast packaged as a method to mount Vue the prototype 
Vue.prototype. Toast $ = function (MSG) { 
    instance.show = to true 
    instance.msg = MSG 
    the setTimeout (() => {
        instance.show = false
    }, 5000)
}

  Consistent with the definition of components, assemblies and general statements. Plug-in process, and the general assembly of component instantiation, except that the portion of the plug assembly when the initialization method to manually call. such as:

    1, Vue.extend action is a configuration method of assembling components VueComponent

    2, new TempConstructor () is an example of the component instance. Examples of the construction method, but the state of the data component is initialized, and not the Template parsing component, there is no subsequent generation and parsing vnode vnode

    3, instance. Role $ mount (div) is to parse the template file, generated render function, which in turn calls createElement generate vnode, the last generation of true DOM, DOM will generate real mount on an instance instance of $ el property, that is examples instance. $ el final result is instantiated components.

    4, assembly, props ultimately declared property on a component instance, the instance attributes directly, you can change the properties responsive to also pass parameters . The method of assembly property is initialized as follows:

function initProps (Comp) {
  const props = Comp.options.props
  for (const key in props) {
    proxy(Comp.prototype, `_props`, key)
  }
}
// property broker, from the original object to take a data 
Export function Proxy (target: Object, SourceKey: String, Key: String) {
   // set the object attribute get / set, the data in the data agent component object to vm 
  = sharedPropertyDefinition.get function proxyGetter () {
     return  the this [SourceKey] [Key] 
  } 
  sharedPropertyDefinition.set = function proxySetter (Val) {
     the this [SourceKey] [Key] = Val 
  } 
  Object.defineProperty (target, Key, sharedPropertyDefinition) 
}

  As can be seen from the above, eventually in the constructor, to declare all the properties of a variable, essentially in the content read _props, _props attributes will be performed in response to instantiate the component, InitState in the InitProps type declaration, the specific code is as follows:

function initProps (vm: Component, propsOptions: Object) {
  const propsData = vm.$options.propsData || {}
  const props = vm._props = {}
  // cache prop keys so that future props updates can iterate using Array
  // instead of dynamic object key enumeration.
  const keys = vm.$options._propKeys = []
  const isRoot = !vm.$parent
  // root instance props should be converted
  if (!isRoot) {
    toggleObserving(false)
  }
  for (const key in propsOptions) {
    keys.push(key)
    const value = validateProp(key, propsOptions, propsData, vm)
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      const hyphenatedKey = hyphenate(key)
      if (isReservedAttribute(hyphenatedKey) ||
          config.isReservedAttr(hyphenatedKey)) {
        warn(
          `"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
          vm
        )
      }
      defineReactive(props, key, value, () => {
        if (!isRoot && !isUpdatingChildComponent) {
          warn(
            `Avoid mutating a prop directly since the value will be ` +
            `overwritten whenever the parent component re-renders. ` +
            `Instead, use a data or computed property based on the prop's ` +
            `value. Prop being mutated: "${key}"`,
            vm
          )
        }
      })
    } else {
      defineReactive(props, key, value)
    }
    // static props are already proxied on the component's prototype
    // during Vue.extend(). We only need to proxy props defined at
    // instantiation here.
    if (!(key in vm)) {
      proxy(vm, `_props`, key)
    }
  }
  toggleObserving(true)
}

  Here you will traverse all orders props, get and set properties of the responsive statement. When reading and writing property, it invokes the corresponding get / set, will in turn trigger an update of the view , the principle vue responsive in later chapters will be described. In this way, we can pass through the method parameters, to modify dynamically the assembly The props, and further capable of plug-in components.

  Some people may be in doubt, the final results of the analytical element mounted to the body div is created by document.createElement ( 'div'), or the template Template . In fact, the final result after only mount component parses . During the call __patch__, the implementation process, first, the old record of nodes, that is, $ mount (div) in the div; then, according to the vnode render node after the template parsing generated to create a DOM node , after creating a DOM node into the instance $ el; the last step, will be to remove the old node out. So, we have a package of plug-in process, in fact, the only element manually create an intermediate variable, and will not be retained in the final. We may also notice that the plug-in instance after the completion of the DOM we manually mount is mounted, code execution is document.body.append (instance. $ El).

  Annex: test.html test code

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <style>
    .toast{
      position: absolute;
      left: 45%;
      top: 10%;
      width: 10%;
      height: 5%;
      background: #ccc;
      border-radius: 5px;
    }
  </style>
  <title>Hello World</title>
  <script src="https://cdn.bootcss.com/vue/2.6.10/vue.js"></script>
</head>
<body>
<div id='app' v-test>
  <button @click="handleClick">我是按钮</button>
</div>
<script>
function vuePlugins (Vue) {
    Vue.directive('test', {
        bind (el) {
            el.addEventListener('click', function (e) {
                alert('hello world')
            })
        }
    })
}
// const vuePlugins = {
//     install (Vue) {
//         Vue.directive('test', {
//             bind (el) {
//                 el.addEventListener('click', function (e) {
//                     alert('hello world')
//                 })
//             }
//         })
//     }
// }
Vue.use(vuePlugins)
let toast = {
    props: {
        show: {
            type: Boolean,
            default: false
        },
        msg: {
            type: String
        }
    },
    Template: ' <div V-Show = "Show" class = "Toast"> {{MSG}} </ div> ' 
} 
// Get configuration example Toast 
const TempConstructor = Vue.extend (Toast)
 // instantiate Toast 
the let instance =  new new TempConstructor ()
 // create a manual loading of the toast container 
the let div = document.createElement ( ' div ' )
 // parse mounted toast 
instance. $ Mount (div)
 // will toast the body mount 
document. body.append (instance. $ EL)
 // calls toast packaged as a method, a prototype mounted on the Vue 
Vue.prototype. $ toast =  function (MSG) {
    instance.show =  to true 
    instance.msg = MSG 
    the setTimeout (() => { 
        instance.show =  to false 
    }, 5000 ) 
} 
var VM =  new new Vue ({ 
    EL: ' #app ' , 
    Data: { 
        MSG: ' the Hello World ' , 
        a: . 11 
    }, 
    methods: { 
        Test () { 
            the console.log ( ' which is a main method ' ) 
        },
        the handleClick () { 
            the this . Toast $ ( ' Hello World ' ) 
        } 
    }, 
    created () { 
        the console.log ( ' implementation of the method on the main assembly created ' ) 
    }, 
}) 
</ Script > 
</ body > 
</ HTML >

Guess you like

Origin www.cnblogs.com/gerry2019/p/12158463.html