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()
    }
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容