# vue 可复用性和组合

# 混入 mixins

# 利用mixins实现页面的自动埋点

获取用户在某个页面的停留时间


// mixins 
const computingTime = {
    created() {
        this._start = Date.now()
    },
    beforeDestroy() {
        const img = new Image('xxxx')
        img.setAttribute('src',`https://www.debugs.cn?time=${Date.now - this._start}`)
    }
}

// 使用

const Detail = {
  mixins: [computingTime]
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 组件数据优先
  • 同名钩子函数将合并为一个数组,因此都将被调用。混入对象的钩子将在组件自身钩子之前调用。
  • methods、components 和 directives,合并成一个对象,key重复的时候采用组件自己的值
  • Vue.mixin()可以全局混入

# 自定义指令

vue.directive(name,options|function)可以自定义指令

options可以配置

  • bind: 只调用一次,只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  • inserted: 被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
  • update: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有
  • componentUpdated: 指令所在组件的 VNode 及其子 VNode 全部更新后调用
  • unbind: 只调用一次,指令与元素解绑时调用。

钩子参数

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-demo:foo.a.b="message + Math.random()"中,表达式为 "message + Math.random()"。
    • arg:传给指令的参数,可选。例如 v-demo:foo.a.b="message + Math.random()"中,参数为 "foo"。
    • modifiers:一个包含修饰符的对象。例如:v-demo:foo.a.b="message + Math.random()" 中,修饰符对象为 { a: true, b: true }。
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
<div id="hook-arguments-example" v-demo:foo.a.b="message + Math.random()" @click="message=Math.random()"></div>

<script>
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  bind(el,binding,vnode,oldVnode){
     var s = JSON.stringify
      el.innerHTML =
        'arg: '   + s(binding.arg) + '<br>' +
        'expression: ' + s(binding.expression) + '<br>' +
        'modifiers: '  + s(binding.modifiers) + '<br>' +
        'name: '       + s(binding.name) + '<br>' + 
        'oldArg: '      + s(binding.oldArg) + '<br>' +
        'oldValue: '      + s(binding.oldValue) + '<br>' +
        'rawName: '      + s(binding.rawName) + '<br>' +
        'value: '      + s(binding.value) + '<br>' 
        // 打印如下
        // arg: "foo"
        // expression: "message + Math.random()"
        // modifiers: {"a":true,"b":true}
        // name: "demo"
        // oldArg: undefined
        // oldValue: undefined
        // rawName: "v-demo:foo.a.b"
        // value: "hello!0.9805303492940918"
  }, 
  inserted(el,binding,vnode,oldVnode){

  },
  update(el,binding,vnode,oldVnode){

  },
  componentUpdated(el,binding,vnode,oldVnode) {

  },
  unbind(el,binding,vnode,oldVnode){

  }
})

new Vue({
    el:'#app',
    data(){
      return {
        message: 'hello!'
      }
    }
})
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

# 渲染函数 & JSX

# 插件

  1. 为Vue添加全局属性或方法
  2. 添加全局指令,过滤器
  3. 添加全局组合,比如 vue-router添加的 route-link router-view
  4. 添加Vue实例的方法,通过把方法添加到Vue.prototype原型属性上

# 插件开发

Vue的插件应该暴露一个install方法,改方法接受2个参数,第一个是Vue构造器,第二个是参数选项

MyPlugin.install = function (Vue, options) {
  // 1. 添加全局方法或 property
  Vue.myGlobalMethod = function () {
    // 逻辑...
  }

  // 2. 添加全局资源
  Vue.directive('my-directive', {
    bind (el, binding, vnode, oldVnode) {
      // 逻辑...
    }
    ...
  })

  // 3. 注入组件选项
  Vue.mixin({
    created: function () {
      // 逻辑...
    }
    ...
  })

  // 4. 添加实例方法
  Vue.prototype.$myMethod = function (methodOptions) {
    // 逻辑...
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 过滤器