vue-mixins使用注意事项和高级用法

因为在项目中 mixins(混合)特性使用频率是很高的 有必要熟练掌握
官方文档: mixins


实际项目中 一般都存在 列表(list) 这种很常见的使用场景

话再多都不如上demo

file: mixins/list.js

 1 module.exports = {
 2   data () {
 3     return {
 4       list: [],
 5       page: 1,
 6       limit: 15,
 7       total: 0
 8     }
 9   },
10   created () {
11     this.initList()
12   },
13   watch: {
14     page: 'loadData'
15   },
16   methods: {
17     /**
18      * 获取请求参数 默认只传递index(页码) limit(每页条数) 可以由调用方传递指定对象合并(或者覆盖)原参数
19      * @param params
20      * @returns {*}
21      */
22     getParams (params) {
23       return Object.assign({
24         index: this.page,
25         limit: this.limit
26       }, params)
27     },
28     /**
29      * 加载更多
30      */
31     loadMore () {
32         this.page++
33     },
34     /**
35      * 推送到list中 因为vue的监听特性 只能用push进行数据的添加 如果有特殊处理 通过传递一个filter来过滤数据
36      * @param list
37      * @param filter
38      */
39     pushToList (list, filter) {
40       list.forEach((item) => {
41         if (typeof filter === 'function') {
42           this.list.push(filter(item))
43         } else {
44           this.list.push(item)
45         }
46       })
47     },
48     /**
49      * 初始化列表
50      */
51     initList () {
52       this.page = 1
53       this.list = []
54       this.loadData()
55     },
56     /**
57      * @overwrite
58      * 加载数据方法 用到该mixin的都应该重写该方法 否则无法实现加载数据
59      */
60     loadData () {
61       // 每个列表自己的获取数据的方法需要重写
62     }
63   }
64 }

解析

一个列表的基本属性

属性作用或备注
list 列表
page 页码
limit 每页条数
total 总条数

基本方法

方法作用或备注
initList() 初始化列表
loadData() 加载数据
loadMore() 加载更多

扩展方法[主要用于参数的处理和结果的处理]

方法作用或备注
getParams() 获取HTTP请求参数
pushToList() 数据处理方法

每一个列表结构都具备的属性以及方法 可以放到mixins的声明中

从这段代码中可以得知 加载了该mixins的组件会在创建之后执行一个initList方法
顾名思义 就是初始化列表的方法

1 created () {
2     this.initList()
3 }

 

问题

但是问题来了 如果我的组件 不只是在初始化的时候使用
而是在使用了keep-alive的应用下在route->data()的钩子中执行初始化呢?

1 route: {
2   data () {
3     this.initList()
4   }
5 }

这时候你打开控制台 刷新页面 就会发现 第一次进入 初始化了两次

原因

因为mixins的合并策略

当混合对象与组件包含同名选项时,这些选项将以适当的策略合并。例如,同名钩子函数被并入一个数组,因而都会被调用。另外,混合的钩子将在组件自己的钩子之前调用。

 1 var mixin = {
 2   created: function () {
 3     console.log('mixin hook called')
 4   }
 5 }
 6 new Vue({
 7   mixins: [mixin],
 8   created: function () {
 9     console.log('component hook called')
10   }
11 })
12 // -> "mixin hook called"
13 // -> "component hook called"

值为对象的选项,如 methods, components 和 directives 将合并到同一个对象内。如果键冲突则组件的选项优先。

 1 var mixin = {
 2   methods: {
 3     foo: function () {
 4       console.log('foo')
 5     },
 6     conflicting: function () {
 7       console.log('from mixin')
 8     }
 9   }
10 }
11 var vm = new Vue({
12   mixins: [mixin],
13   methods: {
14     bar: function () {
15       console.log('bar')
16     },
17     conflicting: function () {
18       console.log('from self')
19     }
20   }
21 })
22 vm.foo() // -> "foo"
23 vm.bar() // -> "bar"
24 vm.conflicting() // -> "from self"

注意 Vue.extend() 使用同样的合并策略。

所以即使你在引用的组件中 把created重写 也是被合并(两个都会执行) 因为合并的策略不同 导致了 methods 可以被重写 而created ready等只会被合并

解决方法

怎么解决?

读过阅读官方文档后我想你会有答案

我这里提供一个文档中提到的比较灵活的简单的方案 加一个自定义选项

1 created () {
2     let option = this.$options.doNotInit
3     if (!option) {
4       this.initList()
5     }
6 }

通过该选项 doNotInit 来判断是否需要在组件创建完毕之后就初始化

在调用该mixins的组件中 添加这么一个选项 就可以让组件不执行初始化方法

而是通过route->data()钩子来控制列表的初始化

调用

file: anyVueComponent.vue

 1 import List from 'path/mixins/list'
 2 export default{
 3     mixins: [List],
 4     data () {
 5         return {
 6         // 除列表外额外的属性
 7         }
 8     },
 9     methods: {
10         loadData () {
11             this.$http.post(yourApiUrl, this.getParams()).then((res) => {
12             // do somethings
13             })
14         }
15     },
16     doNotInit: true,
17     route: {
18         data () {
19             this.initList()
20         }
21     }
22 }

说到底 仔细阅读Vue文档 项目中遇到的绝大多数问题 都能迎刃而解~

 

posted @ 2017-06-12 15:33  yuwenjing  阅读(1242)  评论(0编辑  收藏  举报