Vue高级API - mixins(含案例)

在项目中 mixins(混合)特性使用频率是很高的 有必要熟练掌握
官网传送门:mixins

# 简介

  混入(mixins)是一种分发Vue组件中可复用功能的非常灵活的方式,它的存在使得开发者们可以定义一部分公用的属性或方法,然后混入到各个组件内部使用,提高了可维护性。

  一个混入自身以一个对象的形式存在,如var mixin = { },它可以包含任意组件选项。在调用方中,调用混入对象使用mixins: [],接收一个混入对象的数组,也就是说可以一次混入多个混入对象。

# 混入选项合并

  当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项中。

 先看案例再理解

'# file: mixins/welcome.js'
export const Welcome = {
  created: {
    this.initPage();
  },
  methods: {
    initPage() {
      this.$toast('icon-welcome', '正在进入系统,请稍后...')
    }
  }
}

在组件中混入如上混入对象

import  { Welcome } from '../assets/js/mixins/welcome'
export default {
  name: 'AnyComponent',
  mixins: [ Welcome ],
  data () {
    return {
      greet: '正在进入业务系统,请稍后...'
    }
  },
  created: {
    this.initPage()
  },
  methods: {
   initPage() {
      this.$toast('icon-welcome', this.greet)
    }
  }
}
----------------------
# 执行结果
正在进入业务系统,请稍后...
正在进入业务系统,请稍后...

  对此结果或许会感到疑惑,那是因为有如下混入规则:

  1. data选项在混入时,数据对象在内部会进行递归合并,当发生冲突时,以组件数据优先
  2. 同名钩子函数混合为一个数组,两个钩子函数内部的逻辑都会被执行,且混入的比组件的先调用
  3. 值为对象的选项methods, components, directives将被 混合为同一个对象。冲突取组件键值对
  4. 自定义的混入策略,见后续

再来理解以上案例,created钩子混入后两个方法调用都会执行,而methods因为混入时键冲突以组件为主,因此有了以上输出。

# 自定义混入策略

  如果想让自定义选项使用自定义逻辑混入合并,可以向Vue.config.optionMessageStrategies 添加一个函数,例如自定义选项名为myOption

Vue.config.optionMessageStrategies.myOption = function (toVal, fromVal) {
    // return mergeVal
}

  对于大多数自定义的对象型选项来说,直接复用methods的即可

var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods

举一个vuex的混入案例如下,复用了computed的混入规则

const merge = Vue.config.optionMergeStrategies.computed
Vue.config.optionMergeStrategies.vuex = function (toVal, fromVal) {
  if (!toVal) return fromVal
  if (!fromVal) return toVal
  return {
    getters: merge(toVal.getters, fromVal.getters),
    state: merge(toVal.state, fromVal.state),
    actions: merge(toVal.actions, fromVal.actions)
  }
}

# 经典案例高级用法

  实际项目中一般都会存在 列表(List) 这种很常见的案例,本文将介绍怎么利用mixin来实现一个能高复用的混入模型,并拆解分析各个步骤要点

$ 代码及设计

  • file: assets/mixins/list.js
module.exports = {
  data () {
    return {
      list: [],  // 列表数据
      page: 1,   // 当前页码
      limit: 10,  // 单页条数
      total: 0   // 总条数
    }
  },
  created () {
    this.initList()
  },
  watch: {
    page: 'loadData'
  },
  methods: {
    /**
     * @func 获取请求参数 默认只传递index, limit。也可以由外部构建合并参数
     * @param params
     * @returns {*}
     */
    getparams (params) {
      return Object.assign({
        index: this.page,
        limit: this.limit
      }, params)
    },

    /**
     * @func 查询结果压入list,注意Vue监听的特性,更新数组应用push,有格式需要处理则传入filter函数
     * @param list-加载更多返回的数据列表, filter-数据过滤函数
     */
    pushToList (list, filter) {
      list.forEach(item => {
        let it = typeof filter == 'function' ? filter(item) : item
        this.list.push(it)
      })
    },
    
    /**
     * @func 加载更多
     */
    loadMore () {
      this.page++
    },

    /**
     * @func 初始化列表
     * /
    initList () {
      this.page = 1
      this.list = []
      this.loadData()
    },

    /**
     * @overwrite
     * @func 加载数据方法,组件中必须根据自己需要重写该方法,否则无法加载数据
     */
    loadData () {
      // please overwrite me
    }
  }
}

$ API 及 README

  • 一个列表的基本属性
属性 作用或备注
list 列表
page 页码
limit 每页条数
total 总条数
  • 基本方法
方法 作用或备注
initList() 初始化列表
loadData() 加载数据(组件请重写)
loadMore() 加载更多
  • 扩展方法:主要用于参数或结果的处理
方法 作用或备注
getParams() 获取HTTP请求参数
pushToList() 数据处理方法,新数据入队列

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

$ 提示:vue监听数组变化

  Vue观察数组变化主要通过以下7个方法(push、pop、shift、unshift、splice、sort、reverse),通过prototype添加或下标方式将不能成功被捕获

$ 问题:非初始化情况下使用

  在keep-alive的应用下使用route-->data()的钩子中执行初始化,会发现初始化了两次

route: {
    data () {
      this.initList()
    }
}

$ 原因:mixin合并策略导致

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

$ 解决办法: 自定义选项

  自定义选项doNotInit,通过该选项来判断是否需要在组件创建完毕之后就初始化
  在调用该mixins的组件中 添加这么一个选项,就可以让组件判断通过create初始化,还是通过route->data()钩子来初始化

created () {
  let option = this.$options.doNotInit
  if (!option) {
    this.initList()
  }
}

$ 使用(调用)混入

  • file: anyVueCompontent.vue
import List  from './../assets/mixins/list'
export default {
  mixins: [ List ],
  data () {
    return {
      // 除列表外其他属性
    }
  },
  methods: {
    loadData () {
        this.$http.post(yourApiUrl, this.getParams()).then(res => {
          // TODO: some logic
        })
    }
  },
  doNotInit: true,  // 指定为created不执行初始化
  route: {
    data () {
      this.initList()
    }
  }
}

你可能感兴趣的:(Vue高级API - mixins(含案例))