一、mixin概念
mixin是vue提供的一种方式来分发vue组件的可复用功能,可以将相同的方法、字段等抽离出来,避免重复定义。混入分为局部混入和全局混入,一个mixin对象可以包含任意组件选项,data、methods、mounted等。
当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。当组件使用了mixin时, mixin中的生命周期函数会先执行,然后在执行组件中的生命周期。
二、使用
1、局部混入
新建mixins文件夹,并在mixins目录下创建一个mixin.js文件,代码如下:
const mixin = {
data() {
return {
msg: "我是张三"
}
},
methods: {
mixinTest() {
console.log(this.msg)
}
}
}
export default mixin;
在需要的页面中引入:
<template>
<div>{{msg}}</div>
</template>
<script>
import mixin from '../mixins/mixin'
export default {
mixins: [mixin],
data() {
return {
}
}
mounted() {
this.mixinTest()
}
}
//我是张三
2、全局混入
在main.js中直接引入使用即可。
import mixin from './mixins/mixin'
Vue.mixin(mixin)
这样就可以直接在组件中使用mixin中定义的字段和方法等。
三、mixin混入的注意事项
- mixin 中定义的方法和参数在各组件中不共享,即当前组件对mixins的属性的修改,其他也引用了这个mixins的组件不会受影响;
- mixin中定义的生命周期函数会比引用组件的生命周期先执行, 会和组件中定义的methods,created等选项合并调用;
- mixin对象里的(components、methods 、computed、data)这些选项,混入组件时选项会被合并,重名冲突时优先采用组件中定义的数据
- 如果同时引入多个mixin对象, 执行顺序和引入顺序一致;
四、以uniapp开发小程序举例,使用mixin实现各个页面的分享功能
在小程序中如果想实现分享功能,需要在各个组件中单独写分享方法,如果页面太多的话,非常麻烦。所以可以使用mixin来简化这个流程。
1.首先在mixins目录下新建share.js
export default {
onShareAppMessage(res) {
return {
path:'/pages/tabIndex/tabIndex',
success(res) {
uni.showToast({
title: '分享成功'
})
},
fail(res) {
uni.showToast({
title: '分享失败',
icon: 'none'
})
}
}
}
}
2、在main.js中引入,并混入到vue对象上。
import share from './mixins/share.js'
Vue.mixin(share)
五、mixin混入对象和Vuex的区别:
- vuex中的方法和变量是可以相互读取并相互更改的,mixin不会。mixin可以定义公用的变量或方法,但是mixin中的数据是不共享的,也就是每个组件中的mixin实例都是不一样的,都是单独存在的个体,不存在相互影响的;
- mixin可以定义公用的变量或方法,但是mixin中的数据是不共享的,也就是每个组件中的mixin实例都是不一样的,都是单独存在的个体,不存在相互影响的;
六、常用mixin
下面是我项目里面封装的常用的一些列表mixin方法:
其中包含获取列表数据、列表查询、列表重置、分页、筛选变化时触发、排序变化时触发、折叠、新增、删除、编辑、导出入excel等方法
export const ListMixin = {
data() {
return {
// 公用接口
api: {
getNewId: 'commonRest/getNewId',
},
/* table加载状态 */
loading: false,
/* 分页参数 */
pagination: {
current: 1,
pageSize: 10,
total: 0,
pageSizeOptions: [10, 20, 30, 50, 100],
showQuickJumper: true,
showSizeChanger: true,
},
// 查询参数
searchForm: {},
/* 排序参数 */
sorter: {
sortColumn: '',
isAsc: '',
},
/* 查询折叠 */
toggleSearchStatus: false,
/* 数据源 */
tableData: [],
// 展开收起
folding: false,
//列表页面查询条件默认宽度
searchCol: {
lg: 6, md: 12, sm: 24,
},
ExportXlsLoading: false,
}
},
created() {
if (this.$route.query.parameter) {
var parameter = JSON.parse(this.$route.query.parameter)
for (let items in parameter) {
this.searchForm[items] = parameter[items]
}
}
this.loadData()
},
methods: {
// 获取列表数据
loadData(arg) {
return new Promise((resolve, error) => {
if (this.url !== undefined && this.url.list !== undefined &&
this.url.list !== '') {
//加载数据 若传入参数1则加载第一页的内容
if (arg === 1) {
this.pagination.current = 1
}
this.loading = true
this.$axios.getAction(
this.url.list,
{
...this.searchForm,
...this.sorter,
current: this.pagination.current,
size: this.pagination.pageSize,
}
).then(res => {
this.pagination.total = res.obj.total
this.tableData = res.obj.records
resolve(true)
}).finally(() => this.loading = false)
}
})
},
// 列表查询
handleSearch(event) {
this.loadData(1)
},
// 列表重置
handleReset() {
this.searchForm = {
sysCode: sessionStorage.getItem('sysCode')
}
this.pagination.current = 1
this.loadData()
},
//分页、筛选变化时触发
handlePageChange({ pageSize, current }) {
this.pagination.current = current
this.pagination.size = pageSize
this.loadData()
},
//排序变化时触发
handleSortChange({ prop, order }) {
let isAsc = order === 'ascending' ? true : false
this.sorter.sortColumn = prop
this.sorter.isAsc = isAsc
this.loadData()
},
//折叠
handleToggleSearch() {
this.toggleSearchStatus = !this.toggleSearchStatus
},
// 新增
handleAdd() {
this.$refs.modalForm.add()
this.$refs.modalForm.title = '新增'
this.$refs.modalForm.visible = true
},
addWithId(param) {
//取消选中效果
this.$refs.singleTable.setCurrentRow()
this.$axios.getAction('commonRest/getNewId').then(res => {
const newData = {
id: 'new' + res,
...param
}
this.$refs.modalForm.add(newData)
this.$refs.modalForm.title = '新增'
this.$refs.modalForm.visible = true
})
},
// 编辑
handleEdit(record) {
this.$refs.modalForm.edit({ ...record })
this.$refs.modalForm.title = '编辑'
this.$refs.modalForm.visible = true
},
// 编辑
editById(id) {
this.$refs.modalForm.queryById(id).then(() => {
this.$refs.modalForm.title = '编辑'
this.$refs.modalForm.visible = true
this.$refs.modalForm.disabled = false
})
},
// 查看
handleView(record) {
this.$refs.modalForm.edit({ ...record })
this.$refs.modalForm.title = '查看'
this.$refs.modalForm.visible = true
this.$refs.modalForm.disabled = true
},
// 查看
viewById(id) {
this.$refs.modalForm.queryById(id).then(() => {
this.$refs.modalForm.title = '查看'
this.$refs.modalForm.visible = true
this.$refs.modalForm.disabled = true
})
},
// 删除
handleDel(id) {
this.$confirm('此操作将永久删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
this.$axios.deleteAction(this.url.del, {
id: id,
}).then(res => {
if (res.result) {
this.$message.success(res.msg)
} else {
this.$message.error(res.msg)
}
this.loadData()
})
})
},
handleStatusChange(row) {
this.$confirm('您确定要修改状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
this.$axios.putForm(this.url.updateStatus, {
id: row.id,
isValid: !row.isValid,
version: row.version,
}).then(res => {
if (res.result) {
this.$message.success(res.msg)
row.isValid = !row.isValid
this.loadData()
} else {
this.$message.error(res.msg)
}
})
})
},
//导出excel
handleExportXls(fileName) {
this.ExportXlsLoading = true
return new Promise(async (resolve, reject) => {
if (!fileName || typeof fileName != "string") {
fileName = "导出文件"
}
let param = { ...this.searchForm, ...this.sorter, };
if (this.selectedRowKeys && this.selectedRowKeys.length > 0) {
param['selections'] = this.selectedRowKeys.join(",")
}
this.$axios.downFile(this.url.exportXls, param).then(data => {
if (!data) {
this.$message.warning("文件下载失败")
reject()
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data]), fileName + '.xls')
} else {
let url = window.URL.createObjectURL(new Blob([data]))
let link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName + '.xlsx')
document.body.appendChild(link)
link.click()
document.body.removeChild(link); //下载完成移除元素
window.URL.revokeObjectURL(url); //释放掉blob对象
resolve()
}
this.ExportXlsLoading = false
})
})
},
//导入excel
handleUploadXls() {
this.$refs.uploadExcelDialog.visible = true
}
},
}
以及封装的我项目里面常用的CRUD表单mixin方法:
import { mapState } from 'vuex'
export const FormMixin = {
computed: {
...mapState({
drawerSize: state => state.themeModule.drawerSize,//使用ES6的箭头函数来给count赋值
dialogSize: state => state.themeModule.dialogSize,//使用ES6的箭头函数来给count赋值
labelPosition: state => state.themeModule.labelPosition,//使用ES6的箭头函数来给count赋值
deviceType: state => state.themeModule.deviceType,//使用ES6的箭头函数来给count赋值
}),
},
data () {
return {
model: {},
initModel: {},//默认值
confirmLoading: false,
title: '',
visible: false,
disabled: false,
ueConfig: {
// 编辑器不自动被内容撑高
autoHeightEnabled: false,
// 初始容器高度
initialFrameHeight: 400,
// 初始容器宽度
initialFrameWidth: '100%',
// 上传文件接口(这个地址是我为了方便各位体验文件上传功能搭建的临时接口,请勿在生产环境使用!!!)
// serverUrl: 'http://35.201.165.105:8000/controller.php',
serverUrl: `${this.$global.API}ueditor`,
// UEditor 资源文件的存放路径,如果你使用的是 vue-cli 生成的项目,通常不需要设置该选项,vue-ueditor-wrap 会自动处理常见的情况,如果需要特殊配置,参考下方的常见问题2
UEDITOR_HOME_URL: '/UEditor/',
},
autoAdaptive: {
lg: 8, md: 12, sm: 24,
// lg: 6, md: 12, sm: 24,
// lg: 12, md: 12, sm: 24,
},
}
},
created() {
let obj = JSON.parse(JSON.stringify(this.initModel))
this.model = { ...obj }
},
methods: {
add (newData) {
this.disabled = false
if (newData) {
//考虑新增时候model中会有默认初始值
// this.model =newData;
let obj = {};
obj = JSON.parse(JSON.stringify(this.initModel))
this.model = { ...obj, ...newData }
}
},
edit (record) {
this.disabled = false
this.model = record
},
queryById (id) {
return new Promise((resolve) => {
if (this.url !== undefined && this.url.queryById !== undefined &&
this.url.queryById !== '') {
this.$axios.getAction(this.url.queryById, { id: id }).then(res => {
resolve(res)
if (res.result) {
this.model = res.obj
} else {
this.$message.error(res.msg)
}
}).finally(() => {
resolve()
})
} else {
resolve()
}
})
},
save () {
if(this.model.cardNo && this.model.cardNo.length < 10){
this.model.cardNo = '0'.repeat(10 - this.model.cardNo.length) + this.model.cardNo;
}
if (this.url !== undefined && this.url.save !== undefined && this.url.save !== '') {
this.$refs.ruleForm.validate(valid => {
if (valid) {
this.confirmLoading = true
this.$axios.postAction(this.url.save, this.model).then(res => {
if (res.result) {
this.$message.success(res.msg)
this.$emit('ok')
this.handleClose()
} else {
this.$message.error(res.msg)
}
}).finally(() => {
//弹窗动画时间
setTimeout(() => {
this.confirmLoading = false
}, 301)
})
}
})
}
},
// 关闭弹框
handleClose () {
this.$emit('close')
this.visible = false
this.model = {id:'',...this.initModel}
if (this.$refs.ruleForm !== undefined) {
this.$refs.ruleForm.clearValidate()
}
},
},
}