什么是混合mixin
首先,谈到混合mixin这个词,并不是只有vue中才有混合的概念。其实在css的预处理器less或者stylus或者scss中也有类似的混合函数mixin的概念。只不过css预处理器中的混合是用来实现样式的复用的。而vue中的混合mixin是用来实现功能的复用的。
less预处理器混合mixin的用法步骤参见我之前的文章: https://juejin.cn/post/6956826951541587982/
官方是如何定义混合mixin的
文档是这样定义的
混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
咋一看,说的不太接地气,那我们来用大白话翻译一下吧
大白话翻译
混入 (mixin) 提供了一种非常灵活的方式
混入功能很叼
来分发 Vue 组件中的可复用功能。
使用混入可以实现在.vue组件中的重复使用的功能。想想有哪些重复使用的功能呢?比如做后台管理系统常常需要使用的分页功能、比如项目中很多的地方都要使用的弹出Message消息提示功能。其实有很多,本文就以分页功能应用场景举例说明
一个混入对象可以包含任意组件选项。
混合是个对象?哇,传说中的面向对象OOP的思想,混合更有点继承的味道吧。混合包含任意组件选项?组件选项不就是data、computed、watch、methods 以及各种生命周期钩子吗,也就是说混合中也可以像组件中那样定义这些组件选项,以供‘混入’使用
当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项
在vue中使用一个‘东西’,一般的套路大致都是 定义 --> 引入 --> 注册 --> 使用。既然在某个.vue中使用混合,那么引入了以后,就相当于拥有混合中的东西了。
实际使用步骤(分页组件使用混合)
先看一下最终的效果图
假设我们的项目中有两个路由页面都用到了分页组件,分页一般搭配表格,为了方便简洁,这里的话,我们就不放表格了。我们要用mixin实现这样的分页效果
第一步,新建好项目
App.vue文件放置对应路由导航和视图结构
// App.vue文件 <template> <div id="app"> <div class="top"> <router-link to="/">路由页面一</router-link> <router-link to="/about">路由页面二</router-link> </div> <div class="bottom"> <router-view></router-view> </div> </div> </template>
路由中这样定义一下
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter) const router = new VueRouter({ routes: [ { path: "/", component: resolve => require(['../views/home.vue'], resolve), }, { path: "/about", component: resolve => require(['../views/about.vue'], resolve), }, ] }) export default router
home.vue和about.vue使用饿了么UI的分页组件(about.vue文件就不放置了,结构基本上一样的)
<template> <div> <div class="block"> <span class="demonstration">第11111个分页中使用混合</span> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :page-sizes="[10, 20, 30, 40]" :current-page="paging.pageIndex" :page-size="paging.pageSize" :total="paging.total" layout="total, sizes, prev, pager, next, jumper" background > </el-pagination> </div> </div> </template> <script> export default { name: "home", data() { return { paging: { pageIndex: 1, pageSize: 10, total: 100, }, }; }, methods: { handleSizeChange(val) { this.paging.pageIndex = 1; this.paging.pageSize = val; }, handleCurrentChange(val) { this.paging.pageIndex = val; }, }, }; </script>
这样的话,两个路由页面的分页效果都有了。只不过还没用到mixin。这个案例中因为home.vue和about.vue文件中都有分页功能,而使用分页功能就要定义 第几页pageIndex、每页显示几条pageSize、总条数total、翻页改变的方法handleCurrentChange、和条数改变的方法handleSizeChange
这些变量和方法。这些变量和方法就属于公共的复用的代码,因为可能好多地方都要用到,我们可以把这些复用的放置在混合文件中,哪里需要使用,哪里就混入进来即可。
第二步(定义一个mixin文件并暴露)
第三步(引入混合注册并使用混合)
首先把原本写好的data中的分页变量和methods中的分页方法删除掉
当然删掉了会报错,因为分页组件需要这些变量和方法,所以接下来我们使用混合进来的变量和方法
引入混合并注册使用
<template> <div> <div class="block"> <span class="demonstration">第11111个分页中使用混合</span> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :page-sizes="[10, 20, 30, 40]" :current-page="paging.pageIndex" :page-size="paging.pageSize" :total="paging.total" layout="total, sizes, prev, pager, next, jumper" background > </el-pagination> </div> </div> </template> <script> // 引入混合 import mixin from '../mixin/index' export default { name: "home", mixins: [mixin] // 注册即使用 }; </script>
另外一个about.vue文件也如法炮制即可,就能实现想要的功能了。篇幅有限不赘述
补充一(查看具体引入的混合)
其实也可以换个角度理解,就是混合是把混合文件中定义的变量方法之类的挂载到某个具体的.vue文件上,也就是挂载到某个具体的vue示例上,所以我们打印这个vue示例,是可以看到挂载进来的mixin代码的,如下:
<script>
import mixin from '../mixin/index' // 引入混合
export default {
name: "home",
mixins: [mixin], // 注册即使用
mounted() {
console.log('打印vue示例this,查看混合',this);// 看这里、看这里、看这里
},
};
</script>
打印结果如下:
很显然,混合中的变量和方法已经被挂载到这个vue组件实例上了,既然挂载到这个示例上了,也就意味着,在template中的html代码里面可以使用了,所以使用混合的确可以使得我们写代码变得更加优雅
补充二(mixin代码与组件代码冲突了怎么办)
- 首先,不要重复
混合中定义的代码就不要与组件中的代码一样
- 其次,以组件中的为准
简而言之,组件中没有的,混合中有,就把混合的拿过来;组件中有的,混合中也有,就不要混合中的,只保留组件中的
补充三 (全局混入,慎用)
上述代码案例我们使用的是局部的mixin,其实也挺方便,哪里需要使用,就哪里去引入混合。使用全局混合虽然省去了,引入注册的这一步,但是全局混合中定义的变量和方法,在每个组件上都会挂载上去,这样的话也不太好。毕竟官方也提醒我们,使用全局混入一定要格外小心
总结
mixin VS vuex
使用vuex也可以管理状态,和混合的区别就是vuex中的数据一但改变,所有的相关的依赖vuex中的都会改变,但是使用mixin,不过出现这样的情况。毕竟vuex是公用的,mixin是独立的