侧边栏壁纸
博主头像
AngusWong's博客 博主等级

行动起来,活在当下

  • 累计撰写 25 篇文章
  • 累计创建 26 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

Vue混入mixin

Administrator
2021-04-09 / 0 评论 / 0 点赞 / 5 阅读 / 0 字

基础

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。 例子:
// 定义一个混入对象
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

// 定义一个使用混入对象的组件
var Component = Vue.extend({
  mixins: [myMixin]
})

var component = new Component() // => "hello from mixin!"

选项合并

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。 比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。
var mixin = {
  data: function () {
    return {
      message: 'hello',
      foo: 'abc'
    }
  }
}

new Vue({
  mixins: [mixin],
  data: function () {
    return {
      message: 'goodbye',
      bar: 'def'
    }
  },
  created: function () {
    console.log(this.$data)
    // => { message: "goodbye", foo: "abc", bar: "def" }
  }
})
同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
var mixin = {
  created: function () {
    console.log('混入对象的钩子被调用')
  }
}

new Vue({
  mixins: [mixin],
  created: function () {
    console.log('组件钩子被调用')
  }
})

// => "混入对象的钩子被调用"
// => "组件钩子被调用"
值为对象的选项,例如 methodscomponents 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
var mixin = {
  methods: {
    foo: function () {
      console.log('foo')
    },
    conflicting: function () {
      console.log('from mixin')
    }
  }
}

var vm = new Vue({
  mixins: [mixin],
  methods: {
    bar: function () {
      console.log('bar')
    },
    conflicting: function () {
      console.log('from self')
    }
  }
})

vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"
注意:Vue.extend() 也使用同样的策略进行合并。

全局混入

混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,这可以用来为自定义选项注入处理逻辑。
// 为自定义的选项 'myOption' 注入一个处理器。
Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})

new Vue({
  myOption: 'hello!'
})
// => "hello!"

重点事项

混入的变量,方法都可当本地方法一样调用,非常方便,可以把同样的代码放入Minxins中复用 示例代码
@/view/mixins/common.js
import SearchForm from '@/view/public/table-form';
import screenfull from 'screenfull';
import { httpDelete, httpGetParams, httpPost } from '@api/data';
import axios from 'axios';

export default {
    components: {
        SearchForm
    },
    data () {
        return {
            loading: false,
            loadingSubmit: false,
            columnsDisplay: [],
            datas: [],
            page: 1,
            pageSize: 40,
            total: 0,
            filterValue: {},
            formModal: false,
            formParams: {},
            editIndex: -1,
            formEdit: null,
            searchParams: {},
            tableSize: 'default',
            tableFullscreen: false,
            tableHeight: 500
        }
    },
    computed: {
        // 动态设置列
        tableColumns () {
            const columns = [...this.columns];
            return columns.filter(item => item.show);
        },

        searchValue: function () {
            let re = {
                pageSize: this.pageSize,
                page: this.page
            }
            return Object.assign(re, this.searchParams, this.filterValue)
        }
    },
    methods: {
        rowClassName: function (row, index) {
            if (row.hidden) {
                return 'row-hidden'
            }
            return ''
        },
        changeSearchParams (params) {
            if (params) {
                this.searchParams = params
            } else {
                this.searchParams = {}
            }
            this.page = 1
            this.getData()
        },
        getData () {
            let _this = this
            _this.datas = []
            if (this.cancel) {
                this.cancel('cancel')
            }
            _this.loading = true
            httpGetParams(_this.getDataUrl, _this.searchValue, new axios.CancelToken(function executor (c) {
                _this.cancel = c
            })).then(res => {
                _this.datas = res.data
                _this.total = parseInt(res.total)
                _this.loading = false
            }).catch(() => {
                _this.loading = false
                // console.log(err)
            })
        },
        handleAdd: function () {
            this.editIndex = -1
            this.formEdit = JSON.parse(JSON.stringify(this.formParams))
            this.formModal = true
        },
        handleEdit: function (row, index) {
            this.editIndex = index
            this.formEdit = JSON.parse(JSON.stringify(row))
            this.formModal = true
        },
        handleDel: function (row, index) {
            let _this = this
            if (_this.cancel) {
                _this.cancel('cancel')
            }
            _this.$Modal.confirm({
                title: _this.$t('common.del_confirm_title'),
                content: _this.$t('common.del_confirm_content'),
                onOk: function () {
                    httpDelete(_this.delUrl + '/' + row.id, null, new axios.CancelToken(function executor (c) {
                        _this.cancel = c
                    }))
                        .then((data) => {
                            _this.$Message.success(_this.$t('common.del_success'))
                            _this.datas.splice(index, 1)
                        })
                        .catch((error) => {
                            if (error.message !== 'cancel') {
                            }
                        })
                }
            })
        },
        transformFormInfo: function (formInfo) {
            return { ...formInfo }
        },
        saveData: function (formInfo) {
            let _this = this
            if (this.cancel) {
                this.cancel('cancel')
            }
            let url = _this.editUrl
            if (this.editIndex > -1) {
                url = url + '/' + formInfo.id
            }
            _this.loadingSubmit = true
            httpPost(url, this.transformFormInfo(formInfo), new axios.CancelToken(function executor (c) {
                _this.cancel = c
            })).then(res => {
                _this.loadingSubmit = false
                _this.$Message.success(_this.$t('common.operate_success'))
                _this.formModal = false
                if (_this.editIndex === -1) {
                    _this.datas.splice(0, 0, res)
                } else {
                    _this.datas.splice(_this.editIndex, 1, res)
                }
            }).catch(() => {
                _this.loadingSubmit = false
                // console.log(err)
            })
        },
        // 表格全屏
        handleFullscreen () {
            this.tableFullscreen = !this.tableFullscreen;
            if (this.tableFullscreen) {
                screenfull.request(this.$refs.card.$el);
            } else {
                screenfull.exit();
            }
        },
        // 改变表格尺寸
        handleChangeTableSize (size) {
            this.tableSize = size;
        },
        // 刷新表格数据
        handleRefresh () {
            this.getData();
        },
        // 重置表格列设置
        handleResetColumn () {
            this.columns = this.columns.map((item, i) => {
                const newItem = item;
                newItem.show = this.columnsDisplay[i];
                return newItem;
            });
        },
        // 切换页码
        pageChange: function (page) {
            this.page = page
            this.getData()
        },
        // 切换每页条数
        handleChangePageSize (size) {
            this.pageSize = size;
            this.getData();
        },
        // 改变表格高度
        changeTableHeight: function () {
            this.$nextTick(() => {
                this.tableHeight = window.innerHeight - this.calOffsetTop(this.$refs.table.$el) - this.$refs.pageFooter.$el.offsetHeight - 16
            })
        },
        calOffsetTop: function (el) {
            if (!el.offsetParent) {
                return el.offsetTop
            } else {
                return el.offsetTop + this.calOffsetTop(el.offsetParent)
            }
        }
    },
    mounted () {
        this.changeTableHeight()
        window.onresize = () => {
            this.changeTableHeight()
        }
    },
    created () {
        if (this.columns) {
            this.columnsDisplay = this.columns.map(_ => !!_.show)
        }
    }
}
  把增删改查放到一起,把表格高度控制放在一起,vue文件中的调用如下,这是一个防伪码批次管理
<template>
  <div>
    <Card :bordered="false" dis-hover class="list-table-list-card ivu-mt" ref="card">
      <SearchForm ref="form" :search-params="searchOption" @on-submit="changeSearchParams"
                  @on-reset="changeSearchParams" @on-collapse="changeTableHeight"/>
      <Button type="primary" icon="md-add" @click="handleAdd">{{ $t('common.add') }}</Button>&nbsp;
      <div class="ivu-inline-block ivu-fr">
        <Dropdown @on-click="handleChangeTableSize" trigger="click">
          <Tooltip class="ivu-ml" :content="$t('common.density')" placement="top">
            <i-link>
              <Icon size="16" type="md-list"/>
            </i-link>
          </Tooltip>
          <DropdownMenu slot="list">
            <DropdownItem name="default" :selected="tableSize === 'default'">{{ $t('common.default') }}</DropdownItem>
            <DropdownItem name="large" :selected="tableSize === 'large'">{{ $t('common.large') }}</DropdownItem>
            <DropdownItem name="small" :selected="tableSize === 'small'">{{ $t('common.small') }}</DropdownItem>
          </DropdownMenu>
        </Dropdown>
        <Tooltip class="ivu-ml" :content="tableFullscreen ? $t('common.exit_fullscreen') : $t('common.fullscreen')" placement="top">
          <i-link @click.native="handleFullscreen">
            <Icon size="16" :custom="tableFullscreen ? 'i-icon i-icon-exit-full-screen' : 'i-icon i-icon-full-screen'"/>
          </i-link>
        </Tooltip>
        <Tooltip class="ivu-ml" :content="$t('common.refresh')" placement="top">
          <i-link @click.native="handleRefresh">
            <Icon size="16" custom="i-icon i-icon-refresh"/>
          </i-link>
        </Tooltip>
        <Dropdown trigger="click">
          <Tooltip class="ivu-ml" :content="$t('common.col_setting')" placement="top">
            <i-link>
              <Icon size="16" type="md-options"/>
            </i-link>
          </Tooltip>
          <DropdownMenu slot="list">
            <div class="ivu-p-8">
              <Row>
                <Col span="12">{{ $t('common.col_show') }}</Col>
                <Col span="12" class="ivu-text-right">
                  <i-link link-color @click.native="handleResetColumn">{{ $t('common.reset') }}</i-link>
                </Col>
              </Row>
            </div>
            <Divider size="small" class="ivu-mt-8 ivu-mb-8"/>
            <li class="ivu-dropdown-item" v-for="item in columns" :key="item.title" v-if="item.title"
                @click="item.show = !item.show">
              <Checkbox v-model="item.show"></Checkbox>
              <span>{{ item.title }}</span>
            </li>
          </DropdownMenu>
        </Dropdown>
      </div>
      <Table
          border
          ref="table"
          :height="tableHeight"
          :columns="tableColumns"
          :row-class-name="rowClassName"
          :data="datas"
          :loading="loading"
          :size="tableSize"
          class="ivu-mt-8">
        <template slot-scope="{ row, index }" slot="nums">
          <span class="my-count-primary">{{ row.sns_count }}</span>
          <ButtonGroup style="float: right" >
            <Button size="small" type="warning" class="right" @click="handleBatchAdd(row)">{{ $t('sn.add_sn') }}</Button>
            <Button size="small" type="info" @click="handExport(row)">{{ $t('sn.export_sn') }}</Button>
          </ButtonGroup>
        </template>
        <template slot-scope="{ row, index }" slot="action">
          <ButtonGroup>
            <Button size="small" type="primary" @click="handleEdit(row,index)">{{ $t('common.edit') }}</Button>
            <Button size="small" type="error" @click="handleDel(row,index)">{{ $t('common.del') }}</Button>
          </ButtonGroup>
        </template>
      </Table>
      <Row style="text-align: right;margin-top: 5px;margin-bottom: -12px;" ref="pageFooter">
        <Page
            :total="total"
            :current.sync="page"
            show-total
            show-sizer
            :page-size="pageSize"
            :page-size-opts="[20,40,60,80,100]"
            @on-change="pageChange"
            @on-page-size-change="handleChangePageSize"/>
      </Row>
    </Card>
    <Modal v-model="formModal" width="800" :title="editIndex===-1?$t('sn.add_batch'):$t('sn.edit_batch')" :transfer="false" :footer-hide="true" :mask-closable="false">
      <BatchForm v-if="formModal" :formData="formEdit" :loading="loadingSubmit" @on-success-valid="saveData"></BatchForm>
    </Modal>

    <Modal v-model="batchAddModal" width="800" :title="$t('sn.batch_add_sn')" :transfer="false" :footer-hide="true" :mask-closable="false" :closable="allowClose">
      <BatchAdd v-if="batchAddModal" :sel-batches="selBatches" :isLockBatches="true" @on-lock-close="lockClose" @on-complete="closeBatchModal"></BatchAdd>
    </Modal>
  </div>
</template>
<script>
    import { httpGetParams } from '@/api/data'
    import BatchForm from '@/view/sn/lib/batchForm';
    import BatchAdd from '@/view/sn/lib/batchAdd';
    import excel from '@/libs/excel';
    import common from '@/view/mixins/common';
    export default {
        name: 'Batch',
        mixins: [common],
        components: {
            BatchForm,
            BatchAdd
        },
        data () {
            return {
                getDataUrl: '/admin/batches',
                editUrl: '/admin/batch',
                delUrl: '/admin/batch',
                selBatches: {},
                searchOption: {
                    intro: {
                        title: this.$t('sn.intro'),
                        type: 'input',
                        value: ''
                    },
                    nums: {
                        title: this.$t('sn.nums') + this.$t('sn.gt_eq'),
                        type: 'number',
                        value: ''
                    }
                },
                columns: [
                    {
                        title: 'ID',
                        key: 'id',
                        width: 60,
                        align: 'center',
                        fixed: 'left',
                        show: true
                    },
                    {
                        title: this.$t('sn.intro'),
                        key: 'intro',
                        minWidth: 150,
                        show: true
                    },
                    {
                        title: this.$t('sn.nums'),
                        slot: 'nums',
                        minWidth: 150,
                        show: true
                    },
                    {
                        title: this.$t('common.updated_at'),
                        key: 'updated_at',
                        minWidth: 180,
                        show: true,
                        render: (h, params) => {
                            const date = this.$options.filters.dateformat(params.row.updated_at * 1000)
                            return h('div', date)
                        }
                    },
                    {
                        title: this.$t('common.operate'),
                        slot: 'action',
                        align: 'center',
                        fixed: 'right',
                        width: 140,
                        show: true
                    }
                ],
                formParams: {
                    id: 0,
                    intro: ''
                },
                batchAddModal: false,
                allowClose: true,
                exportBatch: 0,
                excelExportData: [],
                retry: 0
            }
        },
        methods: {
            lockClose: function () {
                this.allowClose = false
            },
            handleBatchAdd: function (row) {
                this.selBatches[row.id] = row.intro
                this.batchAddModal = true
            },
            closeBatchModal: function () {
                this.batchAddModal = false
                if (!this.allowClose) { this.getData() }
            },
            handExport: function (row) {
                this.$Spin.show({
                    render: (h) => {
                        return h('div', [
                            h('Icon', {
                                'class': 'spin-icon-load',
                                props: {
                                    type: 'ios-loading',
                                    size: 40
                                }
                            }),
                            h('div', { style: { 'font-size': '20px' } }, this.$t('sn.export_tip'))
                        ])
                    }
                });
                this.exportBatch = row.id
                this.excelExportData = []
                this.retry = 0
                this.getExportData(1)
            },
            getExportData: function (page) {
                let searchValue = {
                    page: page,
                    pageSize: 1000
                }
                let _this = this
                httpGetParams('/admin/sns/' + this.exportBatch, searchValue, null).then(res => {
                    res.data.forEach(item => {
                        _this.excelExportData.push(item)
                    })
                    if (res.to >= res.total) {
                        _this.excelExport()
                    } else {
                        _this.getExportData(page + 1)
                    }
                }).catch((err) => {
                    console.log(err)
                    if (_this.retry++ >= 2) {
                        _this.$Spin.hide()
                        _this.$Message.error(this.$t('sn.export_fail'))
                        _this.excelExportData = []
                    } else {
                        _this.getExportData(page)
                    }
                })
            },
            excelExport: function () {
                const title = [this.$t('sn.sn')]
                const key = ['sn']
                excel.export_array_to_excel({ key, data: this.excelExportData, title, filename: this.$t('sn.sn') + '-' + this.exportBatch + '-' + (new Date()).getTime(), autoWidth: true })
                this.$Spin.hide()
            }
        },
        created () {
            this.getData()
        }
    }
</script>
<style lang="less">
.my-count-primary{
  color:#ff9900;
  font-weight: bold;
}
</style>
 
0

评论区