vue2.0笔记

Last Updated:

2022-08-12

动态组件和异步组件

动态组件dynamic component

<keep-alive>
<component is="testComponent"></component>
</keep-alive>

异步组件async component

webpackbuild出来会有多个包

写法一,配合webpack code splitting写法

Vue.component('async-component-webpack-demo', function(resolve){
    require(['./async-component-src-path'], resolve)
})

写法二,factory部分,使用一个Promise(通过webpack+es2015语法,直接通过import来返回一个Promise)

Vue.component('async-component-webpack-demo', () => import('async-component-src-path'))

写法三,依然使用写法二的方式获得factory部分。只是不适用Vue.component,使用*local registration*写法(components字段)

new Vue({
    el: '#app', 
    components: { 'component-a': ComponentA, 'component-b': ComponentB } 
    })

复用性-mixins

合并策略(mixin和component之间)

核心思想就是,component优先级高。 所以:

  1. data对象是合并的,如果data的属性有冲突(即,属性名一样),component的data属性优先
  2. 生命周期的hooks。如果有一致,那么就是先执行完mixin的hook(例如created),再执行component的hook。(从而component能覆盖掉mixin的created发生的一些作用,譬如改了数据)
  3. 其它的对象属性(directives, methods, components),如果属性有冲突(即,属性名一样),那么也是component的优先。

全局mixin(global mixin)写法

Vue.mixin({...})

自定义合并策略(Custom Option Merge Strategies)

When custom options are merged, they use the default strategy which overwrites the existing value. If you want a custom option to be merged using custom logic, you need to attach a function to Vue.config.optionMergeStrategies: Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) { // return mergedVal }

自定义指令Custom Directives

全局注册写法

Vue.directive('name', {
})

组件注册写法(局部)

directives: {
...}

指令生命周期钩子(hook function)

bind, inserted, update, componentUpdated, unbind.

  • bind: called only once, when the directive is first bound to the element. This is where you can do one-time setup work.
  • inserted: called when the bound element has been inserted into its parent node (this only guarantees parent node presence, not necessarily in-document).
  • update: called after the containing component’s VNode has updated, but possibly before its children have updated. The directive’s value may or may not have changed, but you can skip unnecessary updates by comparing the binding’s current and old values (see below on hook arguments).
  • componentUpdated: called after the containing component’s VNode and the VNodes of its children have updated.
  • unbind: called only once, when the directive is unbound from the element.

指令生命周期钩子参数(hook function arguments)

Vue.directive('pin', {
    bind: function (el, binding, vnode) { // bind的这个生命钩子
       el.style.position = 'fixed' 
       el.style.top = binding.value + 'px' 
    } 
})

v-mydirective:[argument]="value"

  1. 其中'pin',就是my-directive;
  2. argument可以是个字符串,也可以是个变量(能转换成字符串)。 其中argumentvalue,都可以通过 const { argument, value } = binding 来访问(即,绑定在binding里头)
  3. value也可以是个Object。只要value是个合法的js表达式就行<div v-demo="{ color: 'white', text: 'hello!' }"></div>

指令,快捷写法(即第二个入参是个函数,不是object)

Vue.directive('color-swatch', 
    function (el, binding) {
         el.style.backgroundColor = binding.value 
    }
)

渲染函数和jsx(Render functions & JSX)

示例

Vue.component('anchored-heading', {
    render: function (createElement) { 
        return createElement( 
                'h' + this.level, // tag name 
                this.$slots.default // array of children 
            ) 
    }, 
    props: { 
        level: { 
            type: Number, 
            required: true 
        } 
    } 
})

上面这个,优于下面这个写法(相当于下面模板的快速版)

<script type="text/x-template" id="anchored-heading-template"> 
    <h1 v-if="level === 1"> <slot></slot> </h1> 
    <h2 v-else-if="level === 2"> <slot></slot> </h2> 
    <h3 v-else-if="level === 3"> <slot></slot> </h3>
    <h4 v-else-if="level === 4"> <slot></slot> </h4>
    <h5 v-else-if="level === 5"> <slot></slot> </h5> 
    <h6 v-else-if="level === 6"> <slot></slot> </h6>
</script>

createElement 参数

// @returns {VNode} 
createElement( 
    // {String | Object | Function} 
    // An HTML tag name, component options, or async 
    // function resolving to one of these. Required. 
    'div', 
    // {Object} 
    // A data object corresponding to the attributes 
    // you would use in a template. Optional. 
    { 
        // (see details in the next section below) 
    }, 
    // {String | Array} 
    // Children VNodes, built using `createElement()`, 
    // or using strings to get 'text VNodes'. Optional. 
    [ 
        'Some text comes first.', 
        createElement('h1', 'A headline'), 
        createElement(MyComponent, { 
            props: { someProp: 'foobar' } 
        }) 
    ] 
)

上面样例中的,第二个入参(Object)的详细情况

{ 
    // Same API as `v-bind:class`, accepting either 
    // a string, object, or array of strings and objects. 
    class: { foo: true, bar: false }, 
    
    // Same API as `v-bind:style`, accepting either 
    // a string, object, or array of objects. 
    style: { color: 'red', fontSize: '14px' }, 
    
    // Normal HTML attributes 
    attrs: { id: 'foo' }, 
    
    // Component props 
    props: { myProp: 'bar' }, 
    
    // DOM properties 
    domProps: { innerHTML: 'baz' }, 
    
    // Event handlers are nested under `on`, though 
    // modifiers such as in `v-on:keyup.enter` are not 
    // supported. You'll have to manually check the 
    // keyCode in the handler instead. 
    on: { click: this.clickHandler }, 
    
    // For components only. Allows you to listen to 
    // native events, rather than events emitted from 
    // the component using `vm.$emit`. 
    nativeOn: { click: this.nativeClickHandler }, 
    
    // Custom directives. Note that the `binding`'s 
    // `oldValue` cannot be set, as Vue keeps track 
    // of it for you. 
    directives: [ { name: 'my-custom-directive', value: '2', expression: '1 + 1', arg: 'foo', modifiers: { bar: true } } ], 
    
    // Scoped slots in the form of 
    // { name: props => VNode | Array<VNode> } 
    scopedSlots: { 
        default: props => createElement('span', props.text) 
    }, 
    
    // The name of the slot, if this component is the 
    // child of another component 
    slot: 'name-of-slot', 
    
    // Other special top-level properties 
    key: 'myKey', 
    ref: 'myRef', 
    
    // If you are applying the same ref name to multiple 
    // elements in the render function. This will make `$refs.myRef` become an 
    // array 
    refInFor: true 
}

使用render函数渲染v-model方式的一个样例

props: ['value'], 
render: function (createElement) {
    var self = this 
    return createElement('input', { 
        domProps: { value: self.value }, 
        on: { 
            input: function (event) {
                 self.$emit('input', event.target.value) 
            } 
        } 
    })
}

一个babel plugin ,让我们用jsx的语法,写vue的render函数(而不是用createElement去一个个写)

父组件传递到孙组件part1:属性(props)的传递

v-bind="data.attrs"

父组件传递到孙组件part2:响应事件(listeners)的传递

v-on="listeners"

### 父组件传递到孙组件part3:样例代码

<template functional> 
    <button class="btn btn-primary" v-bind="data.attrs" v-on="listeners" > 
        <slot/> 
    </button>
</template>

深究响应式(Reactivity in Depth)

数据的变化是如何被追踪的(How Changes Are Tracked)

依赖采集(dependency-tracking)

将一个component触及到(touch)的数据源登记起来,记录到一个watcher那里。每一个component实例,伴生一个watcher

变化通知(change-notification)

当数据源相应数据变化的时候,把这个变化的情况发给一系列的watcher,让它们有依赖到这个变化数据的component,进行相应的view的update

对象(Object)

新增属性,得通过 Vue.set(obj, property, value)

数组(Array)

无法响应式的case

  1. 动态修改array的数组。譬如a.length = 0,这样子无法响应式
  2. 根据index修改array对应地方的值。譬如a[0] = 0, 是无法相应式的。

解决方式

  1. splice
  2. 使用"对象"里头提到的Vue.set(xxx)