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 // ---- 列表編輯、翻頁操做
複製代碼