Vue 2.0 可复用&组合部分

318 阅读7分钟

可复用性&组合


混入

  • 基础知识点

    混入可以用来分发 Vue 组件中的可复用功能,一个混入对象可以包含任意组件选项。当组件使用混入对象时,混入对象的所有选项都会进入到该组件中

  • 选项合并的注意点

    在组件和混入对象含有同名选项发生冲突时,

    1. 会以组件数据优先的策略进行合并
    2. 同名的钩子函数都会被调用,混入对象的钩子会在组件自身钩子之前调用
    3. 值为对象的选项时,将会被合并为同一个对象,在对象的键名发生冲突时,取组件对象的键值对
  • 自定义选项合并策略

    自定义选项将使用默认策略,也可以让自定义选项以自定义逻辑合并,可以在 Vue.config.optionMergeStrategies 添加一个函数:

    Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) { 
        // 返回合并后的值 
    }
    

自定义指令

  • 基本知识点

    注册一个全局自定义指令

    Vue.directive('focus', { 
        // 当被绑定的元素插入到 DOM 中时…… 
        inserted: function (el) { 
            // 聚焦元素 
            el.focus() 
        } 
    })
    

    注册一个局部指令

    directives: { 
        focus: { 
            // 指令的定义 
            inserted: function (el) {
                el.focus() 
            } 
        } 
    }
    
  • 自定义指令的钩子函数

    bind只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置

    inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)

    update: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有,可以通过比较更新前后的值来忽略不必要的模板更新

    componentUpdated: 指令所在组件的 VNode 及其子 VNode 全部更新后调用

    unbind只调用一次,指令与元素解绑时调用

  • 钩子函数参数

    el: 指令所绑定的元素,可以用来直接操作 DOM

    binding: 一个对象,包含以下 property

      1. `name`: 指令名,不包括 `v-` 前缀
      2. `value`: 指令的绑定值
      3. `oldValue`: 指令绑定的前一个值,仅在 `update``componentUpdated` 钩子中可用
      4. `expression`: 字符串形式的指令表达式
      5. `arg`: 传给指令的参数
      6. `modifiers`: 一个包含修饰符的对象
    

    vnode: Vue 编译生成的虚拟节点

    oldVnode: 上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用

    注意: 除了 el 之外,其他参数都应该是只读的,尽量不要去修改

  • 动态指令参数知识点

    指令的参数可以是动态的。 v-mydirective:[argument] = "value" 中, argument 参数可以根据组件实例数据进行更新,在 binding 对象中可以通过 arg 来获得这个动态的参数

  • 函数简写

    在只关系 bindupdate 钩子,且两者触发相同的行为的情况下,可以进行函数的简写,如:

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

渲染函数

  • 基础知识点

    渲染函数能够比模板更接近编译器,能够使用 JavaScript 的完全编程的能力,渲染函数的基本使用如下:

    render: function (createElement) { 
        return createElement('h1', this.blogTitle) 
    }
    
  • 虚拟 DOM

    Vue 通过建立一个虚拟 DOM来追踪如何改变真实DOM

    createElement 返回的不是一个实际的 DOM 元素,它创建的是虚拟节点,它所包含的信息会告诉 Vue 页面上应该渲染的节点类型等,包括其子节点的描述信息

  • createElement 参数

    第一个参数: String | Object | Function,一个 HTML 标签名组件选项对象或者 resolve 了上述任何一种的一个 async函数 (必填)

    第二个参数: 一个与模板中 attribute 对象的数据对象 (可选)

    第三个参数: String | Array,子级虚拟节点,由 createElement() 构建而成,也可以使用字符串来生成“文本虚拟节点”

  • createElement 数据对象参数注意点

    on: { click: this.clickHandler }: 事件监听器在 on 内, 它不再支持 v-on:keyup.enter这样的修饰器了

    nativeOn: { click: this.nativeClickHandler }: 仅用于组件,用于监听原生事件,而不是组件内部使用, vm.$emit 触发的事件

    { name: props => VNode | Array<VNode> }: 作用域插槽的格式

    slot: 'name-of-slot': 如果组件是其它组件的子组件,需要为插槽指定名称

  • 渲染函数的约束

    VNode 必须是唯一的! 组件数中的所有 VNode 必须是唯一的,如果想创建重复的多个元素/组件,可以使用工厂函数来实现,示例如下:

    render: function (createElement) { 
        return createElement('div', 
            Array.apply(null, { length: 20 }).map(function () {
                return createElement('p', 'hi') 
            }) 
        ) 
    }
    
  • 使用JavaScript代替模板功能知识点

    只要在原生的 JavaScript 中可以轻松完成的操作, Vue 的渲染函数就不会提供专有的替代方法

    v-if 和 v-for:可以使用 if/elsemap 来实现相关的功能

    v-model: 渲染函数中没有与 v-model 的直接对应,需要自己实现相应的逻辑

    事件&按键修饰符: 对于 .passive.capture.once 这些事件修饰符,可以在事件前面使用对应的前缀 .passive => & .capture => ! .once => ~,其它的修饰符,可以通过在事件处理函数中使用对应的事件方法来解决

    插槽: 可以通过 this.$slots 来访问静态插槽的内容,每个插槽都是一个虚拟节点数组,也可以通过 this.$scopedSlots 访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数,如果要用渲染函数向子组件中传递作用域插槽,可以利用虚拟节点数据对象中的 scopedSlots 字段

  • JSX

    需要使用一个 Babel插件,用于在 Vue 中使用 JSX语法,它可以回到更接近于模板的语法中,示例如下:

    import AnchoredHeading from './AnchoredHeading.vue' 
    
    new Vue({
        el: '#demo', 
        render: function (h) { 
            return ( 
                <AnchoredHeading level={1}> 
                    <span>Hello</span> world! 
                </AnchoredHeading> 
            ) 
        } 
    })
    

    注意:h 作为 createElement 的别名是 Vue 生态系统中的一个通用惯例

  • 函数式组件知识点

    一个组件如果没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法,只接收一些 prop 的函数,这样的组件成为 functional,它没有响应式数据,也没有实例,没有 this 上下文

    Vue.component('my-component', {
        functional: true,
        props: {
            // ...
        }, 
        render: function (createElement, context) { // ... }
    })
    

    组件需要的一切都是通过 context 参数传递的,该对象有如下字段:

    prop: 提供所有 prop 的对象

    children: VNode 子节点的数组

    slots: 一个函数,返回了包含所有插槽的对象

    scopedSlots: 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽

    data: 传递给组件的整个数据对象,作为 createElement第二个参数传入组件

    parent: 对父组件的引用

    listeners: 一个包含了所有父组件为当前组件注册的事件监听器的对象

    injections: 如果使用了 inject 选项,则该对象包含了应当被注入的 property

    函数式组件的好处在于它只是函数,所以渲染开销也低很多

    函数式组件可以程序化地在多个组件中选择一个进行渲染,也可以在将 childrenpropsdata 传递给子组件之前操作它们

    在函数式组件中,需要显示定义将没有被定义为 prop 的 attribute 添加到组件的根元素上,如果是在 createElement 中,可以通过 context.data context.children 来传递 attribute、事件监听器、子节点等,如果是在基于模板的函数式组件中,可以使用 data.attrs 来传递任何 HTML 属性,也可以使用 listenersdata.on 的别名)传递任何事件监听器

插件

  • 基本知识点

    插件通常用来为 Vue 添加全局功能,插件的功能范围没有严格的限制,一般用于 1.添加全局方法或者 property 2.添加全局资源:指令/过滤器/过渡等 3.通过全局混入来添加一些组件选项 4.添加 Vue 实例方法,通过把它们添加到 Vue.propertype 上实现 5.一个库,提供自己的 API,同时提供上面提到的一个或多个功能

  • 使用注意点

    全局方法 Vue.use() 需要在 new Vue() 启动之前使用插件

    Vue.use 会自动阻止多次注册相同插件,即使是多次调用也只会注册一次该插件

  • 开发插件知识点

    插件需要暴露一个 install 方法,这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象

    // 1. 添加全局方法或 property
    Vue.myMethod = function() { ... }
    // 2. 添加全局资源
    Vue.directive('my-directive', {
        bind(el, binding, vnode, oldVnode) { ... }
        ...
    })
    // 3. 使用混入
    Vue.mixin({
        created() { ... }
        ...
    })
    // 4. 添加实例方法
    Vue.prototype.demo = () => { ... }
    

过滤器

可以通过自定义过滤器,来对一些常见的文本格式化,过滤器可以在两个地方进行使用:双花括号插值v-bind 表达式。过滤器在使用时,需要通过管道符|)来添加到 JS表达式的尾部

  • 过滤器的定义

    局部过滤器的定义:

    filters: {
        filterName: function(value) {
            ...
            return
        }
    }
    

    全局过滤器的定义:

    Vue.filter('filterName', function(value) {
        ...
        return 
    })