mixin 混入

一、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的区别:

  1. vuex中的方法和变量是可以相互读取并相互更改的,mixin不会。mixin可以定义公用的变量或方法,但是mixin中的数据是不共享的,也就是每个组件中的mixin实例都是不一样的,都是单独存在的个体,不存在相互影响的;
  2. 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()
      }
    },
  },
}

  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值