vue + vue-router + vuex + es6 + scss + webpackjavascript
后台系统有不少页面都有相似的增删改查操做,使用mixin效果很是好,重复的劳动大大减小。css
下面分4步来封装:vue
import { doPost } from "@/tools/request.js";
import { toStringValue } from "@/utils/util.js"
// toStringValue():给对象/对象数组的属性值为数值型的转为字符串型
/** @param {Object} o为表单默认要显示的默认值,若是无,就不填写,可选 */
export function createFn(o = {}) {
this.$refs.myForm && this.$refs.myForm.resetFields();
this.dialogForm.formData = Object.assign({}, toStringValue(o));
this.dialogForm.isEdit = false;
this.dialogForm.title = "新增";
this.dialogForm.isVisible = true;
}
export function editFn(row = {}) {
this.dialogForm.isEdit = true;
this.dialogForm.title = "编辑";
this.dialogForm.isVisible = true;
this.dialogForm.formData = Object.assign({}, toStringValue(row));
}
export function delFn(row, url) {
this.$confirm("确认删除该数据吗?", "提示", {
type: "warning"
}).then(
() => {
doPost(url, {
id: row.id
})
.then(res => {
this.$message.success("删除成功");
this.getData();
})
.catch(e => {
this.$message.error(e.message);
catchUrl(e, url)
});
}
).catch(() => {
this.$message.info("取消删除");
});
}
export function delFn2(row, url) {
this.$confirm("确认删除该数据吗?", "提示", {
type: "warning"
}).then(
() => {
doPost(url, {
id: row.id
})
.then(res => {
this.$message.success("删除成功");
this.getData();
})
.catch(e => {
this.$message.error(e.message);
catchUrl(e, url)
});
}
).catch(() => {
this.$message.info("取消删除");
});
}
export function submitFn(formName, url, isEdit) {
const title = isEdit ? '编辑' : '添加';
this.$refs[formName].validate(valid => {
if (valid) {
doPost(url, this.dialogForm.formData)
.then(() => {
this.$message.success(`${title}成功`);
this.getData();
this.dialogForm.isVisible = false;
})
.catch(e => {
// code=0,成功返回;反之,失败提示
if (e.code && e.code !== 0) {
this.$message.error(e.message);
}
catchUrl(e, url, `${title}`)
});
} else {
console.error("Error submit ----- Form invalid !");
return false;
}
})
}
export function getDataFn(url, param = {}) {
this.tableListLoading = true;
doPost(url, param)
.then(res => {
this.tableListLoading = false;
this.page.total = res.count;
this.tableList = res.list;
})
.catch(e => {
// code=0,成功返回;反之,失败提示
if (e.code && e.code !== 0) {
this.$message.error(e.message);
}
catchUrl(e, url)
this.tableListLoading = false;
});
}
export function getDataFn2(fn, param = {}) {
this.tableListLoading = true;
fn(param)
.then(res => {
this.tableListLoading = false;
this.page.total = res.count;
this.tableList = res.list;
})
.catch(e => {
catchFn(e, fn)
this.tableListLoading = false;
});
}
export function mulDelFn(url) {
if (!this.mulSels.length) {
this.$alert("请选择要删除的数据", "提示");
return;
}
const deleIdArr = this.mulSels.map(o => o.id);
this.$confirm("确认删除该数据吗?", "提示", {
type: "warning"
}).then(
() => {
doPost(url, {
ids: deleIdArr
})
.then(res => {
this.$message.success("删除成功");
this.getData();
})
.catch(e => {
catchUrl(e, url)
this.$confirm(e.message, "提示", {
type: "warning"
}).then(
() => {
this.dialogForm.isVisible = false;
}
);
});
}
).catch(() => {
this.$message.info("取消删除");
});
}
function catchUrl(e, url, detail) {
console.group(`Error found in doPost(${url})`)
if (detail) console.info(`--${detail}--报错!`)
console.error(e)
console.groupEnd()
}
function catchFn(e, fn) {
console.group(`Error found in method (${fn.name})`)
console.error(e)
console.groupEnd()
}
复制代码
import TABLE from "@/utils/tableConfig.js";
import * as formFn from "@/utils/formFn.js";
import { debounce, getQueryParam } from "@/utils/util.js";
import ZSelect from "@/components/ZSelect/ZSelect.vue";``
import ZPage from "@/components/ZPage/ZPage.vue";
export default {
components: { ZPage, ZSelect },
data() {
return {
searchFilters: {},
tableList: [],
tableListLoading: false,
page: {
size: 10,
current: 1,
total: 0
},
t: {
border: TABLE.border,
size: TABLE.size,
stripe: TABLE.stripe,
maxHeight: TABLE.maxHeight
}
};
},
methods: {
getData() {
const param = getQueryParam(this.searchFilters, this.page);
formFn.getDataFn.apply(this, [this.url.getData, param]);
},
dbnSearch() {
this.DSearchFn();
},
doSearch() {
this.page.current = 1;
this.getData();
},
dbnResetSearch() {
this.DResetSearchFn();
},
doResetSearch() {
this.searchFilters = {};
this.page.current = 1;
this.getData();
},
currentPageChange(p) {
this.page.current = p;
this.getData();
},
pageSizeChange(size) {
this.page.size = size;
this.getData();
},
indexMethod(idx) {
return (this.page.current - 1) * this.page.size + (idx + 1);
}
},
mounted() {
this.getData();
},
created() {
this.DSearchFn = debounce(() => this.doSearch());
this.DResetSearchFn = debounce(() => this.doResetSearch());
}
}
复制代码
import * as formFn from "@/utils/formFn.js";
import { debounce } from "@/utils/util.js";
import MulSelect from "@/components/ZSelect/MulSelect.vue";
export default {
components: { MulSelect },
data() {
return {
dialogForm: {
isEdit: false,
isVisible: false,
title: "",
formData: {},
formRule: {}
},
mulSels: [] //选中列,主要用于批量删除
};
},
watch: {
'dialogForm.isVisible': {
handler(newV) {
if (newV === false) {
this.$refs.myForm && this.$refs.myForm.resetFields();
}
}
}
},
methods: {
handleEdit(row, col, idx) {
formFn.editFn.apply(this, [row]);
},
handleDel(row, col, idx) {
formFn.delFn.apply(this, [row, this.url.delete]);
},
// 表单新增/编辑+表单重置 start
debounceSubmit(formName) {
this.DSubmitFn(formName);
},
doSubmitForm(formName) {
/* 分别是“修改”和“新增”的url */
let _url = this.dialogForm.isEdit ? this.url.update : this.url.create;
formFn.submitFn.apply(this, [formName, _url, this.dialogForm.isEdit]);
},
resetForm(formName) {
this.$refs[formName].resetFields();
},
handleBeforeClose() {
this.$refs["myForm"].resetFields();
this.dialogForm.isVisible = false;
},
// 表单新增/编辑+表单重置 end
// 批量选择-删除start
handleSelectionChange(val) {
this.mulSels = val;
},
handleMulDel() {
if (this.url && this.url.mulDel) {
formFn.mulDelFn.call(this, this.url.mulDel);
} else {
console.log('多选删除失败:获取不到删除地址');
}
},
// 批量选择-删除end
handleCreate() {
formFn.createFn.apply(this);
}
},
created() {
this.DSubmitFn = debounce(v => this.doSubmitForm(v));
}
}
复制代码
<template>
<section class="table-wrap">
<!-- 查询 -->
<div class="search">
<el-form :inline="true" :model="searchFilters">
<el-row>
<el-col :span="5">
<el-form-item label="客户名">
<el-input v-model="searchFilters.custName" placeholder="客户名"></el-input>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="城市">
<el-input v-model="searchFilters.cityName" placeholder="城市"></el-input>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="品牌">
<el-input v-model="searchFilters.brandName" placeholder="品牌"></el-input>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="上牌时间">
<el-date-picker type="month" v-model="searchFilters.firstLicenseTime" placeholder="上牌时间" value-format="yyyy-MM-dd HH:mm:ss"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="4">
<span class="search">
<el-button type="primary" @click.stop="dbnSearch">查询</el-button>
</span>
<span class="reset">
<el-button type="danger" @click.stop="dbnResetSearch">重置</el-button>
</span>
</el-col>
</el-row>
</el-form>
</div>
<!--列表-->
<el-table :data="tableList" highlight-current-row style="width: 100%;" v-loading="tableListLoading"
:stripe="t.stripe" :border="t.border" :size="t.size" :max-height="t.maxHeight" @selection-change="handleSelectionChange">
<el-table-column type="index" width="55" :index="indexMethod">
</el-table-column>
<el-table-column prop="custName" label="客户名" width="140">
</el-table-column>
<el-table-column prop="carInfo.brandName" label="品牌" width="140">
</el-table-column>
<el-table-column prop="carInfo.seriesName" label="系列" width="140">
</el-table-column>
<el-table-column prop="carInfo.modelName" label="车型" width="480">
</el-table-column>
<el-table-column prop="carInfo.firstLicenseTime" label="上牌时间" width="180">
</el-table-column>
<el-table-column prop="cityName" label="城市" width="100">
</el-table-column>
<el-table-column prop="mortgageAmount" label="按揭欠款" width="100">
</el-table-column>
<el-table-column prop="estimatePrice" label="评估金额" width="100">
</el-table-column>
<el-table-column prop="canLoanAmount" label="可贷金额" width="100">
</el-table-column>
<el-table-column label="操做" fixed="right" width="90px">
<template slot-scope="scope">
<span class="edit">
<el-button size="small" @click.stop="handleEdit(scope.row, scope.column, scope.$index)">查看</el-button>
</span>
</template>
</el-table-column>
</el-table>
<!-- 表格底部操做/分页 -->
<div class="table-bottom-wrap">
<div class="page-box">
<z-page @current-change="currentPageChange" :current-page="page.current" :total="page.total">
</z-page>
</div>
</div>
<!-- 新增-编辑 -->
<el-dialog :title="dialogForm.title" custom-class="addDialog" :visible.sync="dialogForm.isVisible">
<el-form :model="dialogForm.formData" :rules="dialogForm.formRule" ref="myForm" label-width="120px" label-position="right">
<el-row>
<el-col :span="12">
<el-form-item label="客户名" prop="custName">
<el-input v-model="dialogForm.formData.custName" placeholder="客户名" :disabled="true"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="品牌" prop="brandName">
<el-input v-model="dialogForm.formData.brandName" placeholder="品牌" :disabled="true"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="系列" prop="seriesName">
<el-input v-model="dialogForm.formData.seriesName" placeholder="系列" :disabled="true"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="车型" prop="modelName">
<el-input v-model="dialogForm.formData.modelName" placeholder="车型" :disabled="true"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="上牌世间" prop="firstLicenseTime">
<el-date-picker type="month" v-model="dialogForm.formData.firstLicenseTime" placeholder="上牌时间" :disabled="true"></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="城市" prop="cityName">
<el-input v-model="dialogForm.formData.cityName" placeholder="城市" :disabled="true"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="按揭欠款" prop="mortgageAmount">
<el-input v-model="dialogForm.formData.mortgageAmount" placeholder="按揭欠款" :disabled="true"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="评估金额" prop="estimatePrice">
<el-input v-model="dialogForm.formData.estimatePrice" placeholder="评估金额" :disabled="true"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="可贷金额" prop="canLoanAmount">
<el-input v-model="dialogForm.formData.canLoanAmount" placeholder="可贷金额" :disabled="true"></el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="行程(万千米)" prop="kilometers">
<el-input v-model="dialogForm.formData.kilometers" placeholder="行程(万千米)" :disabled="true"></el-input>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click.stop="dialogForm.isVisible = false">取 消</el-button>
</div>
</el-dialog>
</section>
</template>
<script>
import common from '@/mixins/common.js'
import cud from '@/mixins/cud.js'
export default {
mixins: [common, cud],
data() {
return {
url: {
getData: '/carEvaluationService/listCarEstimate'
}
}
}
}
</script>
复制代码
能够看到vue文件的逻辑部分被极大地简化了。java
3-一、vue-mixin合并说明webpack
## mixin合并
数据对象合并【data(一层属性深度浅合并)】:多个合并在一块儿,有冲突的以组件数据优先;
钩子函数合并【created、mounted等】:多个合在一块儿,先调用mixin的再调用组件自己的;【混为同一个数组,因此都被调用】
对象选项合并【methods、components、directives】:mixin的会被vm实例的对应项覆盖。【混为同一个对象,因此键有冲突时只选一个】
复制代码
3-二、约定通用函数方法名和属性名 例如:es6
url: {
getData: "/custPhoneInfoService/list",
update: "/custPhoneInfoService/update",
delete: "/custPhoneInfoService/deleteById",
create: "/custPhoneInfoService/create",
mulDel: "/custPhoneInfoService/mulDelete" // 注意返回去的是id的数组['asb','sdf']
}
复制代码
例如:web
doXXX // ---- 页面上实实在在触发的函数(如点击提交)
DXXX // ---- 页面上触发后通过防抖处理的函数
handleXXX // ---- 列表编辑、翻页操做
复制代码